miércoles, 27 de agosto de 2014

Git zippatch, creando un nuevo comando.



Podemos obtener a través del comando git archive, una copia de nuestro repositorio en un zip.
Esto es genial.

Ahora , vamos a rizar el rizo, un poquito.

Tenemos una conexión a un ftp que tiene nuestra web. Por desgracia, no tenemos git para poder aplicar los parches, y tampoco es un repositorio, por lo tanto, lo único que nos queda es subir los ficheros que hemos modificado/creado desde nuestro repositorio.

Una de las cosas que odiamos los programadores es perder el tiempo en cosas banales.
No me dirás que subir 40 ficheros en diferentes rutas es una tarea agradable, si es así, este post no es para tí. ;-)

La solución sería que alguna cosa que creará un zip con solamente los cambios de la rama donde estemos, y con la misma estructura de directorios.

Git es una caja de sorpresas, en un par de pasos;

1) Creamos un fichero, zippatch.sh, ;
     git archive -o update.zip HEAD $(git diff --name-only HEAD^) -v
     y lo colocamos , en el repositorio o en una ruta que este en el PATH del sistema, por ejemplo, en /git/bin/

2) En nuestro .gitconfig global, creamos un nuevo alias;
[alias]
        zippatch = "!sh zippatch.sh"

Eso es todo. Ahora desde la linea de comando, ejecutamos, podemos ver algo como;

$git zippath 
file.c
dir1/
dir1/readme.MD

Esto nos creará un fichero llamado update.zip,  que contendrá SOLO los ficheros que se modificaron en el último commit. 



sábado, 16 de agosto de 2014

GitBlit. Nuestro github personal.


Hemos actualizado la versión GitBit de la 1.1.0 a la 1.6.0 y las mejoras son espectaculares.
https://dev.gitblit.com/

Podemos ver las mejoras en los siguientes puntos:

  • Mejora claridad en la portada.
  • Accesos directos a nuestros Marcadores, repositorio, actividad y Proyectos.
  • Tickets, que podemos gestionarlo como una rama de nuestro proyecto.
  • Fork de repositorios
  • Documentación a través de README.md , HOME.md
  • Reflujo.
La actualización a sido muy simple, manteniendo todos nuestros users y repositorios sin problemas,siguiendo las instrucciones;

Como nosotros tenemos un directorio diferente, lo único que hice fue apuntar directamente el directorio de trabajo y dejar el resto como estaba;
git.repositoriesFolder=/opt/gitRepos

Lo que más nos ha gustado, es que podemos abrir un ticket , y asociarlo a una rama, comentarlo, etc..
Para ello, se tiene que modificar el fichero de configuración, y determinar que tipo de sistema de tickets queremos más info en  https://dev.gitblit.com/doc/gitblit.git/master/src!site!tickets_overview.mkd






lunes, 7 de abril de 2014

Escritorio de mi GNU/Linux




















Este es mi escritorio actual, y así se va a quedar.

Los gráficos de la derecha se montan a través de conky. Muy interesante es la herramienta conky-manager, que se encarga de todo ;-) , que en mi época lo hacía uno mismo a mano.





jueves, 27 de marzo de 2014

A PC muerto, PC puesto


Mi nueva máquina, un capricho.

La compre en  http://www.framoiz.com/ , decir de verdad que el trato y el favor de cambiarme la torre sin problemas ha sido espectacular.

Al final me decidí por un ;

  • AMD FX-8350 8 núcleos 
  • 16 GIGAS de RAM 1600
  • 120 Disco SSD Samsung
  • 1 Tera Disco Seagate Barracuda
  • La placa 990XDA-UD3, que merece un poco de atención.
  • nVidia GT 750 2Gigas
Como no, Ubuntu 13.10 con GnomeShell. De verdad, cada vez que uso GnomeShell, más me gusta.
Realmente es espectacular y lo limpio que se ve, un gran trabajo de los chicos de Gnome.

Este es escritorio actual, simple y limpio;




La odisea a sido la torre. La que pillé al principio, tenía 4 ventiladores, 2 por la parte de arriba.
Demasiado ruido, y no podían controlarse. Al final, al día siguiente, me hice con otra torre, un pelín más cara, pero con control de los ventiladores, además, los puedo parar manualmente, importante para noches de programación ;-)


Lo de la placa Gigabyte 990XDA-UD3 ha sido de traca y sigue siendo, aunque no tengo USB2, los USB3 funcionan , pero el colmo fue el tema de la red.

Instalo Ubuntu, ni rastro de ella. Probé LiveCD de Debian, LinuxMint, y tampoco. Estuve retocando parámetros de la bios, fuera todo rastro del engendro del EUFI, etc..., mirando por Internet , y nada.

Al final me cansé y me dió por buscar el driver. Lo encontré, y lo único que hice es ejecutar el autorun.sh como root.

Aqui está http://r8168dl.appspot.com/,  o buscar r8168-8.038.00.tar.bz2.
Eso elimina el r8169 que no funciona, y coloca este que va como la seda.

Ahora queda averiguar el tema de los puertos USB2.

Lo que si es impresionante es Steam de Valve. ES ALUCINANTE!! 
Espero que la nena no se percate de ello, sino, me quedo sin ordenador ;-)



También el Nexus 4 lo pincho y todo disponible sin hacer nada. Realmente estoy muy muy contento.
Ahora a meterle todo el tema de programación, máquinas virtuales, etc...



sábado, 22 de marzo de 2014

NAS, muerte HP y resurrección del S.O. del pingüino


Hace unos días, para el día del padre, me regalé yo mismo, que mejor que uno mismo para saber que es lo que uno necesita ;-), un NAS Synologic DS114.

La verdad es que la máquina es una pasada. La idea era apagar el PC, que lo tenia 24 horas encendido, haciendo de servidor de MySql, Servidor de DNLA, Git server, etc..

Así que decido dar el paso, y traspasar los BD de MySql al NAS con MariaDB, crear el repo Git y enchufar un disco externo para la biblioteca multimedia.

¡¡OLE OLE OLE!!

Lo tengo todo listo, y decido apagar la máquina HP Pavilion
La verdad que esta máquina a estado a la altura, excepto un cambio de fuente de alimentación, y una tarjeta un poco más potente. Me ha durado más de 7 años, y ha estado prácticamente los 3 últimos años sin apagarse.
A sido la compañera en la cual he desarrollado cantidad de software y en la que los primeros años la dediqué exclusivamente a MediaCenter. Descanse en paz. R.I.P

Pero ¿ que pasa ahora con todos mis proyectos en mi Ubuntu 10.04 ? No quiero cambiar de distro, porque sería demasiado costoso el cambio para adaptar el software que tengo creado.
Así que miro una máquina que tenia para hacer una recreativa, le quito el disco duro y le pongo el del HP, arranco, y:

¡¡El poder del pingüino!! 

Me dice que la tarjeta Nvidia no se encuentra, que si quiero usar una estandard o poner los que se detectan ahora, le digo que si, y ya estoy otra vez funcionando! He perdido solo un minuto.

Y aquí estoy escribiendo este post desde la máquina provisional.

Ahora a buscar máquina, y la verdad que viendo precios, me decanto por un AMD FX-8350,  un micro de 8 núcleos, pero con un coste inferior que por ejemplo un i5 4670K. 
La gráfica estoy dudando, seguramente seguiré con nVidia por su soporte a Linux, ya que las ATI no tenía muy buenas críticas.

Intentaremos pillar 16GB de RAM, a costa de disco , porque en el NAS tengo 5 Teras, no me preocupa el espacio en la máquina.

A ver si puedo meterle un SSD , para el sistema operativo y hacer un /home aparte en un disco rigido.







martes, 18 de marzo de 2014

Python. Usando TreeStore. PyGtk


En esta 4 entrega, recordad una vez más de hacer un pull del repositorio, veremos como montar en la parte derecha de nuestra pantalla, las bases de datos de nuestro servidor, y dentro de cada base de datos, las tablas correspondientes y dentro , la estructura de cada uno de ellos.

Para usar la vista de arbol desde Glade, simplemente cogemos el objeto;

 self.view_tree = self.glade.get_object('treeview_tables')


Ahora, vamos a montar lo que habíamos comentado a través del método mount_treeview()

    def mount_treeview(self):
        pbd_bd = gtk.gdk.pixbuf_new_from_file("./images/bd.png")
        pbd_table = gtk.gdk.pixbuf_new_from_file("./images/table.png")
        pbd_field = gtk.gdk.pixbuf_new_from_file("./images/field.png")

He visto muchos ejemplos, en que la gente le da por cargar y guardar en el modelo de datos la imagen por cada fila. PITTTTT ERROR!!! INEFICAZ!
No hace falta, hombre. Se abre una sola vez, y se pasa esa imagen que será común a todas la filas. Eso significa , que si las imágenes pesan en memoria 30KB cada una, el consumo será, independientemente de las filas, 90K.
Si cargáramos por cada fila una imagen, pues multiplicar;
total memoria en imagen = filas * ( 3 * 30KB )

En fin, siempre viene bien recordad que la optimizaciones pequeñas, al final son las que marcan la diferencia entre un gran programa y un programa que se arrastra por el escritorio. ;-)

Vamos a ir comentando aunque el código habla por si solo.
Lo primero, es obtener las BD que tenemos en nuestro servidor de MySQL;


        #Preguntamos por la BDs
        sql = "Select schema_name From `INFORMATION_SCHEMA`.`SCHEMATA`"
        cursor = self.db.cursor()
        try:
            cursor.execute(sql)
            result_db = cursor.fetchall()
        except MySQLdb.Error, e:
            self.status_setText( "Error %d: %s" % (e.args[0], e.args[1]) )
            return

En la variable result_db, tenemos nuestras BD.
Ahora de lo que se trata es de empezar a rellenar nuestro TreeStore, que como vemos, estará formado por un tipo Pixbuf y un string;

        self.treestore = gtk.TreeStore(gtk.gdk.Pixbuf, str)

Ahora, lo que vamos hacer es recorrer nuestras bases de datos, y por cada una de ellos vamos a meterle las tablas. 

¿ Y como se hace ? pues a través de un iterator. 

Explicar que es un iterator me puede llevar bastante tiempo, así que vamos a suponer que tú eres un creyente, no importa de que religión o secta, la cuestión es que tienes que tener fe en lo que ves ;-)

Después, por ti mismo, busca documentación sobre ello, o ya reportaré alguna documentación que vi en su momento.

Bueno, como la fe en lo que ves, la introducción del primer grupo, en este caso las bases de datos, verás que el paso de parámetros es None, por la simple razón que es la raiz.

La llamada self.treestore.append nos devuelve un iterator a la vez que introduce el elemento de la base de datos y la imagen, [pbd_bd, bd[0]

Este indica el camino al padre.  ( Tú ves rezando ;-) )

        for bd in result_db:
            iter = self.treestore.append(None,[pbd_bd, bd[0]] )
            cursor1 = self.db.cursor()
            try:
                cursor1.execute( "show tables from " + bd[0])
                result_table = cursor1.fetchall()
            except MySQLdb.Error, e:
                self.status_setText( "Error %d: %s" % (e.args[0], e.args[1]) )
                return

Ahora, recorremos las tablas, que obtuvimos anteriormente con show tables from + la base de dato actual

Pero, ahora, a la hora de introducir en el TreeStore, vamos a indicar a que Padre, a través del iterator creado anteriormente, y que este, a su vez, nos devuelve otro iterator, iterchild, que lo usaremos posteriormente ;


            for table in result_table:
                iterchild = self.treestore.append(iter,[pbd_table, table[0] ] )
                cursor2 = self.db.cursor()
                try:
                  cursor2.execute( "show columns from " + bd[0] + "." + table[0])
                    result_field = cursor2.fetchall()
                except MySQLdb.Error, e:
                   self.status_setText( "Error %d: %s" % (e.args[0], e.args[1]) )
                   return

Bien, y para acabar, vamos a introducir la estructura en su tabla:

                for field in result_field:
                    self.treestore.append(iterchild,[pbd_field, field[0] ] )

Pues lo único que queda, es crear un par de columnas;

        #Create Columns from names fields
        column = gtk.TreeViewColumn( "", gtk.CellRendererPixbuf(), pixbuf=0)
        self.view_tree.append_column( column )
        column = gtk.TreeViewColumn( "Database", gtk.CellRendererText(), text=1 )
        self.view_tree.append_column( column )


Y asociar nuestro TreeStore a nuestra vista;
        self.view_tree.set_model( self.treestore )

El resultado, en la parte derecha de la imagen;



Ahora va tomando una forma más que elegante, para las pocas líneas que hemos picado ;-)

Os aseguro, que si no fuese por Glade, el picar hubiese sido muy tedioso.

En la próxima, veremos de incorporar una pequeña historia sobre las query que hemos ido realizando.

Ah, se me olvidaba, si pruebas USE BD_QUE_QUIERO, algo hace ;-)



domingo, 16 de marzo de 2014

Python. MVC y MySQL ( PyGtk )




En esta tercera entrega de nuestro aprendizaje de Python con PyGtk, vamos a ver como haciendo nuestras Querys de MySQL se verán reflejadas en nuestra vista.

Antes de continuar, hacer un git pull del proyecto ubicado en github, para ver los nuevos cambios.

Las mejoras que tenemos en esta revisión, son;

  • Usamos una statusbar para dar información y mostrar también errores de MySQL
  • Crearemos a través de un TextView, un modelo de datos ListStore y columnas dinámicamente.
  • Controlamos la salida de la aplicación, preguntado si queremos salir.
  • Pulsando la tecla F5 en la ventana, lanzará la consulta que tengamos en ese momento en el TextView
  • Los eventos saltan ahora a la propia clase, abandonando la clase Handler(), por ser más sencillo la gestión. De todas maneras no la quito del código, para que se vea que podemos elegir el sistema que más nos guste.
Casi todo el trabajo se realiza en el método setQuery(), y es lo que veremos a continuación.

Obtener la sentencia que hemos escrito en el textview;

        textbuffer = self.textview_sql.get_buffer()
        self.cSql = textbuffer.get_text(*textbuffer.get_bounds())


Aquí de lo que se trata es de eliminar las columnas de la antigua sentencia ejecutada y limpiar el modelo de datos asociado a la vista;


        # remove columns the old view
        nOld_Fields = self.getTotalColumns()
        if nOld_Fields != 0:
            for column in self.view_lista.get_columns():
                self.view_lista.remove_column( column )


        #Clear model data of view
        oModel = self.view_lista.get_model()
        if oModel != None:
            oModel.clear()
        self.view_lista.set_model()

Ahora, ejecutamos la sentencia en MySQL, también podríamos adaptarlo fácilmente a otro motor, como Sqlite o PostGres, y en caso de error, lo mostramos en la statusbar;

        #Execute Sql
        cursor = self.db.cursor()
        try:
            cursor.execute(self.cSql)
            result = cursor.fetchall()
        except MySQLdb.Error, e:
            self.status_setText( "Error %d: %s" % (e.args[0], e.args[1]) )
            return

Ahora lo que vamos a realizar es muy simple, obtenemos la cantidad de campos y sus nombres, para crear las columnas correspondientes, que lo logramos a través del método AddListColumn()

        num_fields = len(cursor.description)
        field_names = [i[0] for i in cursor.description] # Name of fields

        #Create Columns from names fields
        i = 0
        for nombre in field_names:
            self.AddListColumn(nombre, i)
            i = i + 1

Una vez que tenemos nuestras columnas creadas, lo que nos resta es crear el modelo de datos y rellenarlo con nuestra Query y asignarlo a la vista;

        #Create model dinamic of types str for view
        ListStore = gtk.ListStore(*([str] * num_fields))
        for value in result:
            ListStore.append(value)
        self.view_lista.set_model(ListStore)



Pues esto es todo en esta tercera entrega, ahora podemos empezar a ver resultados visibles ;-)

Para la próxima, usaré un TreeStore, para montar las estructuras de nuestras tablas que tengamos en la base de datos, además, incorporaremos alguna que otra imagen en la vista, para que quede más chulo.

Dejo unas imágenes con los resultados del código a ver que os parecen.









Android y Git. Disponer del hash automáticamente.

Una de las cosas a las que estoy acostumbrado, es tener siempre en mi código, el hash/tag/versión del control de versiones que estoy usan...