Desarrollar aplicaciones usando las APIs de las librerías
de Subversion es bastante sencillo. Todos los ficheros
de cabecera públicos se encuentran en el directorio
subversion/include
del código fuente.
Estos ficheros de cabecera son copiados en su sistema cuando
compila e instala Subversion a partir del código fuente. Estos
ficheros de cabecera recogen por completo las funciones y
tipos de datos accesibles por los usuarios de las librerías
de Subversion.
La primera cosa que puede observar es que los tipos de
datos y funciones de Subversion están protegidos por un espacio
de nombrado . Todo
símbolo público comienza con svn_
,
seguido por un breve código que representa la librería
en la cual es definido (como wc
,
client
, fs
,
etc.), seguido por un único carácter de subrayado
(_
) y por último el resto del nombre
del símbolo. Las funciones semi públicas (usadas por varios
ficheros de código fuente de una librería pero no fuera de
ésta, y contenidas en los propios directorios de las librerías)
difieren de este esquema de nombres en el uso del carácter
de subrayado tras el código de librería, ya que usan doble
carácter de subrayado (__
). Las funciones
que son privadas de un fichero particular no tienen prefijos
especiales, y son declaradas como static
.
Por supuesto, el compilador no tiene interés alguno por estas
convenciones de nombrado, pero ayudan a clarificar el ámbito
de una función o tipo de datos.
Junto con los tipos de datos de Subversion, verá muchas
referencias a tipos de datos que comienzan con
apr_
—símbolos de la librería
Apache Portable Runtime (APR). APR es la librería de
portabilidad de Apache, originada a partir del código fuente
del servidor en un intento de separar el código dependiente
del SO de las porciones de código independientes del SO. El
resultado es una librería que proporciona una API genérica
para realizar operaciones que difieren ligeramente —o
terriblemente— de SO a SO. Aunque el servidor HTTP
Apache fue obviamente el primer usuario de la librería
APR, los desarrolladores de Subversion reconocieron
inmediatamente el valor de usar también APR. Esto significa
que prácticamente no hay porciones de código dependiente
del SO en Subversion. También, significa que el cliente
Subversion se puede compilar y ejecutar dondequiera que lo
haga el servidor. Actualmente esta lista incluye todas las
variantes de Unix, Win32, BeOS, OS/2, y Mac OS X.
Además de proporcionar implementaciones consistentes de
llamadas de sistema que difieren entre sistemas operativos,
[45] APR le da a Subversion acceso inmediato a muchos
tipos de datos, como arrays dinámicos o tablas hash. Subversion usa en gran medida estos
tipos a lo largo del código fuente. Pero quizás el tipo de
datos APR más usado, encontrado en casi todo prototipo de la
API de Subversion, es apr_pool_t
—el
área de memoria de APR. Subversion usa internamente áreas
de memoria para todas las peticiones de reserva de memoria
que necesita (excepto cuando una librería externa requiere
un esquema de gestión de memoria diferente para los datos
que pasan por su API), [46] y aunque una persona que programa usando las
APIs de Subversion no está obligada a hacer lo mismo, tiene
que proporcionar áreas de memoria a las funciones de la API
que los necesitan. Esto significa que los usuarios de la API
de Subversion también tienen que enlazar con APR, y deben
llamar apr_initialize()
para iniciar el
subsistema APR, y entonces adquirir un área de memoria para
usarla con las llamadas de la API de Subversion. Vea “Programando con áreas de memoria” para más información.
Con operaciones de control de versiones remotas como
razón de la existencia de Subversion, tiene sentido
prestar atención al soporte de internacionalización
(i18n[47]). Después de todo,
aunque “remotas” pueda significar “de
un lado a otro de la oficina”, podría significar
perfectamente “de un lado a otro del globo.”.
Para facilitar esto, todas las interfaces públicas de
Subversion que aceptan parámetros de rutas esperan que éstas
sean canónicas, y codificadas en UTF-8. Esto significa,
por ejemplo, que cualquier nuevo cliente binario que use
la interfaz libsvn_client necesita convertir primero las
rutas de la codificación específica local a UTF-8 antes
de pasarlas a las librerías de Subversion, y entonces
reconvertir cualquier resultado generado por Subversion de
nuevo en la codificación local antes de usar esas rutas con
propósitos no relacionados con Subversion. Afortunadamente,
Subversion proporciona un conjunto de funciones (vea
subversion/include/svn_utf.h
) que
pueden ser usadas por cualquier programa para realizar
estas conversiones.
Además, las APIs de Subversion requieren que todos los
parámetros con URLs estén codificados correctamente
como URIs. Así, que en lugar de pasar file:///home/nombreusuario/Mi
fichero.txt
como la
URL de un fichero llamado Mi
fichero.txt
, usted necesita pasar file:///home/nombreusuario/Mi%20fichero.txt
.
De nuevo, Subversion proporciona
funciones de ayuda que su aplicación puede
usar—svn_path_uri_encode
y
svn_path_uri_decode
, para codificar
y decodificar URIs, respectivamente.
Si está interesado en usar las librerías de Subversion
junto con algo que no sea un programa en C—digamos que
un script en Python o una aplicación en Java—Subversion
tiene un soporte básico para esto vía el generador
simplificado de envoltorios e interfaces (SWIG)
[48]. Los
enlaces SWIG para Subversion se encuentran en
subversion/bindings/swig
y están
madurando lentamente hasta llegar a un estado usable. Estos
enlaces le permiten realizar llamadas a funciones de la
API de Subversion indirectamente, usando los envoltorios
que traducen los tipos de datos nativos de su lenguaje de
script a los tipos de datos necesarios por las librerías
C de Subversion.
Hay otro beneficio al acceder a las APIs de Subversion a través de un enlace con otro lenguaje—simplicidad. En general, lenguajes como Python y Perl son mucho más flexibles y fáciles de usar que C o C++. Los tipos de datos de alto nivel y la verificación de tipos por contexto proporcionados por estos lenguajes son a menudo mejores manejando la información que viene de los usuarios. Como ya sabrá, los humanos son muy hábiles fastidiando los datos de entrada de un programa, y los lenguajes de script tienden a manejar tales incorrecciones con más gracilidad. Por eso usar una interfaz y conjunto de librerías altamente optimizados, basados en C, combinados con un lenguaje poderoso, flexible, es tan atractivo.
Echemos un vistazo a un ejemplo que usa los envoltorios SWIG de Subversion para Python. Nuestro ejemplo hará exactamente lo mismo que el último. ¡Fíjese en la diferencia de tamaño y complejidad de esta versión de la función!
Ejemplo 8.2. Usando la capa de repositorio con Python
from svn import fs import os.path def crawl_filesystem_dir (root, directory, pool): """Recursively crawl DIRECTORY under ROOT in the filesystem, and return a list of all the paths at or below DIRECTORY. Use POOL for all allocations.""" # Get the directory entries for DIRECTORY. entries = fs.dir_entries(root, directory, pool) # Initialize our returned list with the directory path itself. paths = [directory] # Loop over the entries names = entries.keys() for name in names: # Calculate the entry's full path. full_path = os.path.join(basepath, name) # If the entry is a directory, recurse. The recursion will return # a list with the entry and all its children, which we will add to # our running list of paths. if fs.is_dir(fsroot, full_path, pool): subpaths = crawl_filesystem_dir(root, full_path, pool) paths.extend(subpaths) # Else, it is a file, so add the entry's full path to the FILES list. else: paths.append(full_path) return paths
Una implementación en C del ejemplo anterior se alargaría bastante más. La misma rutina en C necesitaría prestar especial atención al uso de la memoria, y tendría que usar tipos de datos de propios para representar las tablas hash y la lista de rutas. Python tiene tablas hash (llamadas “diccionarios”) y listas como tipos de datos nativos, y proporciona una maravillosa selección de métodos para operar sobre esos tipos de datos. Y dado que Python usa recolección de basura y recuento de referencias, los usuarios del lenguaje no necesitan preocuparse con la reserva y liberación de memoria.
En la sección previa de este capítulo, mencionamos la
interfaz libsvn_client
, y cómo existe
con el único propósito de simplificar el proceso de escribir
un cliente de Subversion. A continuación presentamos un breve
ejemplo que muestra cómo esta librería puede ser usada vía
los envoltorios SWIG. ¡En sólo unas pocas línea de Python,
puede obtener una copia de trabajo local de Subversion
totalmente funcional!
Ejemplo 8.3. Un script simple para obtener una copia de trabajo local.
#!/usr/bin/env python import sys from svn import util, _util, _client def usage(): print "Usage: " + sys.argv[0] + " URL PATH\n" sys.exit(0) def run(url, path): # Initialize APR and get a POOL. _util.apr_initialize() pool = util.svn_pool_create(None) # Checkout the HEAD of URL into PATH (silently) _client.svn_client_checkout(None, None, url, path, -1, 1, None, pool) # Cleanup our POOL, and shut down APR. util.svn_pool_destroy(pool) _util.apr_terminate() if __name__ == '__main__': if len(sys.argv) != 3: usage() run(sys.argv[1], sys.argv[2])
Los envoltorios de Subversion para otros lenguajes
desafortunadamente tienden a no recibir el mismo nivel
de atención recibido por los módulos principales de
Subversion. No obstante, se han dado pasos significativos
hacia la creación de enlaces funcionales para Python,
Perl y Java. Una vez tenga los ficheros del interfaz SWIG
configurados correctamente, la generación de envoltorios
específicos para todos los lenguajes soportados por SWIG
(que actualmente incluye versiones de C#, Guile, Java,
MzScheme, OCaml, Perl, PHP, Python, Ruby y Tcl) debería ser
teóricamente trivial. A pesar de esto, todavía se requiere
un poco de programación extra para compensar las complejas
APIs con las que SWIG necesita ayuda. Para más información
sobre SWIG, vea la página web del proyecto en http://www.swig.org/
.
[45] Subversion usa llamadas de sistema y tipos de datos ANSI siempre que es posible.
[46] Neon y la base de datos de Berkeley son tales librerías.
[47] N.T.: Forma breve de referirse a la palabra internacionalización, en inglés “internationalization”, que comienza con una “i”, seguida de 18 caracteres y terminada en “n”.
[48] N.T.: “Simplified wrapper and interface generator” en inglés