você está aqui: Home  → Arquivo de Mensagens Programação Shell Linux: Inscrições Abertas

Unindo o subversion e o doxygen para um controle de configuração e uma boa documentação

Colaboração: Francisco José Alonso Ares

Data de Publicação: 07 de August de 2008

O subversion tem uma opção que permite a execução de qualquer programa em algumas etapas de seu trabalho de versionamento. São chamados "hooks", tem nomes padronizados para cada função disponível e devem ser instalados no diretório de mesmo nome dentro do repositório usado, ou seja:

/caminho/para/seu/repositório/hooks

Apesar de seu poder, o subversion sozinho não faz o gerenciamento de configuração de um software, apenas o gerenciamento de versão - que já não é pouca coisa!

Para manter registro não apenas das versões de um software mas também das versões de suas dependências que estejam no mesmo repositório e ainda gerando automaticamente a documentação para cada nova versão atualizada, peguei umas idéias no manual do próprio subversion e do doxygen e bolei os scripts abaixo.

O primeiro é só um "wrapper" para o segundo, que pode ser colocado em outro diretório.

Este segundo script cria um diretório temporário no próprio servidor em que o seu repositório está rodando e faz um "checkout" do projeto que acabou de ter sua versão atualizada.

Como opção, ele verifica se existe um arquivo "geradoc*" (pode ser "geradoc.c", "geradoc.txt", qualquer coisa, até com comprimento nulo, basta ter a entrada); caso não exista, ele não faz mais nada, apenas limpa esse diretório temporário.

Caso o "geradoc*" exista, ele faz uma varredura nos arquivos *.c, *.h, *.cpp e *.hpp (outros podem ser adicionados livremente) em busca da diretiva "#include" que contenha uma referência a algum arquivo que esteja no formato abaixo:

#include "../projeto/arquivo"

onde o "projeto" deve estar sob versionamento do subversion.

Após a extração dessas informações, ele gera um arquivo "depend.c" com umas poucas linhas que serão aproveitadas pelo doxygen. Estas linhas contém o número de versão de cada linha "#include" encontrada que aponte para um projeto externo ao projeto atual.

A seguir, ele remove qualquer prévia existência de um arquivo de configuração do doxygen e o substitui por um padrão, editando apenas o nome do projeto para que o documento final receba o nome do projeto de forma adequada.

O segmento seguinte executa o doxygen, move a documentação em HTML para um diretório onde um apache está rodando, também faz as mesmas tarefas que o "make pdf" faria, ou seja, finaliza a geração da documentação em PDF, que é uma das configurações usadas neste arquivo de configuração padrão do doxygen, copia este PDF para um diretório determinado e o envia por e-mail para o usuário que fez a atualização da versão. Só faltou encriptar via GPG, mas isto fica para outra oportunidade ;)

De quebra, ainda tem mais dois scripts: um encontra a versão do arquivo sendo documentado pelo doxygen dentro do repositório para que esta apareça na documentação gerada e outro que faz este mesmo arquivo passar pelo "astyle" antes de ser documentado, portanto garantindo uma formatação padronizada.

Seguem os arquivos:

arquivo post-commit

#!/bin/bash

/bin/echo _ _ _ _ `/bin/date` $1 $2 >> /var/log/svn/commit.log

r=`/usr/bin/svnlook dirs-changed /desenv/svnroot | /bin/sed -n 2p`

if [ "a" == "a"$r ]
then
       r=`/usr/bin/svnlook dirs-changed /desenv/svnroot | /bin/sed -n 1p`
fi

/caminho/para/o/segundo/script/postco $r $2 &

exit 0

arquivo postco

#!/bin/bash

# evita que traduções afetem comandos de "strings" como o sed , o cut e o grep
export LC_ALL="C"

R="$1"
#REV="$2"


u=`/usr/bin/svn info file:///caminho/do/repositório/$R | /bin/grep Author | /bin/cut -d" " -f4`
n=`/bin/cat /etc/postfix/aliases | /bin/grep $u | /bin/cut -f2`
g=`/bin/cat /etc/hosts | grep $u | cut -d" " -f1`
f="refman.pdf"
t=`/bin/echo $R | /bin/cut -d"/" -f2`

#cd /tmp/
#if [ -s post_commit ]
#then
#   /bin/rm -fR post_commit
#fi

d=`/bin/tempfile -d /tmp/ -p postcommit`
/bin/rm -f $d
/bin/mkdir $d
cd $d

/bin/echo = = = = `/bin/date` $R $u $n $g $t $d>> /var/log/svn/commit.log

/usr/bin/svn co file:///caminho/do/repositório/$R ./ > /dev/null

if [ -f geradoc* ]
then

#código de verificação e documentação de dependências

   LC_ALL="C"
   touch depend.c
   echo "/*! " > depend.c
   echo " * \\file depend.c " >> depend.c
   echo " * \\author "$u >> depend.c
   echo " * \\brief Lista de dependências para controle de configuração." >> depend.c
   echo " *" >> depend.c

   for h in "*.c" "*.h" "*.cpp" "*.hpp"
   do
       for i in $h
       do
           if [ "$h" != "$i" ]
           then
               m=`/bin/tempfile -d /tmp/ -p postcommit`
               fgrep "#include \"" $i | grep [\/\\] | sed s#\\\\#\/#g > $m
               a=`cat $m`
               rm -f $m
               if [ "$a" != "" ]
               then
                   for j in $a
                   do
                       if [ "$j" != "#include" ]
                       then
                           d=`echo $j | cut -d "\"" -f2`
                           b=`basename $d`
                           d=`echo $d | sed s/$b//`
                           l=`echo $d | cut -d "/" -f2`
                           k=`svn info file:///caminho/do/repositório/trunk/$l 2>/dev/null | grep "Changed Rev:" | cut -d " " -f4`
                           if [ "$k" != "" ]
                           then
                               echo " * \""$i"\"" depende do projeto "\""`echo $j | cut -d "/" -f2`"\", que está na versão " $k >> depend.c
                           else
                               echo " * \""$i"\"" depende do projeto "\""`echo $j | cut -d "/" -f2`"\", <b>que não está no repositório! </b>" >> depend.c
                           fi
                           echo " *" >> depend.c
                       fi
                   done
               fi
           fi
       done
   done
   echo -e " */\n">> depend.c

#fim do código de verificação e documentação de dependências

   if [ -f Doxyfile ]
   then
       /bin/rm -f Doxyfile
   fi

   /bin/cat /caminho/do/arquivo/padrão/Doxyfile.post_commit | /bin/sed -e s/ProjectName/$t/ -e "s%/post_commit_dir/%"`/bin/pwd`/"%" > ./Doxyfile

   /usr/bin/doxygen > /dev/null 2> /dev/null

   cd doc
   if [ -d html ]
   then
       if [ -d /var/www/localhost/htdocs/docs/$t ]
       then
       /bin/rm -fR /var/www/localhost/htdocs/docs/$t
       fi

           /bin/mkdir /var/www/localhost/htdocs/docs/$t

       cd html
       /bin/mv * /var/www/localhost/htdocs/docs/$t/
       cd ..
   fi

   cd latex

   /usr/bin/pdflatex refman.tex > /dev/null 2> /dev/null
   /usr/bin/makeindex refman.idx > /dev/null 2> /dev/null
   /usr/bin/pdflatex refman.tex > /dev/null 2> /dev/null

   latex_count=5

   E=0

   while [ $E == 0 ]
   do
       /usr/bin/pdflatex refman.tex > /dev/null 2> /dev/null
       /bin/egrep -s 'Rerun (LaTeX|to get cross-references right)' refman.log
       E=$?
       if [ $E == 0 ]
       then
           latex_count=`expr $$latex_count - 1`
           if [ $latex_count == 0 ]
           then
               E=1
           fi
       fi
   done

   /bin/cp refman.pdf ../..
   /bin/mv refman.pdf /caminho/da/pasta/de/documentação/"$t"_"$2"_refman.pdf

   cd ../..

   /usr/sbin/sendmail -f admin@srv.com.br -r admin@srv.com.br $n << EOF
Bcc: Administrador <admin@srv.com.br>
Subject: Projeto $1 na v$2 .
From: "root @ desenv" <admin@srv.com.br>
To: $u <$n>
Reply-to: "root @ serv" <admin@srv.com.br>
X-Mailer: postfix in $HOSTNAME

Seu projeto $1 foi efetivado no repositorio na v$2 .

Os documentos podem ser encontrados em:

http://desenv/docs/$t

O PDF se encontra na pasta "caminho da pasta de documentação" deste servidor e anexo a esta mensagem.


—
servidor "desenv"

`uuencode $f $f`

EOF

   cd ..
fi

/bin/rm -fR $d

arquivo Doxyfile.post_commit

PROJECT_NAME           = ProjectName
PROJECT_NUMBER         =
OUTPUT_DIRECTORY       = ./doc
CREATE_SUBDIRS         = NO
OUTPUT_LANGUAGE        = Brazilian
USE_WINDOWS_ENCODING   = YES
BRIEF_MEMBER_DESC      = YES
REPEAT_BRIEF           = YES
ABBREVIATE_BRIEF       =
ALWAYS_DETAILED_SEC    = YES
INLINE_INHERITED_MEMB  = YES
FULL_PATH_NAMES        = YES
STRIP_FROM_PATH        = /post_commit_dir/
STRIP_FROM_INC_PATH    =
SHORT_NAMES            = NO
JAVADOC_AUTOBRIEF      = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP         = YES
INHERIT_DOCS           = YES
DISTRIBUTE_GROUP_DOC   = NO
SEPARATE_MEMBER_PAGES  = NO
TAB_SIZE               = 4
ALIASES                =
OPTIMIZE_OUTPUT_FOR_C  = NO
OPTIMIZE_OUTPUT_JAVA   = NO
SUBGROUPING            = YES
EXTRACT_ALL            = YES
EXTRACT_PRIVATE        = YES
EXTRACT_STATIC         = YES
EXTRACT_LOCAL_CLASSES  = YES
EXTRACT_LOCAL_METHODS  = YES
HIDE_UNDOC_MEMBERS     = NO
HIDE_UNDOC_CLASSES     = NO
HIDE_FRIEND_COMPOUNDS  = NO
HIDE_IN_BODY_DOCS      = NO
INTERNAL_DOCS          = YES
CASE_SENSE_NAMES       = YES
HIDE_SCOPE_NAMES       = NO
SHOW_INCLUDE_FILES     = YES
INLINE_INFO            = YES
SORT_MEMBER_DOCS       = YES
SORT_BRIEF_DOCS        = YES
SORT_BY_SCOPE_NAME     = YES
GENERATE_TODOLIST      = YES
GENERATE_TESTLIST      = YES
GENERATE_BUGLIST       = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS       =
MAX_INITIALIZER_LINES  = 30
SHOW_USED_FILES        = YES
SHOW_DIRECTORIES       = YES
FILE_VERSION_FILTER    = "/caminho/auxiliares/versionfilter.sh"
QUIET                  = YES
WARNINGS               = YES
WARN_IF_UNDOCUMENTED   = YES
WARN_IF_DOC_ERROR      = YES
WARN_NO_PARAMDOC       = YES
WARN_FORMAT            = "$file:$line: $text"
WARN_LOGFILE           =
INPUT                  =
FILE_PATTERNS          = *.c \
RECURSIVE              = YES
EXCLUDE                = .* */teste/*
EXCLUDE_SYMLINKS       = NO
EXCLUDE_PATTERNS       =
EXAMPLE_PATH           =
EXAMPLE_PATTERNS       =
EXAMPLE_RECURSIVE      = NO
IMAGE_PATH             =
INPUT_FILTER           =
FILTER_PATTERNS        = *.c="/caminho/auxiliares/beautyfier.sh"        \
                        *.h="/caminho/auxiliares/beautyfier.sh"        \
                        *.cpp="/caminho/auxiliares/beautyfier.sh"      \
                        *.hpp="/caminho/auxiliares/beautyfier.sh"      \
                        *.c++="/caminho/auxiliares/beautyfier.sh"      \
                        *.h++="/caminho/auxiliares/beautyfier.sh"
FILTER_SOURCE_FILES    = NO
SOURCE_BROWSER         = YES
INLINE_SOURCES         = YES
STRIP_CODE_COMMENTS    = YES
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION    = YES
VERBATIM_HEADERS       = YES
ALPHABETICAL_INDEX     = YES
COLS_IN_ALPHA_INDEX    = 5
IGNORE_PREFIX          =
GENERATE_HTML          = YES
HTML_OUTPUT            = html
HTML_FILE_EXTENSION    = .html
HTML_HEADER            =
HTML_FOOTER            =
HTML_STYLESHEET        =
HTML_ALIGN_MEMBERS     = YES
GENERATE_HTMLHELP      = NO
CHM_FILE               =
HHC_LOCATION           =
GENERATE_CHI           = NO
BINARY_TOC             = NO
TOC_EXPAND             = NO
DISABLE_INDEX          = NO
ENUM_VALUES_PER_LINE   = 4
GENERATE_TREEVIEW      = YES
TREEVIEW_WIDTH         = 250
GENERATE_LATEX         = YES
LATEX_OUTPUT           = latex
LATEX_CMD_NAME         = latex
MAKEINDEX_CMD_NAME     = makeindex
COMPACT_LATEX          = YES
PAPER_TYPE             = a4wide
EXTRA_PACKAGES         =
LATEX_HEADER           =
PDF_HYPERLINKS         = YES
USE_PDFLATEX           = YES
LATEX_BATCHMODE        = YES
LATEX_HIDE_INDICES     = NO
GENERATE_RTF           = NO
RTF_OUTPUT             =
COMPACT_RTF            = YES
RTF_HYPERLINKS         = YES
RTF_STYLESHEET_FILE    =
RTF_EXTENSIONS_FILE    =
GENERATE_MAN           = NO
MAN_OUTPUT             = man
MAN_EXTENSION          = .3
MAN_LINKS              = NO
GENERATE_XML           = NO
XML_OUTPUT             = xml
XML_SCHEMA             =
XML_DTD                =
XML_PROGRAMLISTING     = YES
GENERATE_AUTOGEN_DEF   = NO
GENERATE_PERLMOD       = NO
PERLMOD_LATEX          = NO
PERLMOD_PRETTY         = YES
PERLMOD_MAKEVAR_PREFIX =
ENABLE_PREPROCESSING   = YES
MACRO_EXPANSION        = YES
EXPAND_ONLY_PREDEF     = NO
SEARCH_INCLUDES        = YES
INCLUDE_PATH           =
INCLUDE_FILE_PATTERNS  =
PREDEFINED             =
EXPAND_AS_DEFINED      =
SKIP_FUNCTION_MACROS   = YES
TAGFILES               =
GENERATE_TAGFILE       =
ALLEXTERNALS           = NO
EXTERNAL_GROUPS        = YES
PERL_PATH              = /usr/bin/perl
CLASS_DIAGRAMS         = YES
HIDE_UNDOC_RELATIONS   = YES
HAVE_DOT               = YES
CLASS_GRAPH            = YES
COLLABORATION_GRAPH    = YES
GROUP_GRAPHS           = YES
UML_LOOK               = YES
TEMPLATE_RELATIONS     = YES
INCLUDE_GRAPH          = YES
INCLUDED_BY_GRAPH      = YES
CALL_GRAPH             = YES
GRAPHICAL_HIERARCHY    = YES
DIRECTORY_GRAPH        = YES
DOT_IMAGE_FORMAT       = png
DOT_PATH               =
DOTFILE_DIRS           =
MAX_DOT_GRAPH_WIDTH    = 1024
MAX_DOT_GRAPH_HEIGHT   = 1024
MAX_DOT_GRAPH_DEPTH    = 0
DOT_TRANSPARENT        = NO
DOT_MULTI_TARGETS      = YES
GENERATE_LEGEND        = YES
DOT_CLEANUP            = YES
SEARCHENGINE           = YES

arquivo versionfilter.sh

#!/bin/sh
PTH=`pwd`
if [ -d CVS ] ; then
       cvs status `echo $1 | sed s%$PTH\/%%` | sed -n 's/^[ \]*Working revision:[ \t]*\([0-9][0-9\.]*\).*/\1/p'
elif [ -d .svn ] ; then
       svn stat -v `echo $1 | sed s%$PTH\/%%` | sed -n 's/^[ A-Z?\*|!]\{1,15\}/r/;s/ \{1,15\}/\/r/;s/ .*//p'
       #F=`echo $1 | sed s%$PTH\/%%`
       #E=`svn stat -v $F | sed -n 's/^[ A-Z?\*|!]\{1,15\}/r/;s/ \{1,15\}/\/r/;s/ .*//p'`
fi

arquivo beautyfier.sh

#!/bin/sh
/usr/bin/astyle --break-blocks --min-conditional-indent=0 --style=linux -CSKNPT4 $1
rm $1.orig
cat $1

Agora chega ;)



Veja a relação completa dos artigos de Francisco José Alonso Ares