projects:uocmaster
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| projects:uocmaster [2011/12/27 23:24] – [Instalación de Programas de Control de Código Fuente] rlunaro | projects:uocmaster [2022/12/02 21:02] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Master of the UOC (Universidad Oberta de Catalunya) ====== | ||
| + | |||
| + | ===== Reconfigurar teclado en linux ===== | ||
| + | |||
| + | Con el teclado del sistema Toshiba 430CDT que estamos manejando | ||
| + | se dan unas particularidades que lo hacen peculiar: | ||
| + | |||
| + | - La tecla " | ||
| + | - Las teclas de mayor que y menor que, tampoco están | ||
| + | - La tecla de slash invertido tampoco está | ||
| + | |||
| + | Era preciso resolver estas carencias para que el teclado funcionara | ||
| + | correctamente. A fin de lograrlo con éxito, fué preciso identificar | ||
| + | cómo funciona el teclado en Debian. | ||
| + | |||
| + | ==== Funcionamiento del teclado en Debian ==== | ||
| + | |||
| + | Cuando se arranca el sistema, el script ''/ | ||
| + | encargado de cargar la configuración del teclado, que se encuentra | ||
| + | en ''/ | ||
| + | |||
| + | Si es la primera vez que se ejecuta (porque se acaba de reinstalar | ||
| + | el sistema operativo, por ejemplo), es posible que esa lectura del | ||
| + | mapa de teclado se efectúe de ''/ | ||
| + | actual, la inspección del script indica que esto no es así ya que la | ||
| + | ruta a ese archivo aparece comentada. | ||
| + | |||
| + | |||
| + | ===== Los mapas de teclado en Linux ===== | ||
| + | |||
| + | Linux posee un potente mecanismo para asignar las teclas físicas del | ||
| + | teclado a teclas " | ||
| + | |||
| + | Toda esta parafernalia se consigue con tres elementos: | ||
| + | |||
| + | * los mapas de teclado, ficheros ascii donde se asigna una tecla física (o combinación de varias, como Alt + F1) a un caracter o varios caracteres | ||
| + | * el fichero loadkeys, encargado de " | ||
| + | * el comando showkeys, que al pulsar una tecla devuelve el número de tecla física que tiene | ||
| + | |||
| + | |||
| + | ===== Reprogramando el teclado ===== | ||
| + | |||
| + | Para reprogramar el teclado, lo primero que hicimos estudiar cómo íbamos | ||
| + | a colocar las teclas: | ||
| + | |||
| + | * por su proximidad, la tecla /o/a (masculine, ordfeminine, | ||
| + | * los caracteres /o/a se colocarían como AltGr+8 y AltGr+9 | ||
| + | * el caracter backslash se colocaría en AltGr+7 | ||
| + | |||
| + | Mediante el comando showkeys identificamos la tecla /o/a como de código 41. | ||
| + | Su programación actual es: | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | alt keycode | ||
| + | </ | ||
| + | |||
| + | y será sustituida por: | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | # keycode | ||
| + | # | ||
| + | </ | ||
| + | |||
| + | El siguiente paso es identificar la tecla 7/slash. Mediante showkey | ||
| + | identificamos que se trata de la tecla de código 8, que en el mapa | ||
| + | de teclado actual (/ | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | alt keycode | ||
| + | </ | ||
| + | |||
| + | y al tercer valor que es el valor que tiene la tecla cuando se pulsa AltGr, lo reemplazamos por backslash: | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | </ | ||
| + | |||
| + | En el caso de las teclas 9 y 10, que corresponden a los caracteres | ||
| + | 8 y 9 respectivamente, | ||
| + | retornen " | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | alt keycode | ||
| + | keycode | ||
| + | alt keycode | ||
| + | </ | ||
| + | |||
| + | |||
| + | Queda ahora colocar los caracteres mayor que y menor que. Por proximidad, | ||
| + | se colocarán en las teclas AltGr+Z y AltGr+X. Donde antes estaba: | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | keycode | ||
| + | </ | ||
| + | |||
| + | ahora quedará como: | ||
| + | |||
| + | < | ||
| + | keycode | ||
| + | altgr keycode 44 = less | ||
| + | keycode | ||
| + | altgr | ||
| + | </ | ||
| + | |||
| + | ====== Actualización del sistema ====== | ||
| + | |||
| + | Para actualizar el sistema el primer paso que hemos realizado ha sido | ||
| + | añadir la siguiente línea en ''/ | ||
| + | |||
| + | < | ||
| + | deb ftp:// | ||
| + | </ | ||
| + | |||
| + | Y ejecutar el comando '' | ||
| + | de paquetes. Hemos de hacer notar que woody ha pasado de ser " | ||
| + | " | ||
| + | |||
| + | A continuación hemos ejecutado " | ||
| + | aquellos paquetes que proceda. | ||
| + | |||
| + | |||
| + | ====== Otras modificaciones en el sistema operativo que no se han descrito ====== | ||
| + | |||
| + | ==== Corrección de la configuración del lector de noticias ==== | ||
| + | |||
| + | El lector de noticias inn tenía un error en el fichero de configuración | ||
| + | ''/ | ||
| + | que no habían sido configurados correctamente. Se modificó el fichero para | ||
| + | que el contenido: | ||
| + | |||
| + | <code properties> | ||
| + | # General Settings | ||
| + | |||
| + | domain: | ||
| + | innflags: | ||
| + | mailcmd: | ||
| + | server: | ||
| + | </ | ||
| + | |||
| + | Quedara así: | ||
| + | |||
| + | <code properties> | ||
| + | # General Settings | ||
| + | |||
| + | domain: | ||
| + | innflags: | ||
| + | mailcmd: | ||
| + | server: | ||
| + | </ | ||
| + | |||
| + | Este error provocaba un mensaje de error que llegaba por correo electrónico | ||
| + | cada vez que se ejecutaba el crontab ''/ | ||
| + | |||
| + | ==== Ajuste de permisos para el acceso a unidad de cdrom y a floppy disk ==== | ||
| + | |||
| + | La configuración de permisos para el acceso al cdrom y al floppy disk | ||
| + | eran poco operativos, además de inseguros. Los permisos | ||
| + | iniciales eran rwxr-xr-x para el usuario root y el grupo root, lo que | ||
| + | implica que en la práctica sólo el superusuario tiene acceso de lectura | ||
| + | y escritura a estos dispositivos, | ||
| + | tienen acceso a los mismos una vez montados: | ||
| + | |||
| + | < | ||
| + | chupete:/# ls -lad floppy cdrom | ||
| + | drwxr-xr-x | ||
| + | drwxr-xr-x | ||
| + | </ | ||
| + | |||
| + | Resulta más adecuado hacer un uso racional de los grupos " | ||
| + | de tal modo que sólo los usuarios que pertenezcan a estos grupos tengan | ||
| + | acceso a estos dispositivos por defecto. Para ello se configuró el grupo | ||
| + | propietario de estos directorios como " | ||
| + | los permisos se establecieron como rwxrwx---, de tal modo que para acceder | ||
| + | al floppy o al cdrom se tiene que pertenecer a estos grupos: | ||
| + | |||
| + | < | ||
| + | chupete:/# ls -lad floppy cdrom | ||
| + | drwxrwx--- | ||
| + | drwxrwx--- | ||
| + | </ | ||
| + | |||
| + | ==== Instalación de paquetes complementarios ==== | ||
| + | |||
| + | Se han instalado los siguientes paquetes complementarios: | ||
| + | |||
| + | ==== Corrección de problemas con apt ==== | ||
| + | |||
| + | Se ha resuelto un problema con la configuración de apt: la línea que había | ||
| + | en sources.list para el acceso a security era: | ||
| + | |||
| + | < | ||
| + | deb http:// | ||
| + | </ | ||
| + | |||
| + | Cuando debian pasó " | ||
| + | " | ||
| + | paquetes de versiones posteriores a las que funcionaban en woody, creando | ||
| + | colisiones. Bastó corregirla línea en cuestión: | ||
| + | |||
| + | < | ||
| + | deb http:// | ||
| + | </ | ||
| + | |||
| + | Y ejecutar apt-get update / apt-get upgrade para que todo volviera a | ||
| + | funcionar con normalidad. | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ====== Instalación de Programas de Control de Código Fuente ====== | ||
| + | |||
| + | ==== Qué se va a evaluar ==== | ||
| + | |||
| + | |||
| + | **Portabilidad** | ||
| + | |||
| + | En esta sección analizaremos la disponibilidad de esta herramienta | ||
| + | para otras plataformas distintas de Linux; tanto de las herramientas | ||
| + | cliente, para la descarga y desarrollo en Windows, pero trabajando | ||
| + | con un servidor Linux, como en las herramientas servidor, para trabajar | ||
| + | desde cualquier plataforma a un servidor en cualquier plataforma. | ||
| + | |||
| + | **Realizando el primer cambio** | ||
| + | |||
| + | La primera prueba que se va a realizar es completar un cambio simple | ||
| + | mediante la herramienta de control de código fuente; el objetivo es | ||
| + | familiarizarse con la herramienta, | ||
| + | de uso; si es fácil implantarla en un proyecto y si la curva de | ||
| + | aprendizaje de la misma es alta. | ||
| + | |||
| + | **Realizando un cambio concurrente** | ||
| + | |||
| + | Un aspecto que nos ha parecido interesante evaluar es el tratamiento que | ||
| + | hace el sistema de control de código fuente de varios cambios que se | ||
| + | hagan en el repositorio en la misma línea de código; y en general determinar | ||
| + | que los cambios de unos usuarios no resultan destruidos por los cambios | ||
| + | de otros usuarios. | ||
| + | |||
| + | El espíritu de esta prueba es también evaluar si es posible o no acceder | ||
| + | al repositorio remotamente; | ||
| + | cuál es el proceso para realizarlo y ver las respuestas que se producen | ||
| + | con este modo de acceso. | ||
| + | |||
| + | ==== OpenCM ==== | ||
| + | |||
| + | < | ||
| + | chupete: | ||
| + | </ | ||
| + | |||
| + | OpenCM dice que no tiene instalada la librería openSSL a pesar de que sí | ||
| + | está instalada: | ||
| + | |||
| + | < | ||
| + | chupete: | ||
| + | Reading Package Lists... Done | ||
| + | Building Dependency Tree... Done | ||
| + | Sorry, openssl is already the newest version. | ||
| + | 0 packages upgraded, 0 newly installed, 0 to remove and 1 not upgraded. | ||
| + | chupete: | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | ==== GNU arch ==== | ||
| + | |||
| + | GNU arch parece que adolece del mismo problema: la comprobación de configure | ||
| + | dice que no está instalado " | ||
| + | |||
| + | < | ||
| + | chupete: | ||
| + | |||
| + | The configured versions of diff and diff3 do not handle files | ||
| + | not ending in newline correctly. | ||
| + | |||
| + | configured diff = diff. | ||
| + | configured diff3 = / | ||
| + | |||
| + | |||
| + | Use config options | ||
| + | --with-gnu-diff PROG | ||
| + | --with-gnu-diff3 PROG | ||
| + | |||
| + | NOTE: especially on BSD-derived systems, you will want | ||
| + | to grab a recent version of GNU diff and compile it for use | ||
| + | with those config options. | ||
| + | the native diff tools on your system, but you do need to | ||
| + | | ||
| + | have made a poor decision about their native diffs. | ||
| + | |||
| + | | ||
| + | </ | ||
| + | |||
| + | |||
| + | Sin embargo, sí que lo está: | ||
| + | |||
| + | < | ||
| + | chupete: | ||
| + | diff - File comparison utilities | ||
| + | chupete: | ||
| + | Reading Package Lists... Done | ||
| + | Building Dependency Tree... Done | ||
| + | Sorry, diff is already the newest version. | ||
| + | 0 packages upgraded, 0 newly installed, 0 to remove and 1 not upgraded. | ||
| + | chupete: | ||
| + | diff diff3 | ||
| + | chupete: | ||
| + | diff3: missing operand | ||
| + | diff3: Try 'Diff3 --help' | ||
| + | </ | ||
| + | |||
| + | Con los paquetes *.deb que encontré tampoco funciona: informa que la versión | ||
| + | de libc no es la que el paquete esperaba y cancela. | ||
| + | |||
| + | |||
| + | ==== darcs ==== | ||
| + | |||
| + | === Qué dice su página web === | ||
| + | |||
| + | |||
| + | [1] http:// | ||
| + | |||
| + | Su página web[1] presenta a darcs como "otro sistema de control de código | ||
| + | fuente", | ||
| + | Como base teórica el autor presenta una " | ||
| + | en la mecánica cuántica, que sirve de fundamento teórico del software. | ||
| + | |||
| + | === Instalación === | ||
| + | |||
| + | |||
| + | Según su página web, tras modificar el fichero sources.list de debian para | ||
| + | que incluya los fuentes al proyecto: | ||
| + | |||
| + | < | ||
| + | deb http:// | ||
| + | </ | ||
| + | |||
| + | |||
| + | Hemos ejecutado '' | ||
| + | paquetes: | ||
| + | |||
| + | < | ||
| + | chupete:/ | ||
| + | Hit http:// | ||
| + | Hit http:// | ||
| + | Get:1 http:// | ||
| + | Ign http:// | ||
| + | Fetched 1100B in 1s (763B/s) | ||
| + | Reading Package Lists... Done | ||
| + | Building Dependency Tree... Done | ||
| + | chupete:/ | ||
| + | </ | ||
| + | |||
| + | Y a continuacion apt-get install darcs para que efectúe la instalación: | ||
| + | |||
| + | < | ||
| + | chupete:/ | ||
| + | [....] | ||
| + | Official i386 Binary-1 (20031201)' | ||
| + | |||
| + | Get:1 http:// | ||
| + | Selecting previously deselected package libgmp3. | ||
| + | (Reading database ... 34955 files and directories currently installed.) | ||
| + | Unpacking libgmp3 (from .../ | ||
| + | Selecting previously deselected package darcs. | ||
| + | Unpacking darcs (from .../ | ||
| + | |||
| + | chupete:~# apt-get install darcs-server | ||
| + | </ | ||
| + | |||
| + | Es aconsejable instalar también el programa wget, que darcs necesita | ||
| + | pero no comprueba su existencia: | ||
| + | |||
| + | < | ||
| + | chupete:~# apt-get install wget | ||
| + | </ | ||
| + | |||
| + | |||
| + | La instalación ha sido sencilla y sin dificultades; | ||
| + | que la distribución donde lo ha desarrollado y probado es Debian. | ||
| + | |||
| + | === Realizando el primer cambio === | ||
| + | |||
| + | Igual que en el caso anterior, para las pruebas hemos utilizado el mismo | ||
| + | proyecto "hello world" que en el caso de Aegis. El comando que crea el | ||
| + | repositorio es "darcs initialize", | ||
| + | el propio subdirectorio del proyecto: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | AUTHORS | ||
| + | COPYING | ||
| + | ChangeLog | ||
| + | INSTALL | ||
| + | Makefile | ||
| + | Makefile.am | ||
| + | Makefile.dist | ||
| + | Makefile.in | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | AUTHORS | ||
| + | COPYING | ||
| + | ChangeLog | ||
| + | INSTALL | ||
| + | Makefile | ||
| + | Makefile.am | ||
| + | Makefile.dist | ||
| + | </ | ||
| + | |||
| + | El siguiente paso consiste en añadir todos los ficheros del proyecto | ||
| + | al repositorio del mismo: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | </ | ||
| + | |||
| + | Y luego se efectúa un checkout de todos los ficheros, que en el lenguaje | ||
| + | de darcs implica grabar todos los cambios: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | Darcs needs to know what name (conventionally an email address) to use as the | ||
| + | patch author, e.g. 'Fred Bloggs < | ||
| + | now it will be stored in the file ' | ||
| + | in the future. | ||
| + | this file. | ||
| + | |||
| + | What is your email address? Pruebas Darcs < | ||
| + | What is the patch name? Initial Release | ||
| + | Do you want to add a long comment? [yn] | ||
| + | |||
| + | Initial Release | ||
| + | ***DARCS*** | ||
| + | |||
| + | Aquí pondremos la descripción larga del parche, que en este caso | ||
| + | es la creación inicial del repositorio. | ||
| + | |||
| + | --Fin del Fichero-- | ||
| + | </ | ||
| + | |||
| + | |||
| + | Después de realizados unos cambios en el proyecto, el propio darcs nos | ||
| + | informa de qué es lo que hemos cambiado en el mismo mediante el comando | ||
| + | '' | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | { | ||
| + | hunk ./Makefile 42 | ||
| + | -build_triplet = i686-pc-linux-gnu | ||
| + | -host_triplet = i686-pc-linux-gnu | ||
| + | -target_triplet = i686-pc-linux-gnu | ||
| + | -ACLOCAL = ${SHELL} / | ||
| + | +build_triplet = i586-pc-linux-gnu | ||
| + | +host_triplet = i586-pc-linux-gnu | ||
| + | +target_triplet = i586-pc-linux-gnu | ||
| + | +ACLOCAL = ${SHELL} / | ||
| + | hunk ./Makefile 48 | ||
| + | -AMTAR = ${SHELL} / | ||
| + | -AUTOCONF = ${SHELL} / | ||
| + | +AMTAR = ${SHELL} / | ||
| + | +AUTOCONF = ${SHELL} / | ||
| + | hunk ./Makefile 51 | ||
| + | [...] | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Igual que en el caso anterior, simplemente ejecutando '' | ||
| + | guardaremos los datos relativos al cambio en el repositorio de código | ||
| + | fuente: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | hunk ./Makefile 42 | ||
| + | -build_triplet = i686-pc-linux-gnu | ||
| + | [....] | ||
| + | What is the patch name? Tras ejecutar configure | ||
| + | Do you want to add a long comment? [yn] n | ||
| + | Finished recording patch 'Tras ejecutar configure' | ||
| + | </ | ||
| + | |||
| + | Una nueva ejecución del comando '' | ||
| + | que la información en el repositorio se ha guardado con éxito. | ||
| + | |||
| + | |||
| + | === Realizando un cambio concurrente === | ||
| + | |||
| + | Ahora vamos a realizar un cambio al repositorio desde dos ubicaciones/ | ||
| + | ususarios distintos, y vamos a observar cómo se gestionan las colisiones | ||
| + | sobre el mismo fichero de código fuente. | ||
| + | |||
| + | == Haciendo que el repositorio sea visible públicamente == | ||
| + | |||
| + | El primer paso para realizar esto es hacer que el repositorio que hemos | ||
| + | creado, que por ahora sólo es visible para nuestro usuario, lo sea para el | ||
| + | resto del mundo. | ||
| + | |||
| + | Hemos creado un directorio / | ||
| + | que darcs crea en esta máquina, a continuación hemos hecho un enlace | ||
| + | simbólico a nuestro proyecto desde el mismo: | ||
| + | |||
| + | < | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | total 8 | ||
| + | drwxr-xr-x | ||
| + | drwxr-xr-x | ||
| + | lrwxrwxrwx | ||
| + | </ | ||
| + | |||
| + | == Descargando el repositorio para trabajar con él == | ||
| + | |||
| + | El segundo paso es que otro usuario -sea pruebas1- se descargue una copia | ||
| + | completa del código fuente así publicado y pueda trabajar con él. Para ello | ||
| + | pruebas1 ha creado un directorio de trabajo con un repositorio vacío: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | pruebas1@chupete: | ||
| + | pruebas1@chupete: | ||
| + | </ | ||
| + | |||
| + | Y mediante el comando darcs pull ha solicitado una copia completa de todos | ||
| + | parches que tiene el usuario pruebas2 en su repositorio: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | |||
| + | Sat Jul 23 11:47:38 CEST 2005 Pruebas Darcs < | ||
| + | * Initial Release | ||
| + | Shall I pull this patch? (1/2) [ynWvpxqadjk], | ||
| + | |||
| + | Sat Jul 23 18:23:02 CEST 2005 Pruebas Darcs < | ||
| + | * Tras ejecutar configure | ||
| + | Shall I pull this patch? (2/2) [ynWvpxqadjk], | ||
| + | pruebas1@chupete: | ||
| + | |||
| + | Sat Jul 23 11:47:38 CEST 2005 Pruebas Darcs < | ||
| + | * Initial Release | ||
| + | Shall I pull this patch? (1/2) [ynWvpxqadjk], | ||
| + | pruebas1@chupete: | ||
| + | AUTHORS | ||
| + | COPYING | ||
| + | ChangeLog | ||
| + | INSTALL | ||
| + | Makefile | ||
| + | Makefile.am | ||
| + | Makefile.dist | ||
| + | </ | ||
| + | |||
| + | == Efectuando un cambio concurrente == | ||
| + | |||
| + | En darcs, los dos usuarios tienen su propio repositorio de código fuente; | ||
| + | por lo que el cambio concurrente se puede producir de dos formas: cuando | ||
| + | el usuario pruebas1 importa un cambio a su repositorio que entra en conflicto | ||
| + | con un cambio que haya realizado él mismo y guardado, o bien cuando el | ||
| + | usuario pruebas2 importa un cambio realizado por el usuario pruebas1 | ||
| + | que entra en conflicto con los cambios realizados por él. | ||
| + | |||
| + | Entendiendo que la raiz del problema es más o menos la misma, optaremos por | ||
| + | probar uno de los casos: cuando el usuario pruebas2 ha realizado un cambio | ||
| + | y éste entra en conflicto con el cambio que el usuario pruebas1 ha hecho en | ||
| + | su propio repositorio. Hacerlo de este modo es más fácil ya que así el | ||
| + | usuario pruebas1 no necesita hacer su repositorio accesible públicamente. | ||
| + | |||
| + | Comenzaremos por realizar los cambios con el usuario pruebas2 y guardarlos | ||
| + | en el repositorio: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | Hello, World! + change made by pruebas2 | ||
| + | </ | ||
| + | |||
| + | Bien, el cambio ya está hecho. Ahora lo que haremos será guardar los cambios | ||
| + | en nuestro repositorio local: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | { | ||
| + | binary ./ | ||
| + | hunk ./ | ||
| + | - cout << " | ||
| + | + cout << " | ||
| + | } | ||
| + | pruebas2@chupete: | ||
| + | binary ./ | ||
| + | Shall I record this patch? (1/2) [ynWsfqadjk], | ||
| + | hunk ./ | ||
| + | - cout << " | ||
| + | + cout << " | ||
| + | Shall I record this patch? (2/2) [ynWsfqadjk], | ||
| + | What is the patch name? Change on the line hello world | ||
| + | Do you want to add a long comment? [yn] n | ||
| + | Finished recording patch ' | ||
| + | </ | ||
| + | |||
| + | Ahora el usuario pruebas1 hará un cambio en su propio repositorio: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Y lo guardará en darcs: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | { | ||
| + | hunk ./ | ||
| + | - cout << " | ||
| + | + cout << " | ||
| + | } | ||
| + | pruebas1@chupete: | ||
| + | Darcs needs to know what name (conventionally an email address) to use as the | ||
| + | patch author, e.g. 'Fred Bloggs < | ||
| + | now it will be stored in the file ' | ||
| + | in the future. | ||
| + | this file. | ||
| + | |||
| + | What is your email address? Pruebas Darcs Uno < | ||
| + | hunk ./ | ||
| + | - cout << " | ||
| + | + cout << " | ||
| + | Shall I record this patch? (1/1) [ynWsfqadjk], | ||
| + | What is the patch name? change on the hello world line | ||
| + | Do you want to add a long comment? [yn] n | ||
| + | |||
| + | Finished recording patch ' | ||
| + | </ | ||
| + | |||
| + | |||
| + | Y ahora integramos los cambios de pruebas2 en el repositorio de pruebas1, lo | ||
| + | que provocará una colisión: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | Pulling from " | ||
| + | |||
| + | Fri Jul 29 12:14:21 CEST 2005 Pruebas Darcs < | ||
| + | * Change on the line hello world | ||
| + | Shall I pull this patch? (1/1) [ynWvpxqadjk], | ||
| + | We have conflicts in the following files: | ||
| + | ./ | ||
| + | Finished pulling and applying. | ||
| + | </ | ||
| + | |||
| + | |||
| + | El cambio aparece en el código fuente así: | ||
| + | |||
| + | < | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | v v v v v v v | ||
| + | cout << " | ||
| + | ************* | ||
| + | cout << " | ||
| + | ^ ^ ^ ^ ^ ^ ^ | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Que obviamente al compilar produce un error y permite la corrección. | ||
| + | |||
| + | |||
| + | |||
| + | === Conclusiones === | ||
| + | |||
| + | Darcs es un sistema de control de código fuente distribuido. Cada uno de | ||
| + | los desarrolladores tiene su propio repositorio de código fuente donde | ||
| + | almacena sus propios cambios. Mediante su publicación en un sitio web, | ||
| + | estos cambios se pueden hacer visibles para el resto de desarrolladores. | ||
| + | |||
| + | A mi modo de ver, un sistema de control de código fuente distribuido, | ||
| + | incluso en un modelo de desarrollo como lo es el del software libre, | ||
| + | presenta una gran desventaja cuando el número de desarrolladores es | ||
| + | grande; ya que la sincronización de los cambios habrá de hacerse | ||
| + | forzosamente en un repositorio común o de lo contrario existe un gran | ||
| + | riesgo de que alguno de los miembros del equipo acabe con una versión | ||
| + | del proyecto diferente. | ||
| + | |||
| + | Por otra parte, he encontrado que el aprendizaje de la herramienta es | ||
| + | muy rápido y simple: comienza por unos ejemplos básicos para ir adentrandose | ||
| + | poco a poco en cuestiones más complicadas. | ||
| + | |||
| + | La resolución de los conflictos se realiza directamente en el fichero | ||
| + | implicado -no se ha hecho prueba de lo que ocurriría con los ficheros | ||
| + | binarios-, que en el caso del código fuente puede ser una solución | ||
| + | válida ya que al compilar se explicitaría un error. Sin embargo, los | ||
| + | conflictos en ficheros de texto planos -un changelog, por ejemplo- | ||
| + | podrían pasar desapercibidos al no requerir la intervención del | ||
| + | desarrollador para su integración. | ||
| + | |||
| + | Aunque también puede verse el defecto como una ventaja, ya que eso | ||
| + | permite la integración automática de parches al repositorio sin la | ||
| + | intervención del usuario más que en la supervisión del mismo. | ||
| + | |||
| + | Otra cosa que sería interesante destacar, aunque no se ha podido | ||
| + | verificar, es que existen versiones para otras plataformas: | ||
| + | FreeBSD y Windows. | ||
| + | |||
| + | |||
| + | |||
| + | ==== Aegis ==== | ||
| + | |||
| + | |||
| + | === Creación del proyecto === | ||
| + | |||
| + | Los pasos que se van a dar a continuación se efectuarán con el perfil | ||
| + | de administrador de aegis, que es el usuario " | ||
| + | que hacer nada especial para informar a aegis que éste es el usuario | ||
| + | administrador; | ||
| + | administrativas con este usuario. | ||
| + | |||
| + | Para guardar todos los proyectos hemos creado un directorio /aegis, que | ||
| + | inicialmente estará vacío. Como proyecto de pruebas hemos creado mediante | ||
| + | kdeveloper un programa "Hello World!" | ||
| + | necesarios para autoconf y automake. | ||
| + | |||
| + | Mediante el comando aenpr crearemos el proyecto y a continuación | ||
| + | establecemos las características del mismo mediante aepa: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | pruebas1@chupete: | ||
| + | |||
| + | /* | ||
| + | ** Project hello_world | ||
| + | */ | ||
| + | description = "The \" | ||
| + | developer_may_review = false; | ||
| + | developer_may_integrate = false; | ||
| + | reviewer_may_integrate = false; | ||
| + | developers_may_create_changes = false; | ||
| + | umask = 022; | ||
| + | default_test_exemption = false; | ||
| + | minimum_change_number = 10; | ||
| + | reuse_change_numbers = true; | ||
| + | minimum_branch_number = 1; | ||
| + | skip_unlucky = false; | ||
| + | compress_database = false; | ||
| + | develop_end_action = goto_being_reviewed; | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Asignacion de las figuras de desarrollador, | ||
| + | |||
| + | Áhora añadimos al proyecto las figuras de desarrollador -pruebas2-, | ||
| + | revisor -pruebas3- e integrador -pruebas4-: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | === Creamos la primera rama del proyecto === | ||
| + | |||
| + | Siguiendo con el usuario administrador de aegis -pruebas1-, hemos creado | ||
| + | la rama 1.0 para comenzar los cambios al proyecto: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | |||
| + | List of Projects | ||
| + | Sat Jul 16 23:34:10 2005 | ||
| + | |||
| + | Project | ||
| + | --------- | ||
| + | hello_world | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | "/ | ||
| + | aegis: project " | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | "/ | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Damos de alta el primer cambio del proyecto === | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | |||
| + | /* | ||
| + | ** nc dflt hint | ||
| + | */ | ||
| + | brief_description = " | ||
| + | description = " | ||
| + | cause = internal_bug; | ||
| + | test_exempt = true; | ||
| + | test_baseline_exempt = true; | ||
| + | regression_test_exempt = true; | ||
| + | architecture = | ||
| + | [ | ||
| + | " | ||
| + | ]; | ||
| + | </ | ||
| + | |||
| + | === El desarrollador realiza el primer cambio === | ||
| + | |||
| + | Ahora entramos como el usuario pruebas2 al objeto de hacer la primera subida | ||
| + | del proyecto. | ||
| + | |||
| + | La primera subida de ficheros es la más compleja, ya que hay que crear | ||
| + | el fichero aegis.conf con la información necesaria para que el almacenamiento | ||
| + | de versiones de los fuentes y la construcción del fichero se resuelvan | ||
| + | satisfactoriamente. | ||
| + | |||
| + | Comenzaremos por visualizar el cambio que tenemos pendiente: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | |||
| + | Project " | ||
| + | List of Changes awaiting_development | ||
| + | |||
| + | Change | ||
| + | ------- ------- | ||
| + | 10 awaiting_ | ||
| + | development | ||
| + | </ | ||
| + | |||
| + | A continuación informamos a Aegis que comenzamos la fase de desarrollo. | ||
| + | Aegis hace una copia de la rama activa tal y como está en el repositorio | ||
| + | en un directorio creado a tal efecto para nosotros: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | "/ | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y a continuación informamos a Aegis que pasamos a trabajar en el | ||
| + | directorio del proyecto mediante el comando aecd: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | |||
| + | Nuestro paso siguiente será hacer una copia completa del proyecto | ||
| + | " | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | hello_world | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | aegis.log | ||
| + | pruebas2@chupete: | ||
| + | </ | ||
| + | |||
| + | Añadiremos al proyecto todos los ficheros como nuevos: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | AUTHORS | ||
| + | COPYING | ||
| + | ChangeLog | ||
| + | INSTALL | ||
| + | Makefile | ||
| + | Makefile.am | ||
| + | Makefile.dist | ||
| + | pruebas2@chupete: | ||
| + | foreach? aenf $i -p hello_world.1.0 -c 10 | ||
| + | foreach? end | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | .... | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | completed | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | pruebas2@chupete: | ||
| + | </ | ||
| + | |||
| + | El manual de usuario dice que se tiene que aportar un fichero aegis.conf | ||
| + | en la primera versión del proyecto, donde se registra cómo se construye | ||
| + | el proyecto, qué herramientas de control de versiones se están utilizando, | ||
| + | etc. | ||
| + | |||
| + | Sin embargo, los pasos para crearlo no están muy claros; nosotros hemos | ||
| + | optado por copiar de / | ||
| + | que pueden sernos de utilidad: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete:/ | ||
| + | </ | ||
| + | |||
| + | En principio, daremos los valores por defecto como válidos. El uso de make | ||
| + | con aegis requiere de algunos " | ||
| + | en su lugar usemos la herramienta cook que se integra mejor con aegis-. | ||
| + | |||
| + | No obstante, para los proyectos autoconf y automake hace una salvedad. | ||
| + | En el manual de usuario, en la página 79 pueden leerse las instrucciones | ||
| + | concretas para llevar a cabo esta fase para el caso de proyectos que | ||
| + | usen Autoconf, como el nuestro. | ||
| + | |||
| + | El primer paso es reemplazar build_command por "exit 0" en el fichero de | ||
| + | configuración " | ||
| + | sin construir: | ||
| + | |||
| + | < | ||
| + | /* | ||
| + | * The build_command field of the project config file is used to invoke the | ||
| + | * relevant build command. | ||
| + | * The ${s Makefile} expands to a path into the baseline during development | ||
| + | * if the file is not in the change. | ||
| + | * about command substitutions. | ||
| + | */ | ||
| + | build_command = "exit 0"; | ||
| + | |||
| + | /* "gmake -f ${s Makefile} project=$p change=$c version=$v"; | ||
| + | </ | ||
| + | |||
| + | Y el siguiente paso consistirá en informar a Aegis de este nuevo fichero. | ||
| + | Tras varias pruebas infructuosas, | ||
| + | aegis espera para este fichero no es " | ||
| + | procedemos a renombrarlo e informar a Aegis del nuevo fichero que hay en | ||
| + | el proyecto: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | El mensaje que salía puede verse aquí: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | pruebas2@chupete: | ||
| + | </ | ||
| + | |||
| + | |||
| + | Una vez introducidos todos los cambios, procedemos a construir el proyecto. | ||
| + | Como es la primera vez, hemos puesto "exit 0" en el comando de construcción | ||
| + | para que nos permita realizarlo sin necesidad de hacer una construcción | ||
| + | real del mismo: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | aegis: exit 0 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | El siguiente paso es indicar a Aegis que el desarrollo a finalizado. Primero | ||
| + | generamos los ficheros de diferencias, | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | [....] | ||
| + | aegis: set +e; diff -U10 -a /dev/null / | ||
| + | hello_world/ | ||
| + | main.cpp,D; test $? -le 1 | ||
| + | aegis: set +e; diff -U10 -a /dev/null / | ||
| + | hello_world/ | ||
| + | main.o,D; test $? -le 1 | ||
| + | aegis: set +e; diff -U10 -a /dev/null / | ||
| + | hello_world/ | ||
| + | / | ||
| + | D; test $? -le 1 | ||
| + | aegis: set +e; diff -U10 -a /dev/null / | ||
| + | hello_world/ | ||
| + | / | ||
| + | template,D; test $? -le 1 | ||
| + | [....] | ||
| + | </ | ||
| + | |||
| + | Tras esta operación se crearán numerosos ficheros con extensión *,D -uno | ||
| + | por cada fichero que se ha cambiado o creado-. Estos ficheros de | ||
| + | diferencias permiten ver a los revisores e integradores qué se ha hecho | ||
| + | en cada cambio. | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | AUTHORS | ||
| + | AUTHORS, | ||
| + | COPYING | ||
| + | COPYING, | ||
| + | ChangeLog | ||
| + | ChangeLog, | ||
| + | INSTALL | ||
| + | INSTALL, | ||
| + | Makefile | ||
| + | Makefile, | ||
| + | Makefile.am | ||
| + | Makefile.am, | ||
| + | Makefile.dist | ||
| + | Makefile.dist, | ||
| + | Makefile.in | ||
| + | Makefile.in, | ||
| + | </ | ||
| + | |||
| + | Y finalmente damos por finalizado el cambio: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Con lo que queda finalizado el primer cambio. | ||
| + | |||
| + | |||
| + | === La revisión e integración del primer cambio === | ||
| + | |||
| + | A diferencia de otros sistemas de control de código fuente, Aegis exige | ||
| + | que los cambios que se realizan estén revisados y e integrados. | ||
| + | |||
| + | == La revisión del cambio == | ||
| + | |||
| + | En primer lugar entraremos como el revisor y daremos por válido el | ||
| + | cambio realizado en el proyecto. Comenzaremos por visualizar los cambios | ||
| + | que tenemos pendientes para revisar: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | |||
| + | Project " | ||
| + | List of Changes being_reviewed | ||
| + | |||
| + | Change | ||
| + | ------- ------- | ||
| + | 10 being_reviewed | ||
| + | </ | ||
| + | |||
| + | El siguiente paso será cambiar al directorio donde se ha realizado el | ||
| + | cambio, que está dentro del directorio " | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | pruebas3@chupete:/ | ||
| + | </ | ||
| + | |||
| + | |||
| + | Para que el grupo de desarrollo pueda trabajar dentro del directorio | ||
| + | del cambio, aegis establece los permisos adecuados del subdirectorio | ||
| + | que contiene el cambio, hello_world.1.0.C010. | ||
| + | |||
| + | En concreto, establece el ' | ||
| + | equipo de desarrollo, que en este caso es " | ||
| + | |||
| + | El comando '' | ||
| + | realizado de una forma rápida: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete:/ | ||
| + | :::::::::::::: | ||
| + | ./AUTHORS,D | ||
| + | :::::::::::::: | ||
| + | --- / | ||
| + | +++ / | ||
| + | @@ -0,0 +1 @@ | ||
| + | +Raul Luna Rodriguez < | ||
| + | --More--(Next file: ./ | ||
| + | </ | ||
| + | |||
| + | |||
| + | Y finalmente, si estimamos que el cambio se ha realizado correctamente, | ||
| + | damos por válido el mismo: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete:/ | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Si consideraramos que el cambio no cumple algún requisito y quisieramos | ||
| + | rechazarlo, utilizaríamos el comando " | ||
| + | |||
| + | == La integración del cambio == | ||
| + | |||
| + | Para ello entraremos como integrador -usuario " | ||
| + | revisar qué cambios están pendientes de integración: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete: | ||
| + | |||
| + | Project " | ||
| + | List of Changes awaiting_integration | ||
| + | |||
| + | Change | ||
| + | ------- ------- | ||
| + | 10 awaiting_ | ||
| + | integration | ||
| + | </ | ||
| + | |||
| + | Pasamos al directorio donde están los ficheros del cambio: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | Comenzamos por informar a aegis que la integración del cambio ha comenzado: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: project " | ||
| + | directory | ||
| + | aegis: project " | ||
| + | directory | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | El integrador debe construir y probar cada cambio: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | aegis: cd / | ||
| + | aegis: user " | ||
| + | aegis: exit 0 | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | pruebas4@chupete:/ | ||
| + | pruebas4@chupete:/ | ||
| + | </ | ||
| + | |||
| + | Y finalmente ya podemos dar la fase de integración como " | ||
| + | el cambio formará parte de la nueva línea base del proyecto: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | [un montón de información sobre la integración] | ||
| + | </ | ||
| + | |||
| + | Como efecto " | ||
| + | figura ya como completado: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | |||
| + | Project " | ||
| + | List of Changes | ||
| + | |||
| + | Change | ||
| + | ------- ------- | ||
| + | 10 completed | ||
| + | </ | ||
| + | |||
| + | === Efectuando un cambio concurrente === | ||
| + | |||
| + | Vamos a ver cómo gestiona Aegis aquellos cambios que afecten a la misma | ||
| + | línea de código. Para ello designaremos a pruebas2 y pruebas3 como | ||
| + | desarrolladores y les asignaremos un cambio, de tal forma que las | ||
| + | modificaciones que harán al proyecto afectarán a la misma línea de | ||
| + | código. | ||
| + | |||
| + | == El administrador añade un nuevo desarrollador al proyecto == | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | == El administrador crea dos cambios nuevos == | ||
| + | |||
| + | Se crearán dos cambios nuevos, uno para el desarrollador pruebas2 | ||
| + | y otro para el desarrollador pruebas3: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | /* | ||
| + | ** Project hello_world.1.0 | ||
| + | ** nc dflt hint | ||
| + | */ | ||
| + | brief_description = " | ||
| + | description = " | ||
| + | cause = internal_bug; | ||
| + | test_exempt = false; | ||
| + | test_baseline_exempt = false; | ||
| + | regression_test_exempt = true; | ||
| + | architecture = | ||
| + | [ | ||
| + | " | ||
| + | ]; | ||
| + | ~ | ||
| + | ~ | ||
| + | ~ | ||
| + | / | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y el cambio para el usuario pruebas3: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | /* | ||
| + | ** Project hello_world.1.0 | ||
| + | ** nc dflt hint | ||
| + | */ | ||
| + | brief_description = " | ||
| + | description = " | ||
| + | cause = internal_bug; | ||
| + | test_exempt = false; | ||
| + | test_baseline_exempt = false; | ||
| + | regression_test_exempt = true; | ||
| + | architecture = | ||
| + | [ | ||
| + | " | ||
| + | ]; | ||
| + | ~ | ||
| + | / | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | == El primer desarrollador lleva a cabo el cambio | ||
| + | |||
| + | Igual que en otros casos, comenzamos por visualizar los cambios pendientes: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | |||
| + | Project " | ||
| + | List of Changes awaiting_development | ||
| + | |||
| + | Change | ||
| + | ------- ------- | ||
| + | 11 awaiting_ | ||
| + | development | ||
| + | 12 awaiting_ | ||
| + | development | ||
| + | </ | ||
| + | |||
| + | Y a continuación nos apropiamos del cambio 11: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | "/ | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y comenzamos el proceso de desarrollo haciendo un " | ||
| + | los cambios que se nos ha creado: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | pruebas2@chupete: | ||
| + | </ | ||
| + | |||
| + | El directorio de cambios ahora creado es muy distinto del original: todos | ||
| + | los ficheros son enlaces simbólicos a los correspondientes ficheros que | ||
| + | quedaron almacenados en el cambio anterior: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | total 24 | ||
| + | drwxr-sr-x | ||
| + | drwxr-xr-x | ||
| + | lrwxrwxrwx | ||
| + | lrwxrwxrwx | ||
| + | lrwxrwxrwx | ||
| + | lrwxrwxrwx | ||
| + | [....] | ||
| + | </ | ||
| + | |||
| + | Aquellos ficheros que vayan a ser modificados han de ser " | ||
| + | local mediante el comando aecp -obviamente, | ||
| + | y aemv, además de sus correspondientes comandos " | ||
| + | para deshacerlos-. | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y ahora sí procedemos a realizar el cambio: | ||
| + | |||
| + | < | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Seguimos manteniendo las fases de construcción y realización de test como | ||
| + | triviales para mantener las pruebas dentro de unos cauces de simplicidad | ||
| + | razonables. De este modo, indicamos a Aegis que construya el proyecto: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | aegis: exit 0 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | |||
| + | Que cree los ficheros de diferencias: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: set +e; diff -U10 -a / | ||
| + | hello_world/ | ||
| + | main.cpp > / | ||
| + | test $? -le 1 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Creamos un test para el cambio que acabamos de hacer. Ya que no vamos | ||
| + | a construir el programa, simplemente verificaremos que la línea en | ||
| + | cuestión se encuentra en el fichero main.cpp: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | complete | ||
| + | pruebas2@chupete: | ||
| + | #!/bin/sh | ||
| + | |||
| + | tmp=/tmp/$$ | ||
| + | here=$(pwd) | ||
| + | |||
| + | fail() | ||
| + | { | ||
| + | echo FAILED 1>&2 | ||
| + | cd $here | ||
| + | rm -rf $tmp | ||
| + | exit 1 | ||
| + | } | ||
| + | |||
| + | pass() | ||
| + | { | ||
| + | cd $here | ||
| + | rm -rf $tmp | ||
| + | exit 0 | ||
| + | } | ||
| + | |||
| + | trap " | ||
| + | |||
| + | |||
| + | # comprobamos que el fichero " | ||
| + | # efectivamente el cambio introducido ya que | ||
| + | # de lo contrario el test de regresion no ' | ||
| + | # falla | ||
| + | |||
| + | grep ' | ||
| + | |||
| + | if [ $? -ne 0 ] | ||
| + | then | ||
| + | fail | ||
| + | fi | ||
| + | |||
| + | # si llega hasta aquí, es que ha funcionado | ||
| + | pass | ||
| + | </ | ||
| + | |||
| + | Probamos el test: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: /bin/sh / | ||
| + | cout << " | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | pruebas2@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: cd / | ||
| + | aegis: /bin/sh / | ||
| + | FAILED | ||
| + | aegis: project " | ||
| + | good | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | |||
| + | E indicamos la finalización del cambio: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | aegis: logging to / | ||
| + | aegis: set +e; diff -U10 -a /dev/null / | ||
| + | 00/ | ||
| + | test $? -le 1 | ||
| + | aegis: project " | ||
| + | pruebas2@chupete: | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | |||
| + | == El segundo desarrollador lleva a cabo el cambio == | ||
| + | |||
| + | El proceso es básicamente el mismo que en el caso anterior: | ||
| + | |||
| + | Nos " | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: project " | ||
| + | "/ | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Hacemos " | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | Copiamos el directorio " | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y procedemos a realizar el cambio: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Como Aegis lo exige, creamos un test para este cambio: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | complete | ||
| + | </ | ||
| + | |||
| + | Y lo completamos con el siguiente script: | ||
| + | |||
| + | < | ||
| + | #!/bin/sh | ||
| + | |||
| + | tmp=/tmp/$$ | ||
| + | here=$(pwd) | ||
| + | |||
| + | fail() | ||
| + | { | ||
| + | echo FAILED 1>&2 | ||
| + | cd $here | ||
| + | rm -rf $tmp | ||
| + | exit 1 | ||
| + | } | ||
| + | |||
| + | pass() | ||
| + | { | ||
| + | cd $here | ||
| + | rm -rf $tmp | ||
| + | exit 0 | ||
| + | } | ||
| + | |||
| + | trap " | ||
| + | |||
| + | |||
| + | # comprobamos que el fichero " | ||
| + | # efectivamente el cambio introducido ya que | ||
| + | # de lo contrario el test de regresion no ' | ||
| + | # falla | ||
| + | |||
| + | |||
| + | grep ' | ||
| + | |||
| + | if [ $? -ne 0 ] | ||
| + | then | ||
| + | fail | ||
| + | fi | ||
| + | |||
| + | pass | ||
| + | </ | ||
| + | |||
| + | |||
| + | Construimos el proyecto (esta fase se sigue manteniendo trivial y en realidad | ||
| + | sólo realiza un "exit 0" | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | aegis: exit 0 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y ejecutamos los test: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: logging to / | ||
| + | aegis: /bin/sh / | ||
| + | cout << " | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: cd / | ||
| + | aegis: /bin/sh / | ||
| + | FAILED | ||
| + | aegis: project " | ||
| + | good | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Creamos los ficheros de diferencias: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: logging to / | ||
| + | aegis: set +e; diff -U10 -a / | ||
| + | hello_world/ | ||
| + | main.cpp > / | ||
| + | test $? -le 1 | ||
| + | aegis: set +e; diff -U10 -a /dev/null / | ||
| + | 00/ | ||
| + | test $? -le 1 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y finalizamos el desarrollo: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: project " | ||
| + | for change 11 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Pero no nos deja finalizar el desarrollo porque el fichero " | ||
| + | bloqueado por el cambio del usuario anterior: habrá de ser revisado y | ||
| + | aprobado el cambio anterior para poder continuar con nuestro cambio. | ||
| + | |||
| + | |||
| + | == Se revisa e integra el cambio del primer desarrollador == | ||
| + | |||
| + | Debido a que el cambio que hemos hecho en el fichero main.cpp en el | ||
| + | primer cambio ha bloqueado este fichero y nos impide continuar con el | ||
| + | cambio del segundo desarrollador, | ||
| + | el primer cambio antes de continuar. | ||
| + | |||
| + | NOTA: El usuario " | ||
| + | la vez desarrollador y revisor: en este apartado actúa como revisor. | ||
| + | |||
| + | **Revisión del cambio ** | ||
| + | |||
| + | Comenzamos por ver los cambios pendientes de revisión que tenemos: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | |||
| + | Project " | ||
| + | List of Changes being_reviewed | ||
| + | |||
| + | Change | ||
| + | ------- ------- | ||
| + | 11 being_reviewed | ||
| + | </ | ||
| + | |||
| + | Y pasamos al directorio del cambio 11: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | Y le damos como válido: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete:/ | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | **Integración del cambio** | ||
| + | |||
| + | Comenzamos la integración del cambio: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete: | ||
| + | aegis: project " | ||
| + | directory | ||
| + | aegis: project " | ||
| + | directory | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | pruebas4@chupete: | ||
| + | aegis: project " | ||
| + | / | ||
| + | </ | ||
| + | |||
| + | Construimos: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | aegis: user " | ||
| + | aegis: exit 0 | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | </ | ||
| + | |||
| + | Probamos: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: appending log to / | ||
| + | aegis.log | ||
| + | aegis: /bin/sh / | ||
| + | t0001a.sh | ||
| + | cout << " | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: appending log to / | ||
| + | aegis.log | ||
| + | aegis: cd / | ||
| + | aegis: /bin/sh / | ||
| + | t0001a.sh | ||
| + | FAILED | ||
| + | aegis: project " | ||
| + | good | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | |||
| + | Generamos los ficheros de diferencias: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: appending log to / | ||
| + | aegis.log | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y damos la integración por finalizada, constituyendo una nueva " | ||
| + | del cambio: | ||
| + | |||
| + | < | ||
| + | pruebas4@chupete:/ | ||
| + | aegis: appending log to / | ||
| + | aegis.log | ||
| + | aegis: cd / | ||
| + | aegis: user " | ||
| + | aegis: ci -u -d -M -m' | ||
| + | -wpruebas2 -t/dev/null / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | new revision: 1.2; previous revision: 1.1 | ||
| + | done | ||
| + | RCS file: / | ||
| + | done | ||
| + | aegis: ( rlog -r / | ||
| + | '/ | ||
| + | aegis: ci -u -d -M -m' | ||
| + | -wpruebas2 -t/dev/null / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | new revision: 1.2; previous revision: 1.1 | ||
| + | done | ||
| + | RCS file: / | ||
| + | done | ||
| + | aegis: ( rlog -r / | ||
| + | '/ | ||
| + | aegis: ci -u -d -M -m' | ||
| + | -wpruebas2 -t/dev/null / | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | initial revision: 1.1 | ||
| + | done | ||
| + | RCS file: / | ||
| + | done | ||
| + | aegis: ( rlog -r / | ||
| + | {print $2}' ) > / | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | aegis: warning: file times in future | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Ahora es el momento de que el segundo desarrollador pueda completar | ||
| + | el cambio que estaba haciendo y que no pudo continuar. | ||
| + | |||
| + | == El segundo desarrollador completa el cambio | ||
| + | |||
| + | Al intentar finalizar el cambio, se nos comunica que la baseline del proyecto | ||
| + | ha cambiado: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete:/ | ||
| + | aegis: project " | ||
| + | changed | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Por lo que es necesario re-copiar main.cpp: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y ahora, al realizar el cambio, ya vemos el cambio que el otro | ||
| + | desarrollador hizo: | ||
| + | |||
| + | < | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Insertaremos nuestro propio cambio: | ||
| + | |||
| + | < | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | cout << " | ||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Y ahora sí que podremos finalizar nuestro desarrollo. Construir, probar y | ||
| + | diferencias: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: logging to / | ||
| + | aegis: project " | ||
| + | baseline | ||
| + | aegis: project " | ||
| + | aegis: exit 0 | ||
| + | aegis: project " | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: /bin/sh / | ||
| + | cout << " | ||
| + | aegis: project " | ||
| + | aegis: project " | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: cd / | ||
| + | aegis: /bin/sh / | ||
| + | FAILED | ||
| + | aegis: project " | ||
| + | good | ||
| + | aegis: project " | ||
| + | pruebas3@chupete: | ||
| + | aegis: appending log to / | ||
| + | aegis: set +e; diff -U10 -a / | ||
| + | hello_world/ | ||
| + | main.cpp > / | ||
| + | test $? -le 1 | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | Y finalizar el desarrollo: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | aegis: project " | ||
| + | </ | ||
| + | |||
| + | === Conclusiones | ||
| + | |||
| + | Más que un sistema de control de código fuente, Aegis permite implantar una | ||
| + | metodología de desarrollo en un equipo de trabajo. El sistema exige que todos | ||
| + | los cambios que se realicen en el software vayan acompañados de un test que | ||
| + | los compruebe (y que deberá fallar en las versiones anteriores del mismo | ||
| + | software). De esta forma, se pretende mejorar la calidad del software | ||
| + | producido. | ||
| + | |||
| + | El sistema además establece tres perfiles en el proceso de desarrollo de | ||
| + | software: el desarrollador, | ||
| + | cambios y los test que los acompañan, el revisor, que se ocupa de verificar | ||
| + | la calidad de los desarrollos y los test realizados y el integrador, que | ||
| + | da la revisión final antes de incorporarlos definitivamente al proyecto. | ||
| + | |||
| + | Aegis se encarga de mantener siempre una " | ||
| + | todos los cambios realizados, probados, revisados e integrados, de tal modo que | ||
| + | se trataría en todo momento de una versión "que funciona" | ||
| + | está siempre disponible para trabajar. | ||
| + | |||
| + | Sin embargo, la metodología de trabajo que propone Aegis parece más adecuada | ||
| + | para un entorno empresarial que para grupos de donde no hay una división tan | ||
| + | clara del trabajo. Igualmente, se trata de un software ideal para aquellos | ||
| + | grupos de trabajo que deseen implantar un método de trabajo así, pero en | ||
| + | absoluto es adecuado para aquellos que tengan otros modelos de desarrollo. | ||
| + | Es decir, que la herramienta exige de un cambio en la organización y forma | ||
| + | de hacer el trabajo, y este hecho ha de ser tenido en cuenta a la hora de | ||
| + | adoptarlo. | ||
| + | |||
| + | Por otra parte, el hecho de que todo el trabajo deba hacerse on-line, tampoco | ||
| + | favorece la dispersión geográfica de los miembros del equipo ya que implicaría | ||
| + | que éstos debieran estar conectados al servidor continuamente para poder | ||
| + | realizar los cambios. | ||
| + | |||
| + | Como hecho muy favorable hay que comentar que, al exigir que siempre se realice | ||
| + | un test para cada cambio que se haga, mejora enormemente la calidad del | ||
| + | software que se produce; aunque por otra parte debería haber una forma de | ||
| + | saltarse esta comprobación ya que hay errores que se detectan (un fallo de | ||
| + | memoria, por ejemplo) que no siempre tienen un test que lo pueda evidenciar. | ||
| + | |||
| + | La documentación no me ha parecido especialmente sencilla de leer, ya que | ||
| + | hay que leersela prácticamente al completo para hacerse una idea de lo que | ||
| + | el programa hace, y cómo hacerlo. Hay aspectos -como la creación del fichero | ||
| + | de configuración- que son realmente oscuros, y no estaría de más un asistente | ||
| + | o algo así para facilitar su creación. | ||
| + | |||
| + | Este hecho se evidencia en que la curva de aprendizaje del programa es alta; | ||
| + | por una parte todo se maneja en línea de comandos y los comandos para su uso | ||
| + | están más pensados en el día a día que en facilitar la vida al que está | ||
| + | aprendiendo a usar la herramienta. | ||
| + | |||
| + | Además, la portabilidad hacia otras plataformas no es posible: no hay versión | ||
| + | para otros sistemas operativos que no sea linux. | ||
| + | |||
| + | ==== CVS ==== | ||
| + | |||
| + | === Instalación === | ||
| + | |||
| + | CVS ya está instalado en el sistema debian: | ||
| + | |||
| + | < | ||
| + | chupete:~# apt-get install cvs | ||
| + | Reading Package Lists... Done | ||
| + | Building Dependency Tree... Done | ||
| + | Sorry, cvs is already the newest version. | ||
| + | 0 packages upgraded, 0 newly installed, 0 to remove and 1 not upgraded. | ||
| + | </ | ||
| + | |||
| + | == Creación del repositorio == | ||
| + | |||
| + | Para ello seguiremos las instrucciones dadas en la documentación de esta | ||
| + | asignatura, con la única diferencia que el repositorio lo crearemos en | ||
| + | ''/ | ||
| + | |||
| + | < | ||
| + | chupete:/ | ||
| + | 0022 | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | </ | ||
| + | |||
| + | == Haciendo una prueba sencilla | ||
| + | |||
| + | A fin de comprobar que el acceso en modo local al repositorio ya es posible, | ||
| + | realizaremos la prueba de importar un fichero sólamente. Esta prueba la | ||
| + | realizará el usuario " | ||
| + | grupo de desarrolladores (src): | ||
| + | |||
| + | < | ||
| + | chupete:~# usermod -G src pruebas2 | ||
| + | </ | ||
| + | |||
| + | Una vez hecho esto, el import funcionará perfectamente: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | File / | ||
| + | N prueba/ | ||
| + | |||
| + | No conflicts created by this import | ||
| + | </ | ||
| + | |||
| + | |||
| + | Comprobamos que efectivamente se obtienen bien los fuentes: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | cvs checkout: warning: cannot write to history file / | ||
| + | cvs checkout: Updating prueba | ||
| + | U prueba/ | ||
| + | pruebas2@chupete: | ||
| + | prueba | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | CVS prueba.txt | ||
| + | pruebas2@chupete: | ||
| + | prueba/ | ||
| + | pruebas2@chupete: | ||
| + | </ | ||
| + | |||
| + | El mensaje de error que aparece es porque los permisos de escritura para el | ||
| + | fichero " | ||
| + | |||
| + | < | ||
| + | chupete:/ | ||
| + | total 92 | ||
| + | drwxr-sr-x | ||
| + | -rw-r--r-- | ||
| + | -rw-r--r-- | ||
| + | chupete:/ | ||
| + | </ | ||
| + | |||
| + | Tras este cambio de permisos, ya funciona correctamente. | ||
| + | |||
| + | |||
| + | === Realizando el primer cambio === | ||
| + | |||
| + | Al igual que en los otros casos, comenzaremos por realizar una importación | ||
| + | del proyecto "hello world" que vamos a usar para los ejemplos y luego | ||
| + | realizar un cambio en el mismo para reflejarlo en el repositorio. | ||
| + | |||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | [....] | ||
| + | cvs import: Importing / | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | N hello_world/ | ||
| + | </ | ||
| + | |||
| + | No conflicts created by this import | ||
| + | |||
| + | Ahora ya podemos eliminar el directorio " | ||
| + | primer check-out directamente del repositorio de código fuente: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | aegis.conf | ||
| + | pruebas2@chupete: | ||
| + | cvs checkout: Updating hello_world | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | [...] | ||
| + | </ | ||
| + | |||
| + | Ha funcionado correctamente. Ahora realizaremos un cambio en el | ||
| + | fichero main.cpp: | ||
| + | |||
| + | < | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Y lo guardamos en el repositorio: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | Checking in main.cpp; | ||
| + | / | ||
| + | new revision: 1.2; previous revision: 1.1 | ||
| + | done | ||
| + | </ | ||
| + | |||
| + | === Realizando un cambio concurrente === | ||
| + | |||
| + | Ahora vamos a realizar un cambio en el repositorio usando dos usuarios | ||
| + | que se conectarán simulando una conexión remota. Estos usuarios realizarán | ||
| + | un cambio en el proyecto hello_world sobre una misma línea de código y | ||
| + | veremos cómo trata cvs los cambios. | ||
| + | |||
| + | == Haciendo que el repositorio sea visible públicamente == | ||
| + | |||
| + | El acceso remoto de los desarrolladores se realizará a través de ssh, | ||
| + | por lo que únicamente es necesario disponer de cuenta en la máquina. | ||
| + | Para el propósito de esta evaluación hemos creado cuatro cuentas | ||
| + | -'' | ||
| + | |||
| + | < | ||
| + | chupete:~# usermod -G src pruebas1 | ||
| + | chupete:~# usermod -G src pruebas2 | ||
| + | chupete:~# usermod -G src pruebas3 | ||
| + | chupete:~# usermod -G src pruebas4 | ||
| + | chupete:~# more /etc/group | grep src | ||
| + | src: | ||
| + | </ | ||
| + | |||
| + | No nos ocuparemos de habilitar el acceso público al repositorio porque | ||
| + | no aportaría nada a la presente evaluación. | ||
| + | |||
| + | Como el acceso que vamos a realizar es a través de ssh, ya no hay nada | ||
| + | más que hacer porque el repositorio ya es accesible a través de estas | ||
| + | cuentas de usuario. | ||
| + | |||
| + | == Descargando el repositorio para trabajar con él == | ||
| + | |||
| + | A continuación estableceremos en la máquina remota dos variables de | ||
| + | entorno para informar a CVS de la ubicación del repositorio, | ||
| + | editor que queremos usar para editar los archivos de log: | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | pruebas1@chupete: | ||
| + | </ | ||
| + | |||
| + | Y seguidamente haremos el " | ||
| + | |||
| + | < | ||
| + | pruebas1@chupete: | ||
| + | The authenticity of host ' | ||
| + | RSA key fingerprint is 7b: | ||
| + | Are you sure you want to continue connecting (yes/no)? | ||
| + | Warning: Permanently added ' | ||
| + | pruebas1@localhost' | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | [...] | ||
| + | </ | ||
| + | |||
| + | Aunque este ejemplo se ha realizado localmente por entero, la comunicación | ||
| + | se ha realizado a través de ssh y podría haberse realizado igualmente por | ||
| + | un usuario cualquiera accediendo remotamente a esta máquina. | ||
| + | |||
| + | La misma seguencia de acciones la realizaremos para el usuario pruebas3. | ||
| + | Hemos incorporado al fichero .cshrc las variables de entorno para que | ||
| + | no haya que introducirlas en cada sesión: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | : | ||
| + | pruebas3@chupete: | ||
| + | / | ||
| + | pruebas3@chupete: | ||
| + | The authenticity of host ' | ||
| + | RSA key fingerprint is 7b: | ||
| + | Are you sure you want to continue connecting (yes/no)? | ||
| + | Warning: Permanently added ' | ||
| + | pruebas3@localhost' | ||
| + | cvs server: Updating hello_world | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | U hello_world/ | ||
| + | [....] | ||
| + | </ | ||
| + | |||
| + | |||
| + | == Efectuando un cambio concurrente == | ||
| + | |||
| + | Tanto el usuario pruebas3 como el usuario pruebas4 harán un cambio en la | ||
| + | misma línea de código del fichero main.cpp, y comprobaremos lo que ocurre | ||
| + | al guardar los cambios en el repositorio. | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | </ | ||
| + | |||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | </ | ||
| + | |||
| + | el usuario pruebas2 guarda sus cambios: | ||
| + | |||
| + | < | ||
| + | pruebas2@chupete: | ||
| + | cvs commit: Examining . | ||
| + | cvs commit: Examining .deps | ||
| + | cvs commit: Examining docs | ||
| + | cvs commit: Examining docs/en | ||
| + | cvs commit: Examining templates | ||
| + | Checking in main.cpp; | ||
| + | / | ||
| + | new revision: 1.5; previous revision: 1.4 | ||
| + | done | ||
| + | </ | ||
| + | |||
| + | el usuario pruebas3 guarda sus cambios: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | cvs commit: Examining . | ||
| + | cvs commit: Examining .deps | ||
| + | cvs commit: Examining docs | ||
| + | cvs commit: Examining docs/en | ||
| + | cvs commit: Examining templates | ||
| + | pruebas3@localhost' | ||
| + | cvs server: Up-to-date check failed for ' | ||
| + | cvs [server aborted]: correct above errors first! | ||
| + | </ | ||
| + | |||
| + | e informa que se ha producido un error al actualizar el fichero " | ||
| + | Al ejecutar update para que actualice su contenido: | ||
| + | |||
| + | < | ||
| + | pruebas3@chupete: | ||
| + | pruebas3@localhost' | ||
| + | cvs server: Updating . | ||
| + | M Makefile | ||
| + | RCS file: / | ||
| + | retrieving revision 1.4 | ||
| + | retrieving revision 1.5 | ||
| + | Merging differences between 1.4 and 1.5 into main.cpp | ||
| + | rcsmerge: warning: conflicts during merge | ||
| + | cvs server: conflicts found in main.cpp | ||
| + | C main.cpp | ||
| + | cvs server: Updating .deps | ||
| + | cvs server: Updating docs | ||
| + | M docs/ | ||
| + | cvs server: Updating docs/en | ||
| + | M docs/ | ||
| + | cvs server: Updating templates | ||
| + | </ | ||
| + | |||
| + | Nos informa que ha habido conflictos en el fichero y que se han realizado | ||
| + | mezclas de código. Al examinar el código podemos observar que cvs ha puesto | ||
| + | los cambios del otro usuario y los nuestros juntos: | ||
| + | |||
| + | < | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | <<<<<<< | ||
| + | cout << " | ||
| + | ======= | ||
| + | cout << " | ||
| + | >>>>>>> | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | === Conclusiones === | ||
| + | |||
| + | |||
| + | CVS es uno de los sistemas de control de código fuente más utilizados en | ||
| + | la actualidad. Quizá su mayor virtud es la estabilidad, | ||
| + | de herramientas disponibles para utilizarlo. También cuenta con una comunidad | ||
| + | de usuarios muy activa y con versiones portadas a diferentes plataformas. | ||
| + | |||
| + | Sin embargo, quizá su mayor defecto es la poca flexibilidad que ofrece | ||
| + | en el manejo del repositorio, | ||
| + | permitido, y el soporte que ofrece para los ficheros binarios es deficiente. | ||
| + | |||
| + | No obstante, se trata de un sistema muy interesante por lo ampliamente probado | ||
| + | que está, y la posibilidad que ofrece de trabajar desde otras plataformas. | ||
| + | |||
| + | En el terreno de la documentación, | ||
| + | -el Cederqvist- me ha parecido bastante arduo de leer, ya que exige leerlo | ||
| + | por completo para encontrar cosas que deberían estar explicadas al principio. | ||
| + | Se hace necesario otro manual que explique el uso y administración de la | ||
| + | herramienta de una forma más fácil. | ||
| + | |||
| + | |||
| + | ==== Subversion ==== | ||
| + | |||
| + | |||
| + | === Instalación === | ||
| + | |||
| + | Subversion está disponible en paquete debian sólamente para la versión " | ||
| + | que es la versión estable en la actualidad. Aunque existía para woody (Debian | ||
| + | 3.0 r2), su autor ha descontinuado el producto una vez que " | ||
| + | estable. | ||
| + | |||
| + | Por lo tanto, la única opción que queda es compilar el paquete y realizar una | ||
| + | instalación manual. | ||
| + | |||
| + | Hemos descargado el la versión 1.2.1, que funciona sin Berkeley DB. Tras | ||
| + | ejecutar configure -hemos de tener en cuenta que configure " | ||
| + | " | ||
| + | funcionar- pasamos a ejecutar make; make install (este último comando | ||
| + | como root), y el proceso de instalación finaliza sin problemas. | ||
| + | |||
| + | == Creación del repositorio == | ||
| + | |||
| + | El siguiente paso consiste en la creación del repositorio, | ||
| + | en el directorio ''/ | ||
| + | |||
| + | < | ||
| + | chupete:~# svnadmin create /var/svn/ | ||
| + | chupete:~# ls /var/svn | ||
| + | README.txt | ||
| + | chupete:~# more / | ||
| + | This is a Subversion repository; use the ' | ||
| + | it. Do not add, delete, or modify files here unless you know how | ||
| + | to avoid corrupting the repository. | ||
| + | |||
| + | If the directory " | ||
| + | you may need to tweak the values in " | ||
| + | requirements of your site. | ||
| + | |||
| + | Visit http:// | ||
| + | </ | ||
| + | |||
| + | **Securización de subversion** | ||
| + | |||
| + | Nuestra intención al utilizar subversion en modo local es que un grupo de | ||
| + | usuarios determinado tuviera acceso al repositorio y a la operativa de | ||
| + | subversion, mientras que otro grupo de usuarios, aunque tuviera cuenta en | ||
| + | el sistema, no pudiera utilizarlo. | ||
| + | |||
| + | Bajo estas premisas, procedimos a asignar permisos de forma que sólo aquellos | ||
| + | usuarios que pertenecieran al grupo de usuarios '' | ||
| + | repositorio. Para ello, creamos un grupo '' | ||
| + | usuarios que nos servirían para hacer las pruebas: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | </ | ||
| + | |||
| + | Los permisos sobre el directorio serán 2770 -el " | ||
| + | y tiene por objeto que cada fichero o directorio que se cree dentro de | ||
| + | ese directorio pertenezca al grupo al que pertenece el directorio-, | ||
| + | y el grupo será svn: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:~# chmod 2770 / | ||
| + | chupete:~# chgrp svn /var/svn | ||
| + | </ | ||
| + | |||
| + | Los comandos relacionados con subversion sólo podrán ser ejecutados por | ||
| + | root o los miembros del grupo svn: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:~# ls -la / | ||
| + | -rwxr-xr-x | ||
| + | -rwxr-xr-x | ||
| + | -rwxr-xr-x | ||
| + | -rwxr-xr-x | ||
| + | -rwxr-xr-x | ||
| + | -rwxr-xr-x | ||
| + | chupete:~# chgrp svn / | ||
| + | chupete:~# chmod 550 / | ||
| + | # el comando " | ||
| + | # a que todos los usuarios deberán tener acceso al mismo (por si quieren | ||
| + | # utilizar Subversion como cliente) | ||
| + | chupete:~# chmod 555 / | ||
| + | chupete:~# ls -la / | ||
| + | -r-xr-xr-x | ||
| + | -r-xr-x--- | ||
| + | -r-xr-x--- | ||
| + | -r-xr-x--- | ||
| + | -r-xr-x--- | ||
| + | -r-xr-x--- | ||
| + | </ | ||
| + | |||
| + | A continuación, | ||
| + | repositorio lo creará el usuario root también, para que los permisos sean | ||
| + | lo más uniformes posible: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | README.txt | ||
| + | chupete:/ | ||
| + | This is a Subversion repository; use the ' | ||
| + | it. Do not add, delete, or modify files here unless you know how | ||
| + | to avoid corrupting the repository. | ||
| + | |||
| + | If the directory " | ||
| + | you may need to tweak the values in " | ||
| + | requirements of your site. | ||
| + | </ | ||
| + | |||
| + | A continuación, | ||
| + | acceso al mismo, cambiaremos el grupo de acceso para todos los ficheros | ||
| + | del repositorio: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | total 36 | ||
| + | drwxrwx--- | ||
| + | drwxr-xr-x | ||
| + | -rw-r--r-- | ||
| + | drwxr-xr-x | ||
| + | drwxr-xr-x | ||
| + | drwxr-sr-x | ||
| + | -r--r--r-- | ||
| + | drwxr-xr-x | ||
| + | drwxr-xr-x | ||
| + | </ | ||
| + | |||
| + | Cambios de permisos: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:/ | ||
| + | chupete:~# chmod 600 / | ||
| + | chupete:~# chmod 600 / | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | chupete:/ | ||
| + | </ | ||
| + | |||
| + | Seguidamente comprobaremos que el acceso al repositorio está permitido | ||
| + | haciendo que uno de los usuarios haga una importación de un proyecto: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | Adding | ||
| + | Adding | ||
| + | Adding | ||
| + | Adding | ||
| + | [....] | ||
| + | Adding | ||
| + | Adding | ||
| + | Adding | ||
| + | Adding | ||
| + | Adding | ||
| + | |||
| + | Committed revision 1. | ||
| + | </ | ||
| + | |||
| + | Se ha comprobado que el usuario pruebas1 como otro usuario que pertenezca | ||
| + | al grupo '' | ||
| + | check-out y check-in de modificaciones, | ||
| + | que los permisos que se han asignado funcionan con normalidad y permiten | ||
| + | la operacion del sistema. | ||
| + | |||
| + | Quedaría comprobar que aquellos usuarios que no pertenecen a ese grupo | ||
| + | especial no disponen de los permisos adecuados para ello: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | / | ||
| + | pruebas2@chupete: | ||
| + | svn: Unable to open an ra_local session to URL | ||
| + | svn: Unable to open repository ' | ||
| + | svn: Can't open file '/ | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Realizando del primer cambio === | ||
| + | |||
| + | Nuestro primer paso será, como viene siendo habitual, realizar una importación | ||
| + | del proyecto " | ||
| + | posteriormente realizaremos un cambio en el mismo para reflejarlo en el | ||
| + | repositorio. | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | Adding | ||
| + | Adding | ||
| + | [....] | ||
| + | Adding | ||
| + | Adding | ||
| + | Adding | ||
| + | |||
| + | Committed revision 1. | ||
| + | </ | ||
| + | |||
| + | El siguiente paso será hacer el checkout inicial: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | pruebas1@chupete: | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | [...] | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | Checked out revision 1. | ||
| + | </ | ||
| + | |||
| + | Realizar un cambio en uno de los archivos: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | Raul Luna Rodriguez < | ||
| + | pruebas1 < | ||
| + | </ | ||
| + | |||
| + | Y hacer un commit: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | Sending | ||
| + | Transmitting file data . | ||
| + | Committed revision 2. | ||
| + | </ | ||
| + | |||
| + | Y posteriormente actualizar los cambios del servidor: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | At revision 2. | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Realizando un cambio concurrente === | ||
| + | |||
| + | Igual que en las pruebas anteriores, comprobaremos cómo resuelve subversion | ||
| + | las colisiones en caso de que dos usuarios realicen un cambio sobre la | ||
| + | misma línea de un archivo de código fuente. Para realizar las pruebas | ||
| + | simularemos que el acceso se está realizando remotamente al repositorio, | ||
| + | aunque las pruebas se seguirán haciendo en local. | ||
| + | |||
| + | == Haciendo que el repositorio sea visible públicamente == | ||
| + | |||
| + | El acceso público lo efectuaremos habilitando el protocolo propietario | ||
| + | para el acceso remoto a la aplicación; | ||
| + | de internet, xinetd. | ||
| + | |||
| + | **Creando un usuario no privilegiado** | ||
| + | |||
| + | Nuestro primer paso -que no lo dice la documentación- será crear un | ||
| + | usuario no privilegiado para que sea quien acceda al repositorio: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:~# useradd -c ' | ||
| + | chupete:~# passwd svn | ||
| + | Enter new UNIX password: | ||
| + | Retype new UNIX password: | ||
| + | passwd: password updated successfully | ||
| + | </ | ||
| + | |||
| + | Y procederemos a cambiar el propietario de todos los ficheros del | ||
| + | repositorio: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:~# chown svn /var/svn -Rv | ||
| + | changed ownership of / | ||
| + | changed ownership of / | ||
| + | changed ownership of / | ||
| + | changed ownership of / | ||
| + | changed ownership of / | ||
| + | changed ownership of / | ||
| + | [...] | ||
| + | </ | ||
| + | |||
| + | **Configurando el super-demonio de internet** | ||
| + | |||
| + | El siguiente paso será configurar el super-demonio de internet para que | ||
| + | ejecute el servidor de subversion, svnserve. Para ello comenzaremos por | ||
| + | añadir en / | ||
| + | subversion: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:~# joe / | ||
| + | [....] | ||
| + | mysql | ||
| + | mysql | ||
| + | svn | ||
| + | svn | ||
| + | rfe | ||
| + | rfe | ||
| + | [....] | ||
| + | </ | ||
| + | |||
| + | Para luego configurar xinetd para que ejecute el servidor svnserve | ||
| + | cuando se le requiera: | ||
| + | |||
| + | <code shell> | ||
| + | chupete:~# joe / | ||
| + | # Subversion | ||
| + | service svn | ||
| + | { | ||
| + | socket_type | ||
| + | protocol | ||
| + | wait = no | ||
| + | user = svn | ||
| + | server | ||
| + | server_args | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | **Configurar el servidor de subversion** | ||
| + | |||
| + | |||
| + | Para probar que nuestra configuración de acceso funciona, habilitaremos | ||
| + | el acceso anónimo de lectura al repositorio editando el fichero | ||
| + | ''/ | ||
| + | |||
| + | <code shell> | ||
| + | chupete:/ | ||
| + | [general] | ||
| + | ### These options control access to the repository for unauthenticated | ||
| + | ### and authenticated users. | ||
| + | ### and " | ||
| + | anon-access = read | ||
| + | auth-access = write | ||
| + | ### The password-db option controls the location of the password | ||
| + | ### database file. Unless you specify a path starting with a /, | ||
| + | ### the file's location is relative to the conf directory. | ||
| + | ### Uncomment the line below to use the default password file. | ||
| + | # password-db = passwd | ||
| + | ### This option specifies the authentication realm of the repository. | ||
| + | ### If two repositories have the same authentication realm, they should | ||
| + | ### have the same password database, and vice versa. | ||
| + | ### is repository' | ||
| + | realm = Project TAS repository | ||
| + | |||
| + | También es necesario configurar adecuadamente el fichero passwd que se | ||
| + | encuentra en el mismo directorio: | ||
| + | |||
| + | chupete:/ | ||
| + | ### The name and password for each user follow, one account per line. | ||
| + | |||
| + | [users] | ||
| + | rluna=pepinillo | ||
| + | </ | ||
| + | |||
| + | **Una prueba sencilla** | ||
| + | |||
| + | Y finalmente, haremos una prueba sencilla para conectarnos a través | ||
| + | de la red, pero de modo local: | ||
| + | |||
| + | <code shell> | ||
| + | rluna@chupete: | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | [....] | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | Checked out revision 2. | ||
| + | </ | ||
| + | |||
| + | **Afinando la configuración ** | ||
| + | |||
| + | Se puede mejorar la configuración del super-demonio de internet estableciendo | ||
| + | la máscara adecuada para el usuario que lo ejecuta (002) y un grupo por | ||
| + | defecto -svn, que ya venía configurado para el usuario-. | ||
| + | |||
| + | También es interesante pasar el parámetro -r al servidor, para que haga un | ||
| + | chroot al repositorio y de esta forma en la url no es necesario indicar | ||
| + | la ruta al repositorio. Es decir, que en vez de referirnos a nuestro | ||
| + | proyecto como '' | ||
| + | como '' | ||
| + | |||
| + | La configuración '' | ||
| + | |||
| + | <code shell> | ||
| + | chupete:/ | ||
| + | # Subversion | ||
| + | service svn | ||
| + | { | ||
| + | socket_type | ||
| + | protocol | ||
| + | wait = no | ||
| + | user = svn | ||
| + | group = svn | ||
| + | umask = 002 | ||
| + | server | ||
| + | server_args | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Y podremos comprobar que la prueba sigue funcionando (tras reiniciar el | ||
| + | super-demonio de internet): | ||
| + | |||
| + | < | ||
| + | rluna@chupete: | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | [....] | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | Checked out revision 2. | ||
| + | </ | ||
| + | |||
| + | == Descargando el repositorio para trabajar con él == | ||
| + | |||
| + | Ahora efectuaremos una descarga del repositorio para el usuario " | ||
| + | y para el usuario " | ||
| + | subversion): | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | [....] | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | A hello_world/ | ||
| + | Checked out revision 6. | ||
| + | </ | ||
| + | |||
| + | == Efectuando un cambio concurrente== | ||
| + | |||
| + | |||
| + | Ahora, tanto el usuario pruebas1 como pruebas2 modificarán el fichero main.cpp: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | < | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Primero pruebas1 hace el commit: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas1@chupete: | ||
| + | Authentication realm: < | ||
| + | Password for ' | ||
| + | Sending | ||
| + | Transmitting file data . | ||
| + | Committed revision 7. | ||
| + | </ | ||
| + | |||
| + | La contraseña que nos ha solicitado no es la de acceso al sistema de | ||
| + | pruebas1, sino la de acceso al repositorio, | ||
| + | efectuaremos el commit para el usuario pruebas2: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | |||
| + | Authentication realm: < | ||
| + | Password for ' | ||
| + | Sending | ||
| + | Transmitting file data .svn: Commit failed (details follow): | ||
| + | svn: Out of date: '/ | ||
| + | </ | ||
| + | |||
| + | Subversion informa que el fichero main.cpp está "out of date", es decir, | ||
| + | está obsoleto según la última revisión. Procedemos entonces a actualizarlo: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | C main.cpp | ||
| + | Updated to revision 7. | ||
| + | </ | ||
| + | |||
| + | y nos informa que ha habido un conflicto con main.cpp. Subversion crea | ||
| + | entonces tres archivos con extensiones .mine, .rANTERIOR y .rACTUAL. | ||
| + | El primero es el fichero original, el siguiente es el fichero tal y | ||
| + | como estaba en el repositorio antes del cambio y finalmente el fichero | ||
| + | .rACTUAL es el fichero como está actualmente en el repositorio. | ||
| + | |||
| + | Lo ilustraremos con el propio contenido del fichero: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | <<<<<<< | ||
| + | cout << " | ||
| + | ======= | ||
| + | cout << " | ||
| + | >>>>>>> | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | pruebas2@chupete: | ||
| + | |||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | pruebas2@chupete: | ||
| + | |||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | pruebas2@chupete: | ||
| + | |||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | cout << " | ||
| + | |||
| + | return EXIT_SUCCESS; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | En este caso, haremos prevalecer nuestro cambio sobre el del otro usuario: | ||
| + | |||
| + | <code shell> | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | pruebas2@chupete: | ||
| + | Sending | ||
| + | Transmitting file data . | ||
| + | Committed revision 8. | ||
| + | </ | ||
| + | |||
| + | === Conclusiones === | ||
| + | |||
| + | La razón de ser de Subversion es ofrecer a la comunidad de Open Source | ||
| + | "un CVS mejorado" | ||
| + | tiene, como son: | ||
| + | |||
| + | * posibilidad de versionar directorios | ||
| + | * posibilidad de incluir enlaces simbólicos | ||
| + | * ahora es posible renombrar un fichero sin que éste pierda su historia | ||
| + | * ahora es posible crear un fichero a partir de la copia de otro sin que éste pierda su historia | ||
| + | * ahora se pueden borrar directorios | ||
| + | * un mejor control sobre los formatos binarios | ||
| + | |||
| + | Quizá los requerimientos de seguridad, tanto en el acceso al repositorio | ||
| + | a través de un acceso local al propio sistema como a través del protocolo | ||
| + | svnserve sea la parte que presenta más carencias. Por la primera parte, | ||
| + | el procedimiento de instalación no establece un conjunto de permisos claro | ||
| + | que permita que un grupo de usuarios de la máquina pueda trabajar con el | ||
| + | repositorio y otros no, por otra parte el acceso remoto no puede limitar | ||
| + | el acceso a partes del repositorio a no ser que se utilicen los " | ||
| + | que provee la aplicación. Los permisos sí que resultan válidos en el | ||
| + | segundo caso para proyectos únicos, pero no para el caso en que un servidor | ||
| + | aloje a varios proyectos. | ||
| + | |||
| + | La documentación que se ha consultado, " | ||
| + | es muy completa y amena de leer; incluye una guía para hacerse rápidamente | ||
| + | con la aplicación, | ||
| + | aparte de una guía de referencia. Como dicen los autores, responde a las | ||
| + | necesidades de conocimiento de subversion que han ido surgiendo en las | ||
| + | listas de correo de esta aplicación a lo largo del tiempo. | ||
| + | |||
| + | ==== Conclusión final ==== | ||
| + | |||
| + | Como conclusión final de este análisis de varios sistemas de control de | ||
| + | código fuente, puede decirse que a pesar de lo superficial del análisis, | ||
| + | he podido detectar diferencias importantes entre las aplicaciones analizadas. | ||
| + | |||
| + | Quizá los análisis expuestos aquí no hayan sido de la profundidad deseable; | ||
| + | quedarían por tratar numerosos puntos como son la facilidad de administración, | ||
| + | un análisis en profundidad de la seguridad de la solución presentada, | ||
| + | la estabilidad del repositorio ante posibles daños en el mismo, la | ||
| + | disponibilidad de API's o librerías para crear aplicaciones cliente. Incluso | ||
| + | sería muy interesante analizar la disponibilidad de estas herramientas para | ||
| + | otras plataformas -Windows o Mac-. | ||
| + | |||
| + | No obstante, para poder realizar una mínima operativa con los repositorios, | ||
| + | ha sido necesario en muchos casos leerse completamente el manual del programa, | ||
| + | por lo que sí que se ha obtenido una visión en profundidad de los puntos | ||
| + | fuertes y débiles de cada programa. | ||
| + | |||
| + | Antes de continuar con el análisis definitivo, quisiera dar un breve repaso | ||
| + | de las características más importantes de cada uno de estos sistemas de | ||
| + | control de código fuente: | ||
| + | |||
| + | En primer lugar, decir que **GNU arch** y **Open CM** no se pudieron instalar | ||
| + | en la versión de debian que estoy utilizando en la actualidad -Debian 3.0 Woody 1-, | ||
| + | por lo que quedaron fuera de la evaluación. No obstante, OpenCM | ||
| + | tiene características muy interesantes respecto a seguridad y robustez | ||
| + | de la solución que merecería la pena valorar. | ||
| + | |||
| + | **Respecto a darcs**, los dos aspectos más destacables son por un lado la sencillez de su funcionamiento: | ||
| + | |||
| + | Más adelante, cuando el proyecto va avanzando y necesitamos | ||
| + | disponer de un repositorio en internet con acceso público, el manual nos | ||
| + | dice cómo hacerlo de la forma más fácil posible. Finalmente, cuando otros | ||
| + | desarrolladores crean parches que nos interesan -también con darcs- podemos | ||
| + | fácilmente pasar a formar una comunidad de desarrolladores sincronizando | ||
| + | nuestros respectivos repositorios. | ||
| + | |||
| + | Esta naturaleza distribuida de los repositorios es un concepto interesante, | ||
| + | que simplifica mucho la tarea de compartir parches y desarrollos entre | ||
| + | desarrolladores, | ||
| + | punto centralizado donde se guarden los fuentes hace que se pierda -o quede | ||
| + | dificultada enormemente- el desarrollo de una versión " | ||
| + | cualquiera de los desarrolladores puede tener la suya propia en su máquina, | ||
| + | mejor o peor parcheada en función de su conexión a internet. | ||
| + | |||
| + | **Respecto a Aegis** puede considerarse que es algo más que un sistema de | ||
| + | control de código fuente. Además de ello, permite organizar el trabajo al | ||
| + | establecer varios perfiles de acceso a la aplicación: | ||
| + | integrador y administrador. Por otra parte, en el proceso de desarrollo | ||
| + | se implanta la obligatoriedad de incluir un script que compruebe cada | ||
| + | cambio que se implanta, con lo que se mejora la calidad del software | ||
| + | que se produce. | ||
| + | |||
| + | Las ventajas que añade Aegis en el desarrollo de su solución se transforman | ||
| + | en inconvenientes en un sistema de fuente abierta, donde los desarrolladores | ||
| + | realizan su labor "por amor al arte", y es difícil que encajen favorablemente | ||
| + | tener a alguien por encima que les asigne las tareas y que revise su trabajo. | ||
| + | |||
| + | Sin embargo sí que parece un sistema muy apropiado para un entorno empresarial, | ||
| + | donde esas jerarquías suelen estar fuertemente establecidas, | ||
| + | parte la disponibilidad de acceso a la máquina de desarrollo es total, hecho | ||
| + | que se hace necesario en este tipo de herramientas y que me parece un | ||
| + | requisito muy exigente para llevarlo a la práctica en el mundo del software | ||
| + | libre. | ||
| + | |||
| + | **La opción de CVS** nos parece altamente interesante por varios motivos: | ||
| + | 1) se trata de un software ampliamente probado, y del que se puede disponer | ||
| + | incluso de empresas que ofrecen soporte; 2) hay una comunidad de usuarios | ||
| + | muy activa que pueden ofrecernos su ayuda, y abundante documentación; | ||
| + | la disponbilidad en otras plataformas -por lo menos en Windows- está | ||
| + | ampliamente consolidada, | ||
| + | servidor. | ||
| + | |||
| + | Sin embargo, las carencias que tiene en la gestión del repositorio son | ||
| + | destacables: | ||
| + | imposibilidad de borrar directorios, | ||
| + | enlaces simbólicos, | ||
| + | borremos completamente ese fichero y creemos uno nuevo con el mismo | ||
| + | nombre.... Se trata de carencias que han alentado la creación del | ||
| + | siguiente competidor en la lucha, Subversion. | ||
| + | |||
| + | **Subversion nace** --y así lo declaran abiertamente sus creadores-- como | ||
| + | '' | ||
| + | la posibilidad de hacer aquello que CVS nunca permitió: guardar historia | ||
| + | de un directorio, permitir cambiar de nombre elementos como directorios, | ||
| + | gestión eficiente de archivos binarios mediante una herramienta " | ||
| + | soporta comparación en modo binario; contemplar la posibilidad de tratar | ||
| + | las colisiones para los ficheros binarios también, permitir reemplazar | ||
| + | ficheros.... | ||
| + | |||
| + | Precísamente esta característica de " | ||
| + | ha hecho que nos tomemos algún tiempo más en su análisis, leyendo en detalle | ||
| + | el manual de la aplicación. Hemos encontrado que, por lo menos en la versión | ||
| + | que se instala en Debian 3.0 (woody1) existen importantes deficiencias de | ||
| + | seguridad: no está adecuadamente cubierto el acceso a través del sistema | ||
| + | de ficheros. Por otra parte, el programa servidor, svnserve debería ejecutarse | ||
| + | como root, comprometiendo la seguridad del sistema en caso de que se produjera | ||
| + | una deficiencia de seguridad como un buffer overflow. | ||
| + | |||
| + | **Finalmente** | ||
| + | |||
| + | Si tuviera que decidirme por un sistema de control de código fuente para | ||
| + | un proyecto de software libre, optaría por Subversion, haciendo las | ||
| + | modificaciones de controles de acceso oportunas. En su favor obra la | ||
| + | gran difusión que está teniendo, la calidad del repositorio que implementan, | ||
| + | la fortaleza de su diseño que le va a permitir un crecimiento estable | ||
| + | en los próximos años, y el hecho innegable que es el reemplazo para | ||
| + | CVS, por lo que va a tener una gran difusión en los próximos años, | ||
| + | y eso garantiza la buena salud del proyecto. | ||
| + | |||
| + | |||
