Uma Task Ant para guardar a revisão do Subversion
Aqui na Riopro mantemos diversas aplicações baseadas no framework e_RP. O armazenamento da versão atual do framework sempre foi feito manualmente.
Esse tipo de controle, além de estar sujeito a falhas humanas, é chato e repetitivo. Precisávamos armazenar em um arquivo a versão da distribuição, para evitar que a atualização do framework com novas funcionalidades impactasse em aplicações em produção. Fez-se então necessário criar uma task do Ant que armazenasse automaticamente a revisão atual que está sendo compilada. O problema é simples, a solução, nem tanto.
Existem “dois” números de revisão que são armazenados. O primeiro se refere ao último número de revisão do repositório SVN na rede. Esse número não é aconselhável armazenar pois o mesmo pode não ser a revisão atual do cliente que está fazendo a compilação. Por isso, optamos por armazenar a revisão do cliente.
A primeira forma de descobrir a versão atual em uso no cliente foi usando o comando svn info. O mesmo gera um output como esse:
# svn info Caminho: . URL: https://NOME_DO_NOSSO_SERVIDOR/svnweb/APLICACAO/trunk Raiz do Repositório: https://NOME_DO_NOSSO_SERVIDOR/svnweb/APLICACAO UUID do repositório: p8dc4c43-e512-5arp-b8c7-6gh8714a3ssab Revisão: 1947 Tipo de Nó: diretório Agendado: normal Autor da Última Mudança: FULANO Revisão da Última Mudança: 1947 Data da Última Mudança: 2007-09-17 10:27:19 -0300 (Seg, 17 Set 2007)
Poderiamos, então, usando clientes Linux extrair o valor da revisão usando o grep ou simplesmente armazenar essas informações em um arquivo junto com a aplicação (experimente também usar svn info –xml para gerar um output no formato xml). Esse comando é útil, mas dificilmente seria possível utilizarmos ele para os clientes Windows.
Como usamos Java para nossa aplicação e o próprio Ant é Java, decidimos criar uma solução Java-Like e que fosse efetivamente portável. Poderiamos usar o JavaHL ou o JavaSVN (atual svnkit). Como já falamos no artigo Apagando suas senhas do Subclipse, preferimos usar o JavaSVN por ele, diferentemente do JavaHL, não precisar ser compilado em cada máquina.
Fizemos primeiramente uma classe dentro do nosso pacote de distribuição para recuperar a informações do cliente SVN. A classe chamamos de SVNRevisionInfo. Coloquei uma classe exemplo em anexo para facilitar a compreensão:
O mais importante é o método createRevisionInfoFile(). Esse método irá gravar as informações que desejamos em um arquivo revision.properties no diretório base do cliente SVN.
Isso forneceu a base para a nossa Ant Task (não se preocupe que ao final colocaremos um arquivo build.xml de exemplo com a Task completa). Criamos, então a Task revision:
<target name="revision" description="Cria o arquivo de revisao">
<delete file="${basedir}/build/revision.properties"/>
<taskdef name="revisionInfoFile" classname="br.com.riopro.SVNRevisionInfo">
<classpath refid="compile.classpath"/>
<classpath path="${basedir}"/>
</taskdef>
<revisionInfoFile/>
<move file="revision.properties" todir="${basedir}/build/"/>
</target>
Essa Task começa com a sua definição (target). Em seguida usamos o delete para apagar o último arquivo que havíamos criado, no nosso caso o arquivo chamasse revision.properties no diretório build. Por último, criamos uma taskdef revisionInfoFile para chamar nossa classe e chamamos ela na task seguinte. Aqui uma nota importante, a classe é sempre inicializada pelo construtor padrão e chama o método público execute. Ao chamarmos a TaskDef (≶revisionInfoFile/>,) a classe que gera o arquivo revision.properties no diretório base do SVN.
O problema passou a ser informar para a classe SVNRevisionInfo o caminho aonde se encontra o diretório base do cliente. Como o Ant chama o construtor padrão, não podemos passa o parâmetro ${basedir} para a classe. Para isso fizemos um artifício. Criamos um arquivo temporário que cria a armazena o parâmetro e depois excluímos o arquivo. Veja abaixo a Task revision modificada:
<target name="revision" description="Cria o arquivo de revisao">
<touch file="${basedir}/br/com/riopro/revisiontemp.properties"/>
<concat destfile="${basedir}/br/com/riopro/revisiontemp.properties">basedirSVN=${basedir}/</concat>
<replace file="${basedir}/br/com/riopro/revisiontemp.properties" token="\" value="/"/>
<delete file="${basedir}/build/revision.properties"/>
<taskdef name="revisionInfoFile" classname="br.com.riopro.SVNRevisionInfo">
<classpath refid="compile.classpath"/>
<classpath path="${basedir}"/>
</taskdef>
<revisionInfoFile/>
<delete file="${basedir}/br/com/riopro/revisiontemp.properties"/>
<move file="revision.properties" todir="${basedir}/build/"/>
</target>
O arquivo vazio revisiontemp.properties é criado no diretório da classe SVNRevisionInfo quando chamamos a TaskDef touch (os que conhecem SO’s Linux devem se lembrar do comando de mesmo nome e que realiza a mesma tarefa). Em seguida usamos o concat para armazenar no arquivo criado a propriedade baseDirSVN=${basedir}/. Por uma questão de compatibilidade com o Windows, usamos replace para substituir a barra invertida por uma barra comum. Acompanhe a versão final no arquivo de exemplo abaixo:
Essa solução não é perfeita, mas evita muitas configurações e pode ser facilmente adaptada para outros builds. Bom uso…
Links Úteis:


