martes, mayo 23, 2006

cojo-gestión de configuración

Este post me ha llevado un poco más de la cuenta, pero es que se las trae... espero que a los informáticos que leen el blog les sirva de algo, y a los profanos... bueno, a lo mejor aprenden que no es oro todo lo que reluce.
Hay un refrán que dice "en casa del herrero cuchillo de palo", lo cuál es bastante cierto si hablamos de informática. Parece que los ingenierillos disfrutan haciendo trabajo de monos espaciales. Se enciende una luz y tiras de una palanca. Repítelo un millón de veces y tendrás a un especialista en ingeniería del software.

Con la ingeniería del software me pasa lo mismo que con el comunismo. Las dos cosas me gustan, pero no puedo decir lo mismo de los ingenieros del software y los comunistas, que suelen ser gilipollas.

Vayamos al meollo de la cuestión. En las asignaturas de "injenierida del chofgüer" y derivadas parece que son asignaturas en las que enseñan a manejar el "Guord", a poner bien de colorines el documento, a hacerte unos encabezados muy chulos, a hacer un montón de fichas en tablitas para requisitos y componentes... y los alumnos, en cuanto tienen que pensar un poco, se quedan pasmados con el dedo en la nariz (ver diagrama:
Free Image Hosting at www.ImageShack.us)
y repiten como buenos simios amaestrados que son. Los más afortunados recibirán su plátano, trabajarán de consultores ganando una pasta y se sentirán dichosos de haber triunfado en la vida. Los menos, acabarán con estos jefes.

Siempre he pensado que la informática se creó con los siguientes objetivos:
  1. Automatizar tareas.
  2. Asistir en la resolución de problemas.
  3. Almacenar datos.
(Y el punto dos se puede abstraer en el punto uno, teniendo en cuenta que la resolución de problemas por ordenador es automatizar procedimientos de resolución.)

Luego vino el ocio, la multimierda y tal, pero eso ya es harina de otro costal y se me escapa un poco del tema... hmmmm... no, ya me he escapado, voy a intentar volver a lo que tenía en la cabeza desde un principio.

Estaba intentando describir cómo para la última práctica de la carrera (Sistemas Informáticos) nos hemos desviado un poco de las típicas chapuzas artesanales y hemos automatizado los procesos de documentación todo lo que hemos podido (se podría haber hecho más, pero hay que encontrar un equilibrio entre el tiempo que empleas en mejorar los procesos y el tiempo que te ahorras con los procesos mejorados); con el fin de poder recurrir aquí cuando quiera repetir y de paso que cualquier otro se pueda subir al carro de los elegidos.

Empecemos enumerando los requisitos necesarios para montar el sistema:
  • Servidor unix (o windows con cygwin) conectado a la red.
    • cvs
    • ssh
    • make
    • openjade (y todas las utilidades para docbook)
    • ghostscript
    • xmllint
    • python
  • Clientes
    • edición xml (posibles alternativas)
      • jedit + plugin xml (recomendada)
      • vex (algo wysiwyg, pero todavía incompleto... como ventaja se puede incluir como workspace en eclipse).
      • kxml (no está mal para ver la estructura, pero pesado para editar)
      • emacs + sgml mode (un clásico que nunca falla)
    • cliente cvs (posibles alternativas)
      • cvs a pelo (algo coñazo, pero efectivo y disponible en casi todas partes)
      • tortoise cvs (cómodo y divertido, para windows)
      • eclipse (es lo más cómodo si ya lo usas para desarrollar y editar xml)
    • hoja de cálculo
      • oocalc (recomendada, porque exporta como queremos)
      • gnumeric (copy & paste a un vi o emacs para exportar)
      • excel (copy & paste a un notepad para exportar)
Ahora vamos a explicar cómo se monta el chiringuito para hacer URD's, SRD's y otras mierdas variadas:
  1. Montar las cuentas de usuarios
  2. Montar un repositorio CVS:
    1. entrar en el directorio que queramos tener como repositorio y ejecutar el comando "cvs init" (un sitio típico es "/var/cvs", aunque puede estar en el home de una cuenta especial para el proyecto, a la que tienen permiso de acceso, lectura y escritura los miembros del grupo)
    2. crear un módulo para la documentación (la manera más fácil es hacerlo con el asistente del eclipse, en el menú contextual sobre un proyecto "team > share project", o en la línea de comandos con "cvs import nombre-modulo grupo version")
  3. Crear uno directorio para cada grupo de:
    • Documentos
    • Imágenes compartidas (logotipos, etc.)
    • Plantillas comunes
  4. Crear un directorio para el primer documento (bajo el de documentos):
    1. Crear un Makefile (que luego explicaremos qué tiene).
    2. Subdirectorio para las imágenes propias del documento.
    3. Subdirectorio para los requisitos, con sus scripts y más cosas (luego lo explicamos).
    4. Documentos xml para cada capítulo ó sección (con el grano todo lo fino que queramos) y un documento maestro (también explicamos cómo funciona ahora).
Aquí está la disposición de nuestro módulo de documentación para Sistemas Informáticos (con algunas cosas abreviadas y con comentarios seguidos de una #):

workspace/ssii_docs/
|-- CVS #esto es información del cvs, los siguientes están abrevidados
| |-- Entries
| |-- Repository
| |-- Root
| `-- Template
|-- diagramas #diagramas del rational y otros dibujitos
| |-- Bender.emx
| |-- CVS
| |-- Disenyo.mdx
| |-- Disenyo.wdx
| |-- Disenyo5EC87526B7F54B30B9A09AFCE8E3EBA7.idx
| |-- Mermelada.mdx
| |-- Mermelada.wdx
| |-- build.xml
| |-- disenyo1037AB48F0554ECA9D513EDDDE78C57A.idx
| |-- instalacion.svg
| `-- sensor_tapon.svg
|-- documentos
| |-- CVS
| |-- anteproyecto #el anteproyecto, abarcará URD y SRD
| | |-- CVS
| | |-- Makefile #fantástico makefile
| | |-- anteproyecto.xml #documento maestro
| | |-- anteproyecto_final.pdf #el resultado final
| | |-- anteproyecto_final.ps #un resultado intermedio
| | |-- anteproyecto_final.xml #un resultado intermedio
| | |-- chap_descripcion_modelo_logico.xml #los siguientes chap*.xml son capítulos
| | |-- chap_disenno_arquitectonico.xml
| | |-- chap_estimacion.xml
| | |-- chap_introduccion.xml
| | |-- chap_maquinas_estados.xml
| | |-- chap_planificacion.xml
| | |-- chap_plano_instalacion.xml
| | |-- chap_presupuesto.xml
| | |-- chap_pruebas.xml
| | |-- chap_requisitos_software.xml
| | |-- chap_requisitos_usuario.xml
| | |-- chap_resumen.xml
| | |-- cocomo #informes del cocomo
| | | |-- CVS
| | | |-- cocomo-report.rpt
| | | `-- cocomo.est
| | |-- images #gráficos para incrustar (*.ps y *.eps)
| | | |-- CVS
| | | |-- Mermelada__Arrancar__Actividad__Arrancar.ps
| | | |-- Mermelada__Arrancar__Secuencia__InteractionInstance1__Arrancar.ps
| | | |-- Mermelada__Casos_uso.ps
| | | |-- Mermelada__Clases_analisis.ps
| | | |-- Mermelada__Configurar__Actividad__Configurar.ps
| | | |-- Mermelada__Configurar__Secuencia__InteractionInstance1__Configurar.ps
| | | |-- Mermelada__Despliegue.ps
| | | |-- Mermelada__Emergencia__Actividad__Emergencia.ps
| | | |-- Mermelada__Emergencia__Secuencia__InteractionInstance1__Emergencia.ps
| | | |-- Mermelada__Generar_informes__Actividad__Generar_informes.ps
| | | |-- Mermelada__Generar_informes__Secuencia__InteractionInstance1__Generar_informes.ps
| | | |-- Mermelada__Parar__Actividad__Parar.ps
| | | |-- Mermelada__Parar__Secuencia__InteractionInstance1__Parar.ps
| | | |-- Mermelada__esclavo 1__estados.ps
| | | |-- Mermelada__esclavo2__estados.ps
| | | |-- Mermelada__maestro__estados.ps
| | | |-- bender.eps
| | | |-- cocomo.eps
| | | |-- costes-proyecto.eps
| | | |-- costos-proyecto.pdf
| | | |-- esclavo1.eps
| | | |-- esclavo2.eps
| | | |-- instalacion.ps
| | | |-- maestro.eps
| | | |-- planificacion.ps
| | | |-- sensor_tapon.ps
| | | `-- vaf.eps
| | |-- presupuesto #una simple hoja de cálculo para trabajar con ella
| | | |-- CVS
| | | `-- hardware.ods
| | |-- pruebas_aceptacion #cositas para las pruebas
| | | |-- CVS
| | | |-- hoja_pruebas_aceptacion.csv #el fichero que se procesa, derivado del excel
| | | |-- hoja_pruebas_aceptacion.excel.xml #fichero de excel para trabajar
| | | |-- procesar_pruebas.py #script que procesa el csv y lo transforma en xml docbook
| | | `-- pruebas_aceptacion.docbook.xml #fragmento de docbook
| | `-- requisitos #los requisitos de usuario y del software
| | |-- CVS
| | |-- README.TXT #instrucciones para usarlos
| | |-- hoja_requisitos.csv #fichero para procesar, derivado del xls
| | |-- hoja_requisitos.xls #fichero de excel, para trabajar
| | |-- matriz-d-sr-ur.docbook.xml #matriz de trazabilidad, derivada del script
| | |-- matriz-i-sr-ur.docbook.xml #matriz de trazabilidad, derivada del script
| | |-- matriz.py #módulo genérico para las matrices de trazabilidad
| | |-- matriz.pyc #bytecode de python
| | |-- procesar_lista_requisitos.py #script que genera listas de requisitos
| | |-- procesar_matriz_directa.py #script que genera una matriz de trazabilidad directa
| | |-- procesar_matriz_inversa.py #script que genera una matriz de trazabilidad inversa
| | |-- requisitos-sr.docbook.xml #fragmento docbook, derivado
| | |-- requisitos-ur.docbook.xml #fragmento docbook, derivado
| | |-- requisitos.py #modulo generico para los requisitos
| | |-- requisitos.pyc #bytecode de python
| | `-- urd.xml #fragmento de docbook, que incrusta los *.docbook.xml
| |-- disenyo #otro documento, más de lo mismo
| | |-- CVS
| | |-- Makefile
| | |-- chap_contexto.xml
| | |-- chap_descripcion.xml
| | |-- chap_descripcion_completo.xml
| | |-- chap_disenyo.xml
| | |-- chap_estandares.xml
| | |-- chap_introduccion.xml
| | |-- chap_viabilidad.xml
| | |-- chap_vision_sistema.xml
| | |-- componentes #descripción detallada de los componentes software
| | | |-- CVS
| | | |-- matriz-trazabilidad.docbook.xml #derivado
| | | |-- modelo_componentes.xls
| | | |-- modulo_automatas #una carpetita para modulito
| | | | |-- CVS
| | | | |-- especificacion-componentes.docbook.xml #fichero derivado del csv
| | | | |-- modelo_componentes.csv #csv exportado del xls
| | | | |-- modelo_componentes.xls #descripción de los componentes
| | | | `-- pseudocodigo #pseudocódigo de los componentes
| | | | |-- CVS
| | | | |-- TODO
| | | | |-- comp_AUT-003.txt
| | | | |-- comp_AUT-004.txt
| | | | |-- comp_AUT-005.txt
| | | | |-- ... #muchos más
| | | | `-- comp_AUT-059.txt
| | | |-- modulo_comunicaciones #otro modulito, igual que el anterior
| | | | |-- CVS
| | | | |-- especificacion-componentes.docbook.xml
| | | | |-- modelo_componentes.csv
| | | | |-- modelo_componentes.xls
| | | | `-- pseudocodigo
| | | | |-- CVS
| | | | |-- comp_COM-003.txt
| | | | |-- comp_COM-004.txt
| | | | |-- ... #muuuuuuchos más
| | | | `-- comp_COM-100.txt
| | | |-- ... #un par de módulos más
| | | `-- scripts
| | | |-- CVS
| | | |-- modulos.py #modulo genérico para los módulos... vaya juego de palabras
| | | |-- modulos.pyc #bytecode de python
| | | |-- procesar_lista_modulos.py #genera la lista de los módulos de un componente
| | | `-- procesar_matriz_trazabilidad.py #genera las matrices de trazabilidad
| | |-- disenyo.xml #documento maestro
| | |-- disenyo_final.pdf #resultado final
| | |-- disenyo_final.ps #resultado intermedio
| | |-- disenyo_final.xml #resultado intermedio
| | `-- images #graficos para incrustar
| | |-- CVS
| | |-- Disenyo__Automatas__Main.eps
| | |-- Disenyo__Comunicaciones__Buzon__Main.eps
| | |-- Disenyo__Comunicaciones__Main.eps
| | |-- Disenyo__Comunicaciones__Mensajes__Main.eps
| | |-- Disenyo__GestorInformes__Main.eps
| | |-- Disenyo__Main.eps
| | |-- Disenyo__SCADA__Main.eps
| | |-- Mermelada__Automatas__Main.ps
| | |-- Mermelada__Comunicaciones__Buzon__Main.ps
| | |-- Mermelada__Comunicaciones__Main.ps
| | |-- Mermelada__Comunicaciones__Mensajes__Main.ps
| | |-- Mermelada__GestorInformes__Main.ps
| | |-- Mermelada__Main.ps
| | |-- Mermelada__SCADA__Main.ps
| | |-- bender.eps
| | `-- diagrama_contexto.ps
| |-- manual_usuario #el manual. estamos trabajando en él ahora mismo
| | |-- CVS
| | |-- Makefile
| | |-- images
| | | |-- CVS
| | | `-- bender.eps
| | `-- sum.xml
| `-- stylesheets #plantillas comunes (sólo se usa custom.dsl, las otras son de referencia)
| |-- CVS
| |-- cogent-both.dsl
| |-- custom.dsl
| |-- freebsd_tuned.dsl
| |-- gdp-both.dsl
| `-- guide.dsl
`-- plantillas_docbook #ejemplos de archivos docbook
|-- CVS
|-- Makefile #ejemplo de makefile
|-- articulo.xml #ejemplo de articulo, para los manuales
|-- chap1src.xml #ejemplo de capitulo, para incluir en documentos
|-- images #varios logos, para guarrear
| |-- CVS
| |-- logo.wmf
| |-- logotipo1.gif
|-- libro.xml #ejemplo de libro
|-- prueba.xml #no sé qué tenía este, creo que era un ejemplo de xinclude
`-- stylesheets
|-- CVS
|-- cogent-both.dsl
|-- custom.dsl
|-- gdp-both.dsl
`-- ldp.dsl

57 directories, 468 files
Ahora vamos a hablar un poco más detalladamente de cada tipo de archivo.

Los XML de DocBook

Para el que no conozca DocBook, habría que decir que es un lenguaje de marcas XML diseñado para escribir documentos estructurados. Los documentos estructurados son aquellos que tienen partes, capítulos, secciones, subsecciones, etc.

La edición de estos documentos puede ser un tanto tediosa si se hace a mano sin ningún editor especializado (que nos ayude con las marcas), pero tiene la ventaja de que al ser texto plano (bueno, al ser XML no es plano, es un árbol :-P), lo cuál tiene algunas recompensas:
  • Se puede gestionar directamente con un SCV, como CVS ó SVN, con lo cuál se mantiene un histórico de las revisiones, se puede volver a una versión anterior en el caso de fallo, se puede ver quién ha escrito cada cosa...
  • Se pueden hacer fácilmente programas que escriban este tipo de documentos (lo cuál lo explotaremos bastante).
  • Se puede editar en (casi) cualquier parte.
Una nota a tener en cuenta aquí, es que como estamos usando OpenJade, le gustan los documentos que están codificados en el formato ISO-8859-1 (eso, o escapáis todos los caracteres acentuados), para lo cuál deberéis especificarlo en las opciones del editor que uséis.

Nosotros también queremos tener documentos modulares, lo cuál lo conseguiremos con dos tecnologías: XInclude y las System Entities de XML.

XInclude
XInclude tiene una ventaja y un inconveniente principales. La ventaja es que permite hacer un pre-procesado de los documentos a incluir, como puede ser seleccionar una rama del XML concreta para incluir ó escapar los caracteres no válidos en un documento XML al incluir texto plano (como los > y los <, por ejemplo).

El inconveniente es que el motor de render que usamos (Jade) no lo procesa correctamente (para los que usen XSL-FO no creo que tengan este problema, pero yo ya había apostado por Jade, ¡y uno no aprende DSSSL para luego cambiarse!).

Para solucionar el problema de procesamiento, optamos por hacer un pre-procesado de los documentos con una herramienta externa, en este caso xmllint.

System Entities
Es un mecanismo bastante más sencillo que el XInclude, ya que simplemente vuelva el contenido del fichero incluido en el maestro, lo cuál tiene el problema de que por lo general, los documentos que incluyamos no serán de por sí documentos DocBook válidos (por las cabeceras y tal) y no serán reconocidos como tal por los editores XML.

Esta característica nos viene muy bien para incluir los cachos de DocBook generados por nuestros programas, ya que en ellos no querremos perder tiempo declarando cabeceras, ni puede que sepamos de antemano en qué rama estarán metidos.

Gráficos

Como habréis podido observar, los gráficos están en formato PS ó EPS, que son formatos de gráficos vectoriales, lo cuál nos vendrá bien para que los diagramas no pierdan calidad en los documentos.

El problema que tienen estos gráficos es que están definidos en un lenguaje de programación de impresoras (que por cierto, es muy divertido aprenderlo, yo lo estoy haciendo) y no hay programas para editarlos directamente... pero por suerte, desde (casi) cualquier programa se puede exportar a PostScript, si bien no directamente, sí mediante la opción de imprimir a un archivo (habiendo instalado los drivers de una impresora PostScript, como los de casi cualquier impresora Láser).

Un pequeño escollo con el que nos encontramos aquí es que al generar los PDF's a partir de DocBook con Jade, nos dice que no le gustan los ficheros PS ni EPS. La solución es crear un PS con Jade y luego convertirlo a PDF con ps2pdf.

Las hojas de cálculo XLS y los CSV

Las hojas de cálculo son para editar registros de formato fijo, como son las típicas plantillas de requisitos y módulos de sofware. Con un poco de arte, se pueden automatizar varias cosillas, como la numeración automática, la selección de enumerados, etc.

Aquí os pongo un par de pantallazos para que veáis de qué hablo:
Free Image Hosting at www.ImageShack.usFree Image Hosting at www.ImageShack.us

El problema de usar los XLS es que son ficheros binarios y no se llevan muy bien con el CVS, así que si usáis Excel (a partir del 2003, creo), podéis guardarlos en el XML ese guarruzo de Microsoft. Si usáis OpenOffice, podéis seguir el tutorial de Pesso para guardar los documentos ODF en texto plano que enlazaré en cuanto esté listo. Si usáis Gnumeric, sólo tenéis que ir a preferencias, y especificar que el nivel de compresión de los archivos es 0.

Los CSV tienen algunas consideraciones especiales, para que puedan ser procesados más fácilmente:
  • Usar el tabulador como separador.
  • No usar delimitadores para el texto.
  • Estar codificados en UTF-8

Los scripts en Python

Para los que no lo conozcan, Python es un lenguaje dinámico interpretado, que te permite hacer muchas guarrerías de forma elegante y rápida, por lo que resulta ideal para lo que queremos hacer aquí.

Estos scripts también deberían estar codificados en UTF-8.

Estos scripts leeran los CSV y generarán cachos de DocBook a porrillo... como no hay mucho más que decir, aquí los pongo tal cual:

anteproyecto/requisitos/requisitos.py

#!/usr/bin/python
# -*- coding: UTF-8 -*-
import sys

"""Encapsula un requisito"""
class Requirement:
def __init__(self):
self.id = ""
self.type = ""
self.nid = -1
self.priority = ""
self.need = ""
self.stability = ""
self.source = ""
self.description = ""
self.verification = ""
self.dependencies = []
def __init__(self, line):
self.parse(line)

def parse(self, line):
tokens = line.strip().split("\t")
self.type = tokens[0]
self.nid = int(tokens[1])
self.id = tokens[2]
self.priority = tokens[3]
self.need = tokens[4]
self.stability = tokens[5]
self.source = tokens[6]
self.description = tokens[7]
self.verification = tokens[8]
self.dependencies = tokens[9:]

def printDocBookSheet(self):
print "<table id =\""+self.id+"\">"
print "<title>"+self.id+"</title>"
print "<tgroup cols=\"4\"><tbody>"
print "<row>"
print "<entry><emphasis role=\"strong\">Prioridad</emphasis></entry>"
print "<entry>", self.priority,"</entry>"
print "<entry><emphasis role=\"strong\">Necesidad</emphasis></entry>"
print "<entry>", self.need,"</entry>"
print "</row>"
print "<row>"
print "<entry><emphasis role=\"strong\">Estabilidad</emphasis></entry>"
print "<entry>", self.stability, "</entry>"
print "<entry><emphasis role=\"strong\">Fuente</emphasis></entry>"
print "<entry>", self.source, "</entry>"
print "</row>"
print "</tbody></tgroup>"
print "<tgroup cols=\"1\"><tbody>"
print "<row>"
print "<entry><emphasis role=\"strong\">Descripción</emphasis></entry>"
print "</row>"
print "<row>"
print "<entry>", self.description, "</entry>"
print "</row>"
print "<row><entry><emphasis role=\"strong\">Dependencias</emphasis></entry></row>"
print "<row><entry>"
for i in self.dependencies:
print "<link linkend=\"" +i+"\">", i, "</link>"
print "</entry></row>"
print "</tbody></tgroup>"
print "</table>"

def createRequirementsList():
reqs = []
headings = True
for line in sys.stdin.readlines():
if headings:
if line.startswith("\t"):
headings = False
else:
if not line.startswith("\t"):
r = Requirement(line)
reqs.append(r)
return reqs
anteproyecto/procesar_lista_requisitos.py

from requisitos import *
import sys

def main():
type = sys.argv[1]

reqs = createRequirementsList()

for r in reqs:
if r.type == type:
r.printDocBookSheet()

main()

anteproyecto/requisitos/matriz.py

from requisitos import *

def directTraceabilityMatrix(reqs, fromType, toType):
matrix = []
types = {}
for i in reqs:
types[i.id] = i.type

for i in reqs:
#si tenemos un requisito del tipo de partida
if i.type == fromType:
#cogemos las dependencias del tipo de destino
d = [j for j in i.dependencies if types[j] == toType]
matrix.append((i.id, d))
return matrix

def inverseTraceabilityMatrix(reqs, fromType, toType):
matrix = []
table = {}
types = {}

#inicializamos la tabla
for i in reqs:
if i.type == toType:
table[i.id] = []

for i in reqs:
types[i.id] = i.type

for i in reqs:
#si tenemos un requisito del tipo de destino
if i.type == fromType:
#miramos las dependencias del tipo de partida
for j in i.dependencies:
if types[j] == toType:
table[j].append(i.id)

#pasamos de la tabla a la lista
for i in table:
matrix.append((i, table[i]))

matrix.sort()

return matrix

def printTraceabilityMatrix(matrix, title):
print "<table>"
print "<title>", title, "</title>"
print "<tgroup cols = \"2\">"
print "<colspec colwidth=\"1*\"/>"
print "<colspec colwidth=\"4*\"/>"
print "<tbody>"
for i,j in matrix:
print "<row>"
print "<entry>", link(i), "</entry>"
print "<entry>"
for k in j:
print link(k)
print "</entry>"
print "</row>"
print "</tbody>"
print "</tgroup>"
print "</table>"
return

def link(r):
return "<link linkend=\""+r+"\">"+r+"</link>"

anteproyecto/requisitos/procesar_matriz_directa.py

from matriz import *

def main():
fromType = sys.argv[1]
toType = sys.argv[2]
title = sys.argv[3]

reqs = createRequirementsList()
matrix = directTraceabilityMatrix(reqs, fromType, toType)
printTraceabilityMatrix(matrix, title)

main()

anteproyecto/requisitos/procesar_matriz_inversa.py

from matriz import *

def main():
fromType = sys.argv[1]
toType = sys.argv[2]
title = sys.argv[3]

reqs = createRequirementsList()
matrix = inverseTraceabilityMatrix(reqs, fromType, toType)
printTraceabilityMatrix(matrix, title)

main()


Makefile (juntándolo todo)

Si alguna vez has utilizado "make", seguramente ya tendrás una idea de cómo funcionan los Makefiles, pero por si acaso, primero haré una breve introducción.

La herramienta make sirve para gestionar dependencias en proyectos, por lo que normalmente se asocia con programas en C (para no tener que compilar módulos que no han sido modificados), pero se puede usar para automatizar casi cualquier proceso de flujo de datos.

Los ficheros Makefile están formados por una lista de reglas, que están separadas entre sí por una o más líneas en blanco. Las reglas tienen 3 partes:
  • Objetivo (nombre del fichero a actualizar o de la regla)
  • Dependencias (otras reglas o nombres de ficheros de los que dependa el objetivo)
  • Acciones (comandos que se ejecutan para crear o actualizar el objetivo)
Así que tenemos que una regla es:
objetivo : dep1 dep2 dep3 #y más... a partir de la almohadilla va comentado
accion1
accion2
#y más...


Ahora aquí van los Makefiles que hemos usado:

anteproyecto/Makefile
NAME = anteproyecto

FLAGS = --dcl `if test -e /usr/share/sgml/xml.dcl ;then echo /usr/share/sgml/xml.dcl; else locate xml.dcl | tail -n1; fi`
STYLESHEET = ../stylesheets/custom.dsl

MOD_REQ = requisitos/requisitos.py
MOD_MAT = requisitos/matriz.py
PROC_LIST_REQ = requisitos/procesar_lista_requisitos.py
PROC_MAT_D_REQ = requisitos/procesar_matriz_directa.py
PROC_MAT_I_REQ = requisitos/procesar_matriz_inversa.py

HOJA_REQUISITOS = requisitos/hoja_requisitos.csv
MATRIZ_D_SR_UR = requisitos/matriz-d-sr-ur.docbook.xml
MATRIZ_I_SR_UR = requisitos/matriz-i-sr-ur.docbook.xml

all: pdf view

view:
xpdf $(NAME)_final.pdf || evince $(NAME)_final.pdf || acroread $(NAME)_final.pdf

pdf: $(NAME)_final.pdf

html: $(NAME)_final.xml $(STYLESHEET)
db2html $(FLAGS) $(NAME)_final.xml
cp -r images $(NAME)_final

$(NAME)_final.pdf: $(NAME)_final.ps
ps2pdf $<

$(NAME)_final.ps: $(STYLESHEET) $(NAME)_final.xml ../images/* images/*
db2ps $(FLAGS) -d $(STYLESHEET) $(NAME)_final.xml

$(NAME)_final.xml: $(NAME).xml chap*.xml requisitos matrices pruebas cocomo/*
xmllint --noent --encode "iso-8859-1" --xinclude $(NAME).xml > $@

#REQUISITOS

requisitos: requisitos/requisitos-ur.docbook.xml requisitos/requisitos-sr.docbook.xml

requisitos/hoja_requisitos.csv: requisitos/hoja_requisitos.xls
echo $@ : HAY QUE ACTUALIZAR EL CSV A MANO!!!
false

requisitos/requisitos-ur.docbook.xml: requisitos/hoja_requisitos.csv $(PROC_LIST_REQ)
cat $< | python $(PROC_LIST_REQ) UR > $@

requisitos/requisitos-sr.docbook.xml: requisitos/hoja_requisitos.csv $(PROC_LIST_REQ)
cat $< | python $(PROC_LIST_REQ) SR > $@

#MATRICES REQUISITOS
matrices: $(MATRIZ_D_SR_UR) $(MATRIZ_I_SR_UR)

$(MATRIZ_D_SR_UR): $(HOJA_REQUISITOS) $(PROC_MAT_D_REQ) $(MOD_REQ) $(MOD_MAT)
cat $< | python $(PROC_MAT_D_REQ) SR UR "Matriz de dependencias directas SR-UR" > $@

$(MATRIZ_I_SR_UR): $(HOJA_REQUISITOS) $(PROC_MAT_I_REQ) $(MOD_REQ) $(MOD_MAT)
cat $< | python $(PROC_MAT_I_REQ) SR UR "Matriz de dependencias inversas SR-UR" > $@

#PRUEBAS ACEPTACION

pruebas: pruebas_aceptacion/pruebas_aceptacion.docbook.xml

pruebas_aceptacion/hoja_pruebas_aceptacion.csv: pruebas_aceptacion/hoja_pruebas_aceptacion.excel.xml
echo $@ : HAY QUE ACTUALIZAR EL CSV A MANO!!!
false

pruebas_aceptacion/pruebas_aceptacion.docbook.xml: pruebas_aceptacion/hoja_pruebas_aceptacion.csv pruebas_aceptacion/procesar_pruebas.py
cat $< | python pruebas_aceptacion/procesar_pruebas.py PA > $@


#PRESUPUESTO


#CLEAN
clean:
rm -rf $(NAME)_final || true
rm -rf $(NAME)_final.junk || true
rm $(NAME)_final.xml || true
rm *.tex *.aux *.dvi *.log *.out *.ps *.pdf || true
rm requisitos/requisitos-??.docbook.xml || true
rm requisitos/matriz-?-??-??.docbook.xml || true
rm pruebas_aceptacion/pruebas_aceptacion.docbook.xml || true
disenyo/Makefile
NAME = disenyo

FLAGS = --dcl `if test -e /usr/share/sgml/xml.dcl ;then echo /usr/share/sgml/xml.dcl; else locate xml.dcl | tail -n1; fi`
STYLESHEET = ../stylesheets/custom.dsl

HOJA_AUT = componentes/modulo_automatas
HOJA_GEI = componentes/modulo_gestor_informes
HOJA_GUI = componentes/modulo_gui
HOJA_COM = componentes/modulo_comunicaciones
SCRIPT_COMPONTENTES = componentes/scripts/procesar_lista_modulos.py
SCRIPT_MATRIZ = componentes/scripts/procesar_matriz_trazabilidad.py

all: pdf view componentes

view:
xpdf $(NAME)_final.pdf || evince $(NAME)_final.pdf || acroread $(NAME)_final.pdf

pdf: $(NAME)_final.pdf

html: $(NAME)_final.xml $(STYLESHEET)
db2html $(FLAGS) $(NAME)_final.xml
cp -r images $(NAME)_final

$(NAME)_final.pdf: $(NAME)_final.ps
ps2pdf $<

$(NAME)_final.ps: $(STYLESHEET) $(NAME)_final.xml ../images/* images/*
db2ps $(FLAGS) -d $(STYLESHEET) $(NAME)_final.xml

preprocesado_xinclude_nivel2: chap_descripcion.xml
xmllint --noent --encode "iso-8859-1" --xinclude chap_descripcion.xml > chap_descripcion_completo.xml

$(NAME)_final.xml: $(NAME).xml chap*.xml matriz componentes preprocesado_xinclude_nivel2
xmllint --noent --encode "iso-8859-1" --xinclude $(NAME).xml > $@

#COMPONENTES

matriz:
python ${SCRIPT_MATRIZ} ${HOJA_AUT}/modelo_componentes.csv ${HOJA_COM}/modelo_componentes.csv ${HOJA_GEI}/modelo_componentes.csv ${HOJA_GUI}/modelo_componentes.csv > componentes/matriz-trazabilidad.docbook.xml

componentes: ${HOJA_AUT}/especificacion-componentes.docbook.xml ${HOJA_COM}/especificacion-componentes.docbook.xml ${HOJA_GEI}/especificacion-componentes.docbook.xml ${HOJA_GUI}/especificacion-componentes.docbook.xml

${HOJA_AUT}/modelo_componentes.csv: ${HOJA_AUT}/modelo_componentes.xls
echo $@ : HAY QUE ACTUALIZAR EL CSV ${HOJA_AUT} A MANO!!!
false

${HOJA_COM}/modelo_componentes.csv: ${HOJA_COM}/modelo_componentes.xls
echo $@ : HAY QUE ACTUALIZAR EL CSV ${HOJA_COM} A MANO!!!
false

${HOJA_GEI}/modelo_componentes.csv: ${HOJA_GEI}/modelo_componentes.xls
echo $@ : HAY QUE ACTUALIZAR EL CSV ${HOJA_GEI} A MANO!!!
false

${HOJA_GUI}/modelo_componentes.csv: ${HOJA_GUI}/modelo_componentes.xls
echo $@ : HAY QUE ACTUALIZAR EL CSV ${HOJA_GUI} A MANO!!!
false

${HOJA_AUT}/especificacion-componentes.docbook.xml: ${HOJA_AUT}/modelo_componentes.csv $(SCRIPT_COMPONTENTES)
cat $< | python $(SCRIPT_COMPONTENTES) ${HOJA_AUT}/pseudocodigo < ${HOJA_AUT}/modelo_componentes.csv > $@

${HOJA_COM}/especificacion-componentes.docbook.xml: ${HOJA_COM}/modelo_componentes.csv $(SCRIPT_COMPONTENTES)
cat $< | python $(SCRIPT_COMPONTENTES) ${HOJA_COM}/pseudocodigo < ${HOJA_COM}/modelo_componentes.csv > $@

${HOJA_GEI}/especificacion-componentes.docbook.xml: ${HOJA_GEI}/modelo_componentes.csv $(SCRIPT_COMPONTENTES)
cat $< | python $(SCRIPT_COMPONTENTES) ${HOJA_GEI}/pseudocodigo < ${HOJA_GEI}/modelo_componentes.csv > $@

${HOJA_GUI}/especificacion-componentes.docbook.xml: ${HOJA_GUI}/modelo_componentes.csv $(SCRIPT_COMPONTENTES)
cat $< | python $(SCRIPT_COMPONTENTES) ${HOJA_GUI}/pseudocodigo < ${HOJA_GUI}/modelo_componentes.csv > $@

#CLEAN
clean:
rm `find componentes -name "*.docbook.xml"` || true
rm -rf $(NAME)_final || true
rm -rf $(NAME)_final.junk || true
rm $(NAME)_final.xml || true
rm *.tex *.aux *.dvi *.log *.out *.ps *.pdf || true



Bueno, pues hasta aquí hemos llegado, que ya estoy hasta los cojones de escribir... si encuentro algún josting de archivos chulo, cuelgo un tbz con todo (o si alguien lo quiere, que me mande un mail a fortranito arroba gmail punto com).

Y recordad: ¡make es vuestro amigo!

lunes, mayo 15, 2006

Fortran by Warchief

Me he traido la tableta gráfica a la facultad para hacer unos diagramas para una práctica (y de paso vacilar un poco) y un colega freak ha hecho una caricatura:


Image Hosted by ImageShack.us


Ya le pillaré por banda en alguna tira... xD

jueves, mayo 11, 2006

next blog

¿Alguna vez has pinchado en el enlace que hay arriba a la derecha que pone "next blog"? Yo sí. Se encuentran cosas sorprendentes.

Hay un tipo concreto de blogger que me ha llamado la atención: adolescente depresivo que escribe un par de post contando qué dura es su vida y cómo le ignora el chico/a que le gusta y del que después no se vuelve a saber nada más (con un poco de suerte tomó la decisión acertada y se suicidó).

Además, estos blogs vienen en dos sabores a elegir: fondo negro VS fondo rosa. Creo que está bastante claro cómo son los que escriben cada tipo de blog. Los del fondo negro son los depresivos que se creen que todo el mundo está en su contra, que se sienten infravalorados (hey, a lo mejor es que realmente eres una mierda y por eso la gente te trata como tal!). Los del fondo rosa suelen ser niñas adolescentes que han leido demasiadas novelas de Danielle Steel y piensan que la vida es un culebrón, pero que al final habrá final feliz. Seguramente acaben cambiando el fondo rosa por uno negro.

Esa mierda no es buena, hermano.

Aquí os dejo unos cuantos enlaces por si os queréis deprimir un rato:
http://ifyoudontgrowyoudie.blogspot.com/
http://worker--bee.blogspot.com/
http://unspokenhopes.blogspot.com/
http://ilikethegirl.blogspot.com/
http://azureblessing.blogspot.com/
http://angelfireslife.blogspot.com/

En fin, si algún día me pongo a escribir cosas así (ya no me refiero al rollete intimista, sino a hacer el lila), que alguien me pegue una patada en los huevos.

jueves, mayo 04, 2006

Peor remedio que enfermedad

Os voy a contar lo que le sucedió a un colega, cuya identidad no revelaré para preservar su dignidad y anonimato.

Mi amigo tenía un problema; no follaba. No pillaba cacho ni emborrachando a las pibas. Un certero análisis vino a revelar que la causa era que tenía mucha caspa. No es que el chaval saliese en El Tomate, sino que le llamaban del Xanadú cuando se quedaban sin nieve artificial. Así que se fue presto al Carrefúl a comprar el mejor champú anticaspa posible (tampoco diré la marca, no sea que me denuncien).

Al cabo de unos días parecía que la cosa se había solucionado, los hombros de mi colega estaban limpios como una patena, pero no sospechaba que igual de limpia se iba a quedar si cabeza. El champú era tan fuerte que le estaba jodiendo el cuero cabelludo y dejando la cocorota como a Constantino Romero, sin ni un pelo de tonto.

Como no se iba a quedar en cama para siempre, enfermo de alopecia, se lo tomó con ánimo y fue a buscar una solución para aquel nuevo problema. Acudió a la farmacia y le dispensaron un crecepelo en espray unas pastillas cojonudas para arreglar la perjudicación. Efectivamente, la perjudicación de la azotea se le quitó, pero eran medicamentos caros y potentes, así que pagó con un billete de 500€ y le dieron 10€ de vuelta. Luego los efectos secundarios le dieron otros 10€ de vuelta (es decir, que le salió talego y medio).

La cosa iba mejorando, ya tenía la cabeza limpia y melenuda, pero ahora tenía una tripa que no le hacía nada atractivo. Cargado de moral por los éxitos parciales anteriores, se dijo que a la tercera iría la vencida y se decidió a ir al gimnasio a ponerse en forma. Una vez allí, se convenció a sí mismo de que la solución definitiva sería ponerse cachas, así ninguna tía podría resistírsele.

Para aumentar la efectividad de su entrenamiento, se puso a tomar proteinas y pastillitas mágicas que le daban los nuevos amigos que hizo en el gimnasio... se puso hecho un auténtico bestia, con su pelo flamante y sus músculos se convirtió en el terror de las nenas.

Por desgracia, con tanto anabolizante se volvió impotente, así que sigue sin poder follar.