miércoles, abril 20, 2011

Subversion. Creando un patch y aplicándolo en otro branch

Cuando manejo dos branches o ramas de un mismo proyecto, me encuentro con bugfixes que deben de quedar en los dos, para ello creo un patch en la versión que arreglé para aplicarlo en la otra versión.
$ svn diff -c 372 > bugfix_patch
372 es la revisión que contiene el bugfix, el archivo creado contiene la información del patch

Index: update_script.py
===================================================================
--- update_script.py (revision 371)
+++ update_script.py (revision 372)
@@ -20,7 +20,7 @@
     ids = model.Product.getAll_filtered()
     
     for i in ids:
-        l.append(i.model)
+        l.append(i.model.strip() if i.model != None else '')
     
     rpc.updateList(l)
 

luego copio el archivo bugfix_patch al working directory de mi otro branch y aplico el patch.
$ patch -p0 < patch2
-p0 hace que los nombres de los archivos contenidos en el patch mantengan completo su path

Mas info en patch manpage

viernes, abril 15, 2011

Subversion. Moviendo un repositorio svn

Necesito mover un repositorio de un servidor a otro. En este caso es un viejo proyecto que no quiero perder que está alojado en un viejo servidor. Parece que en svn la mejor opción es hacer un dump, y luego un load.

$ svnadmin dump /home/svn/crmdev > crmdev.dump
* Dumped revision 0.
* Dumped revision 1.
* Dumped revision 2.
* Dumped revision 3.
* Dumped revision 4.
...

* Notar que svnadmin dump sólo funciona para paths y no urls.
Se crea un archivo de 184M
...
184M -rw-r--r-- 1 lukesw lukesw 184M 2011-04-15 11:04 crmdev.dump
...
Lo comprimo...
$ bzip2 crmdev.dump
... y queda en unos 141M
141M -rw-r--r-- 1 pablito pablito 141M 2011-04-15 11:04 crmdev.dump.bz2
Me ahorré 40M de transferencia entre servers, que con la tasa de transferencia de Infinitum son bastante considerables.
$ scp crmdev.dump.bz2 svn@super.newserver.com:/home/svn
En el nuevo servidor creo el repositorio y lo cargo con el dump
$ svnadmin create crmdev
$ svnadmin load crmdev < crmdev.dump
...
<<< Started new transaction, based on original revision 1
     * adding path : trunk/umlconcepts ... done.
     * adding path : trunk/umlconcepts/.classpath ... done.
     * adding path : trunk/umlconcepts/.myumldata ... done.
     * adding path : trunk/umlconcepts/.project ... done.
     * adding path : trunk/umlconcepts/.settings ... done.
     * adding path : trunk/umlconcepts/.settings/com.genuitec.eclipse.core.prefs ... done.
     * adding path : trunk/umlconcepts/uml.umr ... done.
...
<<< Started new transaction, based on original revision 63
     * editing path : trunk/productsweb/WebRoot/WEB-INF/jsp/footer.jsp ... done.

------- Committed revision 63 >>>
Listo, el repositorio ha sido copiado/movido

martes, abril 12, 2011

.hgignore para proyectos Turbogears 2+

Subversion es mi VCS favorito, sin embargo uso mucho Mercurial para cambios pequeños, pruebas de código y parches. Tengo repositorios híbridos (SVN/HG) que me funcionan muy bien. Copio mi archivo .hgignore para futura referencia.
# use glob syntax.
syntax: glob
*.svn   # repositorio híbrido
*.pyc   # compilados
*~      # temporales

syntax: regexp
^lib$   # librería específica del proyecto
* Tengo que hacer una referencia rápida para Mercurial

lunes, abril 04, 2011

Multiple relación a la misma tabla con Declarative SQLAlchemy 0.6

En el manual de SQLAlchemy la solución no es muy clara para la forma declarative, me arrojaba el siguiente error
sqlalchemy.exc.ArgumentError: Column-based expression object expected for argument 'primaryjoin'; got: 'False'
Al ver Column-based expression supuse que era el mismo tipo que en los filtros y así fué. La solución es simple como siempre, la pongo aquí para referencia.
class Registro(DeclarativeBase):
    __tablename__ = 'registro'
    
    #{ Columns    
    id = Column(Integer, primary_key=True)
    # folio único
    folio = Column(Integer, nullable=True)
    medic_id = Column(u'medic_id', Integer, ForeignKey('medic.id'))
    nursea_id = Column(u'nursea_id', Integer, ForeignKey('nurse.id'), nullable=True)
    nurseb_id = Column(u'nurseb_id', Integer, ForeignKey('nurse.id'), nullable=True)
    room_id = Column(u'room_id', Integer, ForeignKey('room.id'))
    status_id = Column(u'status_id', Integer, ForeignKey('status.id'))
    fecha = Column(u'fecha', Date(timezone=False), primary_key=False, nullable=True)
    patient = Column(u'patient', Unicode(255), nullable=False)
    patient_age = Column(u'patient_age', Integer, nullable=True)
    mat = Column(u'mat', Unicode(255), nullable=False)
    kit_id = Column(u'kit_id', Integer, ForeignKey('kit.id'))
    hour_in = Column(u'hour_in', Unicode(16), nullable=False)
    hour_out = Column(u'hour_out', Unicode(16), nullable=False)
    diagnosis = Column(u'diagnosis', Text(length=None, convert_unicode=True, \
        assert_unicode=None), primary_key=False)
    procedure = Column(u'procedure', Unicode(255), nullable=False)
    notes = Column(u'notes', Text(length=None, convert_unicode=True, \
        assert_unicode=None), primary_key=False)
la relación dentro la misma clase queraría así
    #{ Relations
    
    medic = relation(Medic)
    kit = relation(Kit)
    status = relation(Status)
    room = relation(Room)
    nursea = relation(Nurse, primaryjoin=nursea_id == Nurse.id)
    nurseb = relation(Nurse, primaryjoin=nurseb_id == Nurse.id)
    
    #}

viernes, abril 01, 2011

Python y locale.setlocale

Quiero desplegar las fechas de mis páginas hechas con Turbogears2.0 en español.  Ahora tengo esta salida.

In [5]: datetime.datetime.now().strftime("%a %d de %B del %Y")
Out[5]: 'Fri 01 de April del 2011'

Reviso los locale que tengo instalados en mi servidor, en este caso un Ubuntu Lucid (10.04)

root@kirk:~# locale -a
C
POSIX
en_AG
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_NG
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8
root@kirk:~#

Si no está el locale que requiero, lo genero, en este caso es: es_MX.UTF-8

root@kirk:~# /usr/sbin/locale-gen es_MX.UTF-8
Generating locales...
es_MX.UTF-8... done
Generation complete.
root@kirk:~#
La generación de locales en Lucid difiere un poco de como lo hacía en Intrepid
Confirmo la generación del locale

root@kirk:~# locale -a
C
POSIX
en_AG
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_NG
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8
es_MX.utf8
root@kirk:~#

Bien, ya tengo un locale en español que puedo utilizar. Lo activo dentro de mi ambiente python y compruebo.

In [6]: import locale

In [7]: locale.setlocale(locale.LC_ALL, 'es_MX.utf8')
Out[7]: 'es_MX.utf8'

In [8]: datetime.datetime.now().strftime("%a %d de %B del %Y")
Out[8]: 'vie 01 de abril del 2011'


Algo realmente simple me entretuvo mucho tiempo, ya que obtenía errores como:

In [9]: locale.setlocale(locale.LC_ALL, 'es_MX')
---------------------------------------------------------------------------
Error Traceback (most recent call last)

/usr/lib/python2.6/locale.pyc in setlocale(category, locale)
511 # convert to string

512 locale = normalize(_build_localename(locale))
--> 513 return _setlocale(category, locale)
514
515 def resetlocale(category=LC_ALL):

Error: unsupported locale setting

... y encontré poca documentación al respecto, lo pongo aquí para futuras referencias.