Etiqueta

05 enero 2011

Actualización automática de bibliotecas a los usuarios finales

Problemática

A menudo los desarrolladores realizamos cambios sobre las bibliotecas Omnis Studio para adaptarlas a las necesidades de los usuarios o para corregir posibles deficiencias, esto obliga a actualizar las versiones que estos tiene instaladas. Se necesita por tanto un procedimiento que actualice de forma automática los ordenadores de los usuarios.

Escenario previo (Requerimientos):

Partimos de la base de que disponemos de un servidor FTP, donde existe un directorio llamado “ForUpdate”, que contendrá una copia de las bibliotecas a actualizar, es el lugar donde el desarrollador dejará la nueva biblioteca, cada vez que se produzca un cambio en la misma y por tanto debe ser actualizada al usuario.

Resolución:

Ahora construiremos una nueva biblioteca llamada “Actualiza” en nuestro ejemplo y que una vez terminada situaremos en la carpeta “startup” de Omnis Studio, la idea es que sea la primera biblioteca que Omnis Studio ejecutará.

Todos los procedimientos descritos pertenecen a la clase Task “Startup_Task”

Las variables del caso son las siguientes:

No. Instance Variable Type Subtype Init.Val/Calc

1 iActualizado Boolean
2 iArchivo Character 100
3 iDirArchi Character 100
4 iDirFTP List
5 iDirLocal List
6 iFTPSocket Long integer
7 iPassword Character 100 ‘******’
8 iServerDirec Character 100 '192.33.20.20'
9 iServerError Character 500
10 iUsuario Character 100 'librerias'

En primer lugar construiremos el método $construct de la librería “Actualiza”, todos los procesos que tendrán lugar se ejecutarán desde este procedimiento.

Después de haber definido las variables del caso, debemos hacer lo mismo con las siguientes variables locales:


No. Local Variable Type Subtype

1 lErrCode Short integer (0 to 255)
2 lExportPath Character 100
3 ok Boolean

Además del método público $construct, crearemos un total de seis métodos privados: EnFTP, EnUsuario, Guardarropa, Compara, SolicitaCopia y CopiaFTP.

El método $construct se compondrá finalmente de las siguientes líneas de código:

;; obtiene el contenido del directorio FTP a actualizar
1 Do method EnFTP Returns ok
2 If ok
;; obtiene el contenido del directorio correspondiente a la última actualización
3 Do method EnUsuario
;; selecciona de la lista FTP los archivos que necesitarán actualizarse
4 Do method Compara
;; pregunta al usuario y permite la copia de la nueva versión de la biblioteca
5 Do method SolicitaCopia
6 If iActualizado
;; guarda la lista de archivos FTP en un documento local denominado UltimoUpdate.txt
7 Do method Guardaropa
8 End If
9 End If

El procedimiento “EnFTP”, tiene como objetivo leer la entrada del directorio de los archivos contenidos en el servidor FTP y guardarlo sobre la lista “iDirFTP”, para posteriormente compararla con las entradas de directorio correspondientes a la última actualización que realizo el usuario.


No. Local Variable Type Subtype

1 lErrCode Short integer (0 to 255)

1 ; establece la conexión con el servidor FTP
2 FTPConnect (iServerDirec,iUsuario,iPassword) Returns iFTPSocket
3 If iFTPSocket; entra en el directorio "ForUpdate"
8 FTPCwd (iFTPSocket,'ForUpdate') Returns lErrCode
9 If lErrCode
10 OK message Error FTP {[con("Error al acceder al directorio FTP de
actualización ",kCr,"Código : ",lErrCode)]}
11 Else
12 Do iDirFTP.$define(iDirArchi)
13 ; devulve la lista de archivos en el directorio FTP sobre la variable iDirFTP en formato extendido
14 FTPList (iFTPSocket,iDirFTP,,1) Returns lErrCode
15 If lErrCode
16 FTPGetLastStatus (iServerError) Returns lErrCode
17 OK message Error FTP {[con("Error obteniendo la lista de archivos del
servidor FTP",kCr,"Devolvio: ",kCr,iServerError)]}
18 Quit method kFalse
19 Else
20 Quit method kTrue
21 End If
22 End If
23 End If

El procedimiento “EnUsuario”, la idea es compara la lista de los archivos a actualizar (servidor FTP), con los de la última actualización realizada, pero note que en caso de tratarse de la primera actualización dicha lista no existirá, por lo que deberá ser creada.

Finalmente la lista se guardará en un archivos de texto local denominado “UltimoUpdate.txt” y es desde este archivo que se cargará la lista de archivos para su comparación, la lista de archivos contenida en “UltimoUpdate.txt” se guardará en la variable de lista “iDirLocal”.

Finalmente y a estas alturas del proceso abremos obtenido dos listas, “iDirFTP” (con el directorio del servidor FTP) e “iDirLocal” (con el directorio correspondiente a la última actualización)
No. Local Variable Type Subtype

1 lExportPath Character 100

1 ; confecciona una lista con los últimos archivos actualizados
2 Calculate lExportPath as con(sys(115),'UltimoUpdate.txt')
3 Test if file exists {[lExportPath]}
4 If flag false
5 Do method Guardaropa ;; guarda la lista de archivos FTP en un documento
local denominado UltimoUpdate.txt
6 End If
7 Do iDirLocal.$define(iDirArchi)
8 Set import file name {[lExportPath]}
9 Prepare for import from file {Delimited (commas)}
10 Import data iDirLocal
11 End import
12 Close import file
El procedimiento “Guardarropa”, tiene como único objetivo actualizar el archivo local “UltimoUpdate.txt”, que como ya sabe el lector, contiene las entradas del directorio FTP, correspondientes a la última actualización.

No. Local Variable Type Subtype

1 lExportPath Character 100

1 Calculate lExportPath as con(sys(115),'UltimoUpdate.txt')
2 Set print or export file name {[lExportPath]}
3 Prepare for export to file {Delimited (commas)}
4 Export data iDirFTP
5 End export
6 Close print or export file
El procedimiento “Compara”, halla las diferencias entra las listas “iDirFTP” e “iDisLocal”, el resultado final es que únicamente quedan seleccionadas las entradas del directorio FTP, que deberán ser actualizadas (“iDirFTP”)

No. Local Variable Type Subtype

1 lComapara Character 100

1 Set current list iDirLocal
2 For each line in list from 1 to #LN step 1
3 Load from list
4 Calculate lComapara as iDirArchi
5 Do iDirFTP.$search(iDirArchi=lComapara,kTrue,kFalse,kTrue,kFalse)
6 End For
7 Set current list iDirFTP
8 Invert selection for line(s) (All lines)
A continuación describimos el procedimiento “SolicitaCopia”, cuya única misión es solicitar al usuario el lugar de destino para albergar la nueva biblioteca actualizada.

1 Calculate iActualizado as kFalse
2 For each line in list (Selected lines only) from 1 to #LN step 1
3 Load from list
4 Calculate iArchivo as right(iDirArchi,len(iDirArchi)-pos(':',iDirArchi)-3)
5 Yes/No message ¡Nueva versión! (Icon,Sound bell) {Existe una nueva versión
de [iArchivo][kCr]¿Desea instalarla ahora?}
6 If flag true
7 Do method CopiaFTP
8 End If
9 End For
Finalmente tan sólo nos queda describir el último de los procedimientos “CopiaFTP”, que es donde finalmente se copiaran los archivos o biblioteca a actualizar desde el servidor FTP al ordenador del usuario. La variable “iActualizado”, nos permitirá saber si todo el proceso termino con éxito.

Note que sólo si todo el proceso termina con éxito se actualizará el archivo “UltimoUpdate.txt”, de este modo se podría volver a intentar la actualización tantas veces como se requiera.


No. Local Variable Type Subtype

1 lError Short integer (0 to 255)
2 lPath Character 500

1 Do FileOps.$selectdirectory(lPath,con('Elija destino para ',iArchivo)) Returns
lError
2 If lError=1
3 FTPType (iFTPSocket,1) Returns iServerError
4 If not(iServerError)
5 Calculate lPath as con(lPath,':',iArchivo)
6 Working message Descargando.../-1073735809,-1073735805;50;0;60 {Copiando
librería [iArchivo]...}
7 FTPGet (iFTPSocket,iArchivo,lPath) Returns iServerError
8 If iServerError
9 OK message Error FTP {[con("Error al copiar el archivo
",upp(iArchivo),kCr,"Código de error : ",iServerError)]}
10 Calculate iActualizado as kFalse
11 Else
12 Calculate iActualizado as kTrue
13 End If
14 Else
15 Calculate iActualizado as kFalse
16 End If
17 Else
18 Calculate iActualizado as kFalse
19 End If
Bueno… esto ha sido todo, se trata de la primera entrega de las muchas cosas que deseo compartir con todos los desarrolladores de Omnis Studio.

Cuento con vuestro ánimo para seguir poniendo mis experiencias, en este blog.

1 comentario:

Anónimo dijo...

excelente explicacion hermano, sigue asi, te agradecemos la colaboracion en OMNI ya que hay pocos que se toman la tarea de explicar las cosas como tu,

Suerte