lunes, 28 de diciembre de 2015

hbmk2 y los VCS


Toda la vida he estado usando el fichero makefile, y concretamente, para Borland C, para contruir la aplicación en Harbour.

Desde hace relativamente un año, decidí que era demasiado complicado mantener dicho makefile, sobretodo cada vez que tenia que introducir alguna librería nueva en el sistema, averiguar ya de por si que librerías eran todo una odisea.

Así que me puse a mirar hbmk2 de Viktor Szakats. Una autentica maravilla!
Mirando la documentación, y me paro en estos 2.

-vcshead=<file>     genera un archivo de cabecera .ch con información del
                    repositorio local. Actualmente están soportados Git, SVN,
                    Mercurial, Bazaar, Fossil, CVS y Monotone. El archivo de
                    cabecera definirá la constante de preprocesador
                    _HBMK_VCS_TYPE_ con el nombre del VCS detectado, y
                    _HBMK_VCS_ID_ con el ID Único del repositorio local. Si
                    no se detecta un VCS, un número secuencial será
                    incrementado cada vez que se construya.


 -tshead=<file>      genera archivo de cabecera .ch con información de
                    fecha/hora. Cabecera generado definirá macros
                    _HBMK_BUILD_DATE_, _HBMK_BUILD_TIME_,
                      _HBMK_BUILD_TIMESTAMP_ con fecha/hora de creación de
                      archivo


Siempre, desde que uso un VCS, pasando desde CVS y SVN, teníamos la posiblidad de poner un define con una marca, donde el propio control de versiones lo cambiaba.

Con Git, esto no es posible directamente, porque el hash es sobre el cálculo del estado actual
del repositorio, hay que hacerlo a posterior.

Bueno, ¿ y todo esto para que sirve ? Muy simple, tenemos que identificar de alguna manera que la aplicación que está corriendo de que código fuente depende. Así, encontrar un bug, es tan simple de ir a esa versión tal y como estaba y mirar de arreglar y parchear en el código actual.

Hasta ahora tenía una forma muy simple, y es que siempre tener una marca, como;
#define df_Version  "27/10/2105 10:10 master"

Cada vez que generaba una versión nueva, tengo que acordarme de cambiarlo.
Esto me sirve para recorrer después fácilmente la historia e identificar el commit.

Ahora con hbmk2 puedo hacer que lo hago por mí, añadiendo el hash a la versión que corresponde, tan simple como añadir esto en nuestro fichero de compilación ;
-vcshead=./include/cv.ch
-tshead=./include/bd.ch



Después, en nuestro prg, añadimos ;

#include "cv.ch"
#include "bd.ch"

#define df_Version "id:" + _HBMK_VCS_ID_ + " date:" +_HBMK_BUILD_DATE_ + " time:"+ _HBMK_BUILD_TIME_  

La fecha/hora no es la del commit, es cuando lo estas generando actualmente.
 Entonces  la manera de proceder es simple;
  • Modifica / Crea / Borrar código
  • git commit
  • hbmk2 
Puede ser que queramos tener los ficheros .ch en el control de versiones, esto ocasiona que siempre te avisará que hay cambios.

Tan simple como aplicar nuestro ocultamiento al estilo Naruto ;-), usando http://xthefull.blogspot.com.es/2015/11/ignorar-fichero-del-repositorio-en-git.html

Ahora, cada vez que compilo, ya no tengo que preocuparme de cambiar nada, la aplicación ya me dirá cuál commit es la que se usó para generarlo;
 
id:de867af date:20151228 time:163110

Después tan facil como ver ;

λ git log --stat de867af
commit de867af8fbec6768118b019c3af60331f2faec01
Author: Rafa Carmona <rafa.thefull@gmail.com>
Date:   Mon Dec 28 16:29:29 2015 +0100

    Soporte completo para identificar version de Git a traves de Harbour

      * include/bd.ch y include/cv.ch son generados automáticamente por Harbour
        NO TOCAR

 include/bd.ch | 4 ++++
 include/cv.ch | 2 +-
 project.hbm    | 1 +
 server.prg    | 3 ++-
 4 files changed, 8 insertions(+), 2 deletions(-)

 



martes, 24 de noviembre de 2015

Convertir XML a Hash en Harbour ( update II )



En eso que estaba yo pensando en como acceder a un XML que contiene solo nodos de elementos,
sin atributos, sin tener que estar continuamente haciendo búsquedas.

Pues vamos a dotarle a Harbour la manera de recorrer cualquier nodo, y devolver un Hash con
el contenido.

Los subnodos, simplemente serán arrrays con Hash.
He aquí el codigo de ejemplo;

UDPATE. Soporte para atributos.
Ahora, se crea un hash con el  nombre del elemento, mas @attribute  que va a contener un hash con los atributos del nodo, de esta manera para obtener el nombre del nodo, node1;
hHash["node1@attribute"]["nombre"] mostrará pepe

UPDATE II. Fix espacios en blanco
Se detecta que un nodo, <nodo>Ejemplo XML</nodo>
El valor del Hash["nodo"] será igual a Ejemplo, y debería ser Ejemplo XML
Viktor me ha iluminado, comentando que hay que usar OPAQUE

XML

<?xml version="1.0" encoding="utf-8"?>
<data>
    <node1 nombre="pepe">Ejemplo XML</node1>
    <node2>val2</node2>
    <node3>val3</node3>
    <group>
        <node1>val4</node1>
        <node2>val5</node2>
        <node3>val6</node3>
    </group>
    <group>
        <node1>val24</node1>
        <node2>val25</node2>
        <node3>val26</node3>
      <extras>
            <node1>Extra_val24</node1>
            <node2>Extra_val25</node2>
            <node3>Extra_val26</node3>
        </extras>
    </group>
    <node7>val7</node7>
    <node8>val8</node8>
</data>

PRG

FUNCTION Test( file )
  Local pRoot, hHash

  pRoot :=   mxmlLoadString( NIL, hb_MemoRead( file ),  @type_cb() )
  hHash := XMLtoHash( pRoot, "data" )
 
  // Podemos acceder fácilmente ;
  ??  hHash["node1"]  // Muestra Ejemplo XML
  ??  hHash["node2"]  // Muestra val2  ??  hHash["group"][1]["node1"] // Muestra val4
  ??  hHash["group"][2]["extras"][1]["node1"] // Muestra Extra_val24

    ??  hHash["node1@attribute"]["nombre]  // Muestra pepe

     mxmlDelete( pRoot )

 RETURN nil

STATIC FUNCTION type_cb( node ) ;  RETURN MXML_OPAQUE
 


// ---------------------------------------------------------------------------//
FUNCTION XMLtoHash( pRoot, cElement )
   Local pNode, hNext
   Local Map := {=>}

   if empty( cElement )
      pNode := pRoot
   else  
      pNode := mxmlFindElement( pRoot, pRoot, cElement, NIL, NIL, MXML_DESCEND )
   endif
     
   IF Empty( pNode )
      RETURN Map
   ENDIF

   hNext := mxmlWalkNext( pNode, pNode, MXML_DESCEND )
   Map :=  NodeToHash( hNext )

  return Map

// ---------------------------------------------------------------------------//

STATIC FUNCTION NodeToHash( node  )
   Local wt := 0
   Local hNext
   Local hHashChild := {=>}
   Local hHash := {=>}

   WHILE node != NIL
         
         IF mxmlGetType( node ) == MXML_ELEMENT

            if HB_HHASKEY( hHash, mxmlGetElement( node ) )
               if valtype( hHash[ mxmlGetElement( node ) ] ) <> "A"
                  hHash[ mxmlGetElement( node ) ] := mxmlGetOpaque( node )
               else
                 // Es un array, por lo tanto, no lo tocamos
               endif  
            else                  
               hHash[ mxmlGetElement( node ) ] := mxmlGetOpaque( node )
            endif    
            if HB_MXMLGETATTRSCOUNT( node ) > 0
               hHash[ mxmlGetElement( node ) + "@attribute"] := HB_MXMLGETATTRS( node )
            endif  
 

              if empty( mxmlGetOpaque( node ) ) // Miramos dentro
               hNext := mxmlWalkNext( node, node, MXML_DESCEND )  
               if hNext != NIL
                  if empty( hHash[ mxmlGetElement( node ) ]  )
                     hHash[ mxmlGetElement( node ) ] := {}
                  endif  
                   hHashChild :=  NodeToHash( hNext  )
                   if hHashChild != NIL
                      AADD( hHash[ mxmlGetElement( node ) ], hHashChild )
                   endif  
               endif  
            endif
         ENDIF   

         node := mxmlGetNextSibling( node )
                    
   END WHILE

RETURN hHash
 

Aqui muestra pantallazo de obtener de un XML de SEPA de prueba;
 
 

miércoles, 4 de noviembre de 2015

Ignorar fichero del repositorio en Git


Cuando queremos ignorar un fichero o directorio en concreto, y este fichero no forma parte del repositorio, pero si en la carpeta de trabajo, por ejemplo, los ficheros *.obj , *.log o similar, que no queremos que formen parte, pero que son necesarios en el proyecto.

Pues tan simple como crear un fichero .gitignore, y añadirlos;
/obj/
*.log

Bien, pero , ¿ Y si el fichero en cuestión SI quiero que este en el repositorio ?  por ejemplo, un fichero inicial de configuración, pero NO quiero que se haga un seguimiento, por la sencilla razón,
que contiene los passwords o otros parámetros que no queremos que se actualice.

Pues para eso existe un comando;
git update-index 

Como la finalidad no es explicar TODO lo que hace el comando, vamos directamente a lo que nos interesa, aqui el enlace al comando, https://www.kernel.org/pub/software/scm/git/docs/git-update-index.html

Imaginemos que tenemos un fichero, config.ini, que contiene las diversas opciones.
git update-index --asume-unchanged config.ini

Atentos, git update-index solo maneja ficheros, no directorios.

Ahora, si modificas el fichero config.ini, verás que para Git, no lo has tocado, evitando así tener
que subirlo al repositorio. 

Ah, pero si ahora quiero que Git vuelva a tener encuenta a nuestro fichero, config.ini, pues 
tenemos el comando;
git update-index --no--asume-unchanged config.ini

Para saber que ficheros están como 'ocultos' , usamos el comando, la h en minúscula nos lo indica;
git ls-files -v  

H file.txt
h config.ini

Así, podemos crearnos unos alias, creando-comandos-en-git, para manejar más fácil

[alias]
hide = update-index --assume-unchanged
unhide = update-index --no--assume-unchanged

Aplicando el alias;
git hide config.ini



martes, 6 de octubre de 2015

GitKraken, otro cliente Git.


GitKraken , http://www.gitkraken.com/ , es un cliente GUI Multiplataforma, que se encuentra en beta privada, y que tengo el placer de poder probarlo.

De momento, tiene un aspecto espectacular.


Podéis seguir por twitter , https://twitter.com/gitkraken

martes, 15 de septiembre de 2015

Web Server Harbour


Os muestro un pequeño video de las posibilidades de Harbour funcioanando como un servidor Web.

Dentro de /contrib/httpd, tenéis un servidor web realizado en Harbour.
El autor de esta pequeña obra de arte es Mindaugas Kavaliauskas.

Son unas 2000 lineas de código, que nos permite establecer otro paso a nuestras
aplicaciones, ya sea como complemento a nuestro software de escritorio, o porque no,
hacer una aplicación web usando Harbour.

Actualmente, estoy desarrollando un API, que consiste en un servicio de Windows,
que corre el servidor web, hbhttpd, para diversas API para distintos fabricantes.

Una de las cosas que queria implementar, es un seguimiento de las request/response.
Para ello, usé una simple tabla con Sqlite3, donde guardarlo.

La cosa se complicó, pues no era nada intuitivo, debia pasar los parámetros por get.
El sistema de configuración del servidor, se hace a través de un fichero .ini

Por lo que mi siguiente reto era realizar todo visualmente.
El resultado, a sido asombroso, he aquí un pequeño video demostrativo de lo
que podemos hacer con esta maravilla que hizo Mindaugas Kavaliauskas.

En este caso, TODO esta realizado en Harbour;

 + Servicio de Windows
 + Web Server
 + Acceso a INI, Dbfs , SQL con ADO y Sqlite3 para logs.
 + Bootstrap para HTML, CSS, y JS framework

 Como podéis ver, todo es posible con Harbour ;-)

miércoles, 29 de julio de 2015

Merge de ficheros en Git entre ramas

De las cosas que uno se enamora de Git, es que puede llegar el caso en que existan varias maneras de hacer las cosas.

El reto es el siguiente:
- Partiendo de una rama master, se desarrolla una nueva rama incidencia1, en la cual hemos realizado unos commits, y hemos modificado y añadido un par de ficheros.

Por lo tanto , en el C4 de la rama incidencia1 , tenemos ;

file1.c nuevo fichero.
file2.c modificacion del fichero
file3.c nuevo fichero.


Mientras tanto, en la rama incidencia2,  tenemos que incluir solo 2 los ficheros nuevos de la rama incidencia1.

Claro, que no podemos hacer un merge de la rama incidencia1, porque nos fusionaría el file2.c, y este no vamos a modificarlo, porque necesitamos conservar el de la rama incidencia2

Una simple solución es decirle a git que nos lo traiga a la rama donde estamos, incidencia2, los ficheros que necesitamos de la rama incidencia1;

$ git checkout incidencia1 file1.c file3.c
Ahora solo nos queda añadir los ficheros, git add , y hacer un commit ;-)
$ git add file*
$ git commit -m "Ya tenemos los files desde incidencia1"






jueves, 23 de julio de 2015

Historias de Git

Estar mirando la historia de un proyecto, y encontrarme con esto;




                                                       Ole, Ole, necesitamos vacaciones!!




miércoles, 22 de julio de 2015

Android, Evento OnClick de un boton


Una de las cosas cuando estaba con Java y Swing era la gestión de los eventos a través de los Listener.

Pues bueno, con Android 3/4 de lo mismo, por ejemplo, boton que nos va para otra actividad.



Y pensar que hace años en multiples lenguajes / GUIs tenemos evento OnClick....

En fin, arriba vemos como creamos un objeto, btnEuro,  y lo asignamos a través del setOnClickListener, que a su vez, se le pasa un objeto creado a través de new View.OnClickListener(), que se sobreescribe el method onClick,
y ahí, se crea un Intent, que se le pasa al inicio de la Activity.

¿ Lo podemos hacer más simple ? Pues si, de esta manera;


Y ahora, solo nos queda activarlo;


Y nos queda solo sobrescribir el method OnClick en la propia clase MainActivity;




Update: Bien, también con Android Studio,  podemos hacer lo siguiente;

En las propiedades del botón , ponemos el method que recibirá el evento, solo nos queda codificarlo;

 

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...