Usando las APIs

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.

La librería Apache Portable Runtime

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.

Requisitos de URL y ruta

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.

Usando lenguajes distintos de C y C++

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