Apache Ant: como pude te ignorar por tanto tempo???

“Comodismo emburrece”. Sempre repito orgulhosamente esta frase. Nesta semana acabei por perceber que também cai vítima do mesmo. Devido à comodidade que o Netbeans nos oferece no deploy e build de aplicações, acabei por ignorar completamente o motor responsável por esta comodidade: o Apache Ant.

Na realidade, não foi só o comodismo que me privou de aprender a ferramenta: confesso que a preguiça foi o fator fundamental. Toda vez que lia os scripts do Ant (escritos em XML), me lembrava dos meus tempos do make. Além disto, sempre via os scripts do Ant com certo desdém (não sou fã de DSLs baseadas em XML). Mas recentemente topei com um problema: como automatizar o deploy de minhas aplicações utilizando Java Webstart?

Como utilizo o Spring + Hibernate, a quantidade de arquivos no formato JAR que preciso distribuir é significativa. O que implica na necessidade de executar sempre executar as mesmas tarefas:

  • Assinar todos os meus arquivos .jar
  • Criar um arquivo .jnlp
  • Enviar tanto o arquivo .jnlp quanto os arquivos jar assinados para o servidor

O Netbeans está atualmente caminhando para tornar esta tarefa corriqueira, porém enquanto isto ainda não se tornou realidade, eu precisava repetir esta tarefa manualmente (SHAME ON ME!). Posteriormente escrevi um script em Groovy, porém acabei decidindo por me arriscar com o Ant. E o resultado foi maravilhoso!

A opção pelo Ant se deu quando encontrei por acaso na Internet uma biblioteca de tags chamada Orange Volt cujo objetivo era justamente a automatização do processo que listei acima. Basicamente, a utilizo para gerar o arquivo jnlp, porém todo o procedimento anterior é executado usando as tags nativas do próprio Ant.

Bem, visto que já babei o ovo do Ant, convém descrever a criatura. Trata-se de uma ferramenta de build similar ao GNU Make, porém sem os problemas decorrentes desta. Para começar, não é baseada na execução de aplicações instaladas no computador do usuário, mas sim em classes Java, o que torna seus scripts muito mais fácilmente portáveis. Além disto, o fato de usar o XML acabou se mostrando uma alternativa bastante interessante também (e ai eu paguei lingua) em comparação com a sintaxe do Make (qualquer um que já enfrentou problemas com o caractere tab no make sabe do que estou falando).

Instalação

A instalação do Ant é muito simples, e é composta pelos seguintes passos:

  1. Baixar o Ant em seu site oficial: http://ant.apache.org
  2. Descompactar o conteúdo do arquivo zipado em um diretório de sua escolha
  3. Criação de uma variável de ambiente chamada ANT_HOME, cujo valor deve consisistir no diretório no qual o arquivo zipado foi descompactado.
    Sendo assim, se você descompactou o arquivo no diretório C:\Ant, esta variável deverá possuir o valor C:\Ant
  4. Incluir no path do seu sistema o diretório ANT_HOME/bin
  5. Verificar se a variável de ambiente JAVA_HOME está definida no seu sistema.

Executados estes passos, no seu shell digite o comando ant. Se obtiver uma resposta similar a


Buildfile: build.xml does not exist!
Build failed

é sinal de que o ant foi instalado com sucesso.

Usando o Ant

Como mencionei acima, um script de build do Ant consiste em um documento no formato XML tal como no exemplo abaixo:

<pre><project name="meuProjeto" default="dist" basedir=".">
<description>
Um script ant que não serve para nada!
</description>
...
<target name="dist">
<!-- Eu irei fazer alguma coisa -->
</target>
</project></pre>

Este documento no formato xml deve se chamar build.xml. Quando o comando ant é executado, é buscado no diretório corrente a existência deste arquivo (trata-se do comportamento default da ferramenta). Como pode ser visto no exemplo acima, o elemento raiz deste documento se chama project.

Os principais atributos a serem definidos nesta tag são:
name: o nome do projeto
default: o alvo (target) a ser executado por default pelo script caso nenhum seja definido na linha de comando (mais sobre isto adiante)
basedir: o diretório base para a execução do script. No exemplo acima, se trata do diretório corrente.

A tag description é opcional. Serve apenas para fins de documentação.

Em um projeto podem ser definidos mais de um alvo (target). Um target consiste em um conjunto de tarefas a serem executadas pelo script. Tal como no make, você também pode definir interdependências entre as mesmas, tal como no exemplo abaixo:


<project name="projeto" default="distribuir" basedir=".">

<target name="copiar">
...
</target>

<target name="compilar">
...
</target>

<target name="distribuir" depends="compilar, copiar">
...
</target>

</project>

No exemplo acima, o target distribuir que é o default ao ser executado irá antes chamar os alvos compilar e copiar. Convém mencionar no entanto que a ordem de execução não necessáriamente será compilar e copiar. Se houver mais dependências nas tags compilar ou copiar, estas serão executadas antes das mesmas.

É possível também pela linha de comando executar um target específico. Se for executado o comando ant compilar, por exemplo, a tag distribuir (definida como default no exemplo) não será executada.

Tasks

Assim como um projeto é composto por alvos, um alvo é composto por tarefas (tasks). Uma task nada mais é do que um pedaço de código que pode ser executado. Simplificando ainda mais esta descrição, pense em uma task como um comando. A sintaxe de definição de uma task dentro de um target é muito simples:


<nome_da_task atributo1="valor1" atributo2="valor2" ... atributoN="valorN"/>

O Ant já vêm com uma série de tasks pré definidas, cuja lista pode ser acessada neste link.

Para melhor entender o funcionamento das tasks, segue abaixo um exemplo de build file bem simples. No caso, ele irá fazer o backup de um projeto qualquer.


<project name="backup" default="backup" basedir=".">

<property name="diretorioDestino" location="../backup"/>

<target name="backup">

<mkdir dir="${diretorioDestino}"/>
<zip destFile="${diretorioDestino}/backup.zip"
basedir="."/>

</target>

</project>

Ao ser executado, o script irá executar o alvo default (que também é o único no caso): default. As tasks definidas em seu interior serão executadas na ordem em que são definidas.

Sendo assim, primeiro será criado um diretório um nível abaixo do corrente chamado backup (convém mencionar que este diretório somente será criado caso já não exista). Para tal, utilizamos uma propriedade do script de build.

Pense em uma propriedade como se fosse uma variável utilizada pelo script. No caso, a propriedade em questão diz respeito a uma localização no disco rígido do usuário (o que explica o atributo location passado para a mesma).

Utilizamos o valor da propriedade diretorioDestino na task mkdir utilizando uma sintaxe bastante similar à EL com a qual estamos acostumados a trabalhar em arquivos JSP. Basicamente é a seguinte:


<task nome_do_atributo="${nome_da_propriedade}"/>

Em seguida, é executada a task zip. A função desta tag consiste em criar um arquivo no formato zip. No caso, usei apenas dois dos seus atributos: destFile (que indica o nome do arquivo a ser criado) e basedir (que diz qual o diretório raiz que contém os arquivos a serem incluídos no conteúdo compactado).

Dica importante: sempre consulte o manual do Ant online. http://ant.apache.org/manual/index.html

Criando e usando suas próprias tasks

Óbviamente as tasks que acompanham o Ant não irão suprir 100% das suas necessidades. Neste caso, é possível criar as suas próprias tasks. No manual do Ant há um guia muito simples de como fazê-lo: http://ant.apache.org/manual/developlist.html

Criadas as suas tasks, estas deverão ser empacotadas em arquivos jar. Uma vez gerados os seus arquivos jar, basta copiá-los para o diretório ANT_HOME/lib e em seguida utilizá-las em seus projetos do Ant.

Em seguida, para utilizá-las em seus scripts, utilize a task taskdef, tal como no exemplo abaixo:


<code><project name="blabla" basedir="." default="blablaTask">
<taskdef name="mytask" classname="caminho.para.sua.Task" />
...</code>
</project>

Esta task possui apenas dois atributos:
name: o nome que identificará a sua task dentro do seu script
classname: o caminho da classe que contém a sua implementação

Sendo assim, no mesmo exemplo acima a task poderia ser utilizada como


<code><project name="blabla" basedir="." default="blablaTarget">
<taskdef name="mytask" classname="caminho.para.sua.Task" />

<target name="blablaTarget"></code>

<mytask attribute1="algum valor" attribute2="outro valor"/>

</target>

</project>

Lembre-se: tasks só podem existir dentro de targets!

Tasks realmente úteis

Dentre as tasks disponíveis pelo Ant, algumas se mostraram incrívelmente úteis para mim:

signjar: é a tag que utilizo para assinar todos os meus arquivos .jar (e que me ajudou a resolver o problema com o Java Webstart)

jar: gera arquivos .jar

war/ear: Geram respectivamente arquivos .war e .ear (trata-se de uma especialização da tag jar

tar: gera arquivos .tar

zip/unzip: Compacta/descompacta arquivos no formato .zip

patch: executa patchs em arquivos originais

sync: sincroniza arquivos presentes em diretórios diferentes.

Conclusões

  • Comodismo gera ignorância :). Procure sempre que possível pensar FORA de sua IDE favorita.
  • A sintaxe em XML do Ant, apesar de inicialmente gerar resistência é uma mão na roda.
    Mas se você não gostar da sintaxe XML do Ant, pode contar com o GANT também (eu acho lindo como Groovy sempre torna as coisas mais bonitas)
  • Ant é MUITO mais simples do que aparenta em um primeiro momento.
  • Muito cuidado para não ficar viciado no Ant (agora gero scripts do Ant pra basicamente TODAS as minhas tarefas de manutenção em meus computadores (e em alguns momentos apenas por diversão))

Publicado

em

, , ,

por

Tags:

Comentários

Deixe uma resposta

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.