Este artigo demonstra o processo de criação de releases de projeto, utilizando a ferramenta Ant. Os arquivos gerados da release são o html/css/js/php, necessários para enviar ao cliente, destacando que os arquivos js e css são concatenados e compactados em um único arquivo. O objetivo deste artigo é que através de um simples comando ant a release seja gerada e possa ser enviada para o cliente.

De acordo com a Apache, “A Apache Ant é uma biblioteca Java e uma ferramenta de linha de comando, cuja missão é conduzir os processos descritos na construção de arquivos como alvos e pontos de extensão, que dependem uns dos outros. Ant fornece uma série de tarefas internas que permitem compilar, montar, testar e executar aplicativos”. Essa ferramenta é um software livre, projetado e licenciado pela “Apache Software Foundation.

Instalação do Apache Ant

Para a instalação da ferramenta Ant deve ser realizado o download do arquivo correspondente, compactado, nesse site.

Com o download completo, o arquivo rar deve ser copiado para o diretório de sua preferencia e descompactado. A Figura 1 apresenta o exemplo de caminho que foi realizado a descompactação do arquivo (D:\ant).

Apache Ant
Figura 1. Apache Ant

Com o Ant descompactado, deve ser criada uma variável de ambiente apontando para o caminho de localização do Ant, como exemplificado na Figura 2.

Variável de Ambiente Ant
Figura 2. Variável de Ambiente Ant

A pasta Bin deve ser acrescentada ao PATH de comandos do sistema operacional (D:\>SET PATH=%PATH%;%ANT_HOME%\bin) conforme ilustrado na Figura 3.

Pasta Bin ao Path de comandos do Sistema Operacional
Figura 3. Pasta Bin ao Path de comandos do Sistema Operacional

A verificação de configuração do Ant é possível pela execução do comando ant, exemplificado na Figura 4.

Comando Ant
Figura 4. Comando Ant

O comando de verificação direciona o usuário a uma mensagem informativa, de sucesso ou não, como Figura 5.

Ant configurado com Sucesso
Figura 5. Ant configurado com Sucesso

A mensagem apresentada na Figura 5 ilustra a configuração bem sucedida.

Entendendo o projeto ant-build-xml

Com o Ant configurado corretamente é possível iniciar o processo de geração de releases para liberar para o cliente. O projeto “ant-build-xml”, apresenta na Figura 6, pode ser encontrado no Github.

Projeto ant-build-xml
Figura 6. Projeto "ant-build-xml"

O projeto está divido em build-xml, projeto-exemplo, release-liberacao. Na pasta build-xml (Figura 7) encontra-se os arquivos utilizados pela ferramenta Ant.

Pasta build-xml
Figura 7. Pasta build-xml

A Figura 8 apresenta o projeto-exemplo que será utilizado de base para geração de releases.

Projeto exemplo utilizado para geração das releases
Figura 8. "projeto-exemplo" utilizado para geração das releases

Na Figura 8, dentro da pasta app se encontra arquivos php, utilizados no projeto. Já na pasta css os arquivos css, seguindo da mesma forma para as demais pastas.

A Figura 9 apresenta release-liberacao, um exemplo de releases geradas, que devem ser enviadas para o cliente.

Releases liberação
Figura 9. Releases liberação

A release enviada para o cliente (Figura 9), é considerada a versão 0.0.4. no exemplo.

Entendendo a pasta build-xml

O Ant trabalha com arquivos “XML”, denominados buildfiles, estes são interpretados pelo Ant, para que o mesmo possa executar as tarefas que estão descritas.

Dentro da pasta build-xml deve ser criada a pasta templates, que conterá arquivos padrões do projeto, também a pasta yui com o arquivo “jar”, responsável por compactar arquivos js e css e um arquivo build.xml, conforme Figura 10.

Pasta build-xml
Figura 10. Pasta "build-xml"

Na pasta templates -> js esta o arquivo loader.js, desenvolvido por terceiros, arquivo responsável por inserir os js e css desenvolvidos na página.

O arquivo yuicompressor-2.4.2.jar responsável por compactar os arquivos js e css do projeto se encontra na pasta yui - clique aqui para maiores informações do yuicompressor.

Criação do arquivo build.xml

O arquivo build.xml é o arquivo que será interpretado pelo Ant, neste arquivo irá conter as operações necessárias para geração do “deploy” do projeto.

Configurações Iniciais

Todo build.xml deve iniciar com a tag project, representando o escopo de inicio e fim do projeto, cada “buildfile” só deve conter uma tag “project”. A Listagem 1 apresenta os primeiro passos para criação do build.xml do projeto proposto ant-build-xml.


<?xml version="1.0" encoding="UTF-8"?>
<project name="${project.name}" basedir="." default="deploy" >
	<!-- projeto ant-build-xml -->
</project>
Listagem 1. Inicio arquivo “build.xml”

Na tag project (Listagem 1), o atributo name é setado a variável project.name, a qual está valorizada com o nome do projeto. O atributo basedir ter a função de informar a localização do diretório base, no caso “.” - referência ao diretório que o build.xml está localizado. O atributo default informa para o Ant qual o primeiro procedimento que deve ser executado ao iniciar o deploy.

A Listagem 2 apresenta a configuração inicial do projeto, definindo o nome do projeto como project.name, versão da aplicação que será gerada a release project.vs e a pasta que será enviada a release project.folder.save.

A tag property no Ant deve conter nome e valor, no exemplo foi utilizado para declarar as variáveis.


<?xml version="1.0" encoding="UTF-8"?>
<project name="${project.name}" basedir="." default="deploy" >

    <!-- projeto ant-build-xml -->

    <!-- configurações da aplicacação -->
    <property name="project.name"        value="projeto-teste" />   
    <property name="project.vs"          value="vs.0.0.4" />    
    <property name="project.folder.save" value="release-liberacao" />   
    
    <!-- Diretório para o deploy -->
    <property name="dir.deploy" value="${basedir}/../deploy/" 
        description="diretório do deploy" />   
    
    <!-- YUICompressor -->
    <property name="YUI" value="${basedir}/yui/yuicompressor-2.4.2.jar" 
        description="YUICompressor" /> 

    <!-- Diretório dos templates -->
    <property name="dir.templates" value="${basedir}/templates/" />
    <property name="dir.templates.js" value="${dir.templates}/js/" />
    <property name="js.loader" value="loader.js" />    

</project>
Listagem 2. Configuração da aplicação pelo build.xml

Ainda na Listagem 2, foi definido o diretório que será gerado a release dir.deploy. No projeto ant-build-xml o diretório “deploy” é criado, zipado em um arquivo, enviado para a pasta de liberação release-liberacao e para então ser excluído este diretório.

A property YUI“ especifica o caminho do yuicompressor, responsável por compactar os arquivos js e css.

A property dir.templates dir.templates.js e js.loader especifica para o Ant o caminho do arquivos padrões do projeto, neste caso apenas utiliza-se o js loader como arquivo padrão, poderia ser por exemplo, um arquivo php com a conexão padrão do cliente. A vantagem de se utilizar “templates” padrões é que depois da geração da release não haverá a necessidade de alteração de algum arquivo.

Continuando com o desenvolvimento do deploy.xml, deve ser especificado para o Ant quais os arquivos são necessários para envio ao cliente, como apresenta a Listagem 3.


<!-- Index da Aplicação -->
<property name="dir.deploy.index.php" value="${dir.deploy}/index.php" />    
<property name="dir.base.index.php" value="${basedir}/../projeto-exemplo/index.php" />  

<!-- Localização das pastas padrões do projeto -->
<property name="dir.deploy.img" value="${dir.deploy}/img" />    
<property name="dir.base.img" value="${basedir}/../projeto-exemplo/img" />  

<property name="dir.deploy.css" value="${dir.deploy}/css" />    
<property name="dir.base.css" value="${basedir}/../projeto-exemplo/css" />  

<property name="dir.deploy.js"  value="${dir.deploy}/js"  />    
<property name="dir.base.js"  value="${basedir}/../projeto-exemplo/js"  />  

<property name="dir.deploy.app" value="${dir.deploy}/app" />    
<property name="dir.base.app" value="${basedir}/../projeto-exemplo/app" />
Listagem 3. Configuração dos arquivos necessários para Envio

Na Listagem 3, os arquivos necessários para geração da release são, a pasta img, css, js, app e o arquivo index.php. As demais pastas do “projeto-exemplo” como, “releases e scripts” não são necessárias para release, são apenas utilizadas pelo desenvolvedor.

Criação da Release

A primeira etapa do arquivo build.xml, responsável pela configuração do projeto exemplo, foi finalizada com sucesso, sendo iniciado o processo de criação do projeto, com o envio das pastas e arquivos para release, concatenação e também a tarefa de comprimir os arquivos js e css e gerar a release no formato zip.

A Listagem 4 apresenta o primeiro método que o Ant ira executar, o qual é responsável por chamar as dependências do projeto para geração da release.


<!-- Iniciando o deploy -->
<echo>Iniciando deploy do projeto ${project.name}</echo>
<target name="deploy"
    description="realiza o deploy da aplicação"   
    depends="index, img, css, js, app, zip" >
    
    <echo>Deploy finalizado em ${dir.deploy}</echo>
</target> 
Listagem 4. Inicio do deploy do projeto

A tag “target” é utilizada para executar suas tarefas e suas dependências.

Na Listagem 5 são apresentadas as “targets”, responsáveis por copiar o arquivo index.php e diretório img, app para a pasta do deploy.


<target name="index" depends="clean"
    description="copia o arquivo index.php" >
    
    <echo>Copiando o arquivo index.php</echo>
    <copy file="${dir.base.index.php}"
        tofile="${dir.deploy.index.php}" 
        overwrite="true" />     
</target>   

<target name="img"
    description="copiando os arquivos da pasta img e enviado 
    para a pasta de deploy do projeto">
    
    <echo>Copiando os arquivos da pasta ${dir.base.img} 
    para ${dir.deploy.img}</echo>
    <mkdir dir="${dir.deploy.img}" />

    <copy todir="${dir.deploy.img}">
        <fileset dir="${dir.base.img}" />
    </copy>
</target>   

<target name="app"
    description="copiando os arquivos da pasta app e 
    enviado para a pasta de deploy do projeto">
    
    <echo>Copiando os arquivos da pasta ${dir.deploy.app}</echo>
    <mkdir dir="${dir.deploy.app}" />

    <copy todir="${dir.deploy.app}" >
        <fileset dir="${dir.base.app}" />
    </copy>
</target>
Listagem 5. Target index, img e app

A target img e app são semelhantes, a única diferença é o diretório que será copiado para a pasta deploy.

A Listagem 6 mostra a semelhança entre as targets js e css, onde a única diferença é que a target js é responsável por mover o arquivo loader.js.


<target name="js.copyright" 
    description="criando o copyright js">

    <echo>criando o copyright js</echo>
    <echo message="/* copyright ejs */${line.separator}" 
    file="${dir.deploy.js}/copyright.txt"/>
</target>   

<target name="js.move" depends="js.copyright"
    description="movendo os arquivos da pasta js para a pasta de deploy 
    do projeto e adicionando o copyright nos arquivos">

    <echo>Movendo os arquivos da pasta ${dir.deploy.js} para ${dir.base.js}</echo>
    <copy todir="${dir.deploy.js}" >
        <fileset dir="${dir.base.js}" />
        <filterchain>
            <concatfilter prepend="${dir.deploy.js}/copyright.txt"/>
        </filterchain>
    </copy>
</target>   

<target name="js.compact" depends="js.move" 
    description="concatena os js em um unico arquivo" >
    
    <echo>Construindo o compact js</echo>
    <concat destfile="${dir.deploy.js}/system/compact.js">
        <fileset dir="${dir.deploy.js}/system/" includes="*.js" />
    </concat>
    <echo>Operação de compactação do js realizada</echo>
</target>       

<target name="js.min" depends="js.compact" 
    description="minimiza os arquivos js" >
    
    <echo>Construindo o js.min</echo>
    <apply executable="java" parallel="false" verbose="true" 
        dest="${dir.deploy.js}/system">
        
        <fileset dir="${dir.deploy.js}/system" >
            <include name="compact.js" />
        </fileset>
        <arg line="-jar" />
        <arg path="${YUI}" />
        <arg value="--charset" />
        <arg value="UTF-8" />
        <arg value="-o" />
        <targetfile />
        <mapper type="glob" from="compact.js" to="compact-min.js" />
    </apply>
    <echo>Operação js.min realizada</echo>
</target>   

<target name="js.loader" depends="js.min" 
    description="movendo arquivo js template para a pasta de deploy" >

    <echo>Movendo arquivo js template para a pasta ${dir.deploy.js}</echo>
    <copy todir="${dir.deploy.js}/others" overwrite="true" >
        <fileset dir="${basedir}/templates/js/" />
    </copy>
</target>   

<target name="js" depends="js.loader" 
    description="excluir arquivos js não utilizados" >
    
    <echo>Excluindo arquivos js não utilizados</echo>
    <delete includeemptydirs="true">
        <fileset dir="${dir.deploy.js}/system">
            <include name="*.js"/>
            <exclude name="compact-min.js"/>
        </fileset>
    </delete>   
</target>  
Listagem 6. Target js e css

A Listagem 6 também declara a target js, responsável por excluir os arquivos js não utilizados pela release, destacando que esta target depende da target js.loader.

A target js.loader é responsável por mover o arquivo js template para a pasta do “deploy”, sendo dependente da target js.min, responsável por comprimir o arquivo “js”, deixando o mesmo em apenas uma linha. Salientando que a target js.min depende da target js.compact, a qual é responsável por concatenar todos os arquivos “js” em apenas um arquivo, porém sendo essa dependente da target js.move.

A target js.move, como o próprio nome já sugere, é responsável por enviar todos os arquivos js do sistema para a pasta de deploy, adicionando o conteúdo do arquivo txt copyright no inicio dos arquivos do projeto.

A Listagem 7 apresenta toda a codificação do arquivo deploy.xml, responsável pela criação da release de liberação.


<?xml version="1.0" encoding="UTF-8"?>
<project name="${project.name}" basedir="." default="deploy" >

    <!-- configurações da aplicacação -->
    <property name="project.name"        value="projeto-teste" />   
    <property name="project.vs"          value="vs.0.0.4" />    
    <property name="project.folder.save" value="release-liberacao" />   
    
    <!-- Diretório para o deploy -->
    <property name="dir.deploy" value="${basedir}/../deploy/" 
        description="diretório do deploy" />   
    
    <!-- YUICompressor -->
    <property name="YUI" value="${basedir}/yui/yuicompressor-2.4.2.jar" 
        description="YUICompressor" />  
        
    <!-- Diretório dos templates -->
    <property name="dir.templates" value="${basedir}/templates/" />
    <property name="dir.templates.js" value="${dir.templates}/js/" />
    <property name="js.loader" value="loader.js" />     

    <!-- Index da Aplicação -->
    <property name="dir.deploy.index.php" value="${dir.deploy}/index.php" />    
    <property name="dir.base.index.php" value="${basedir}/../projeto-exemplo/index.php" />  

    <!-- Localização das pastas padrões do projeto -->
    <property name="dir.deploy.img" value="${dir.deploy}/img" />    
    <property name="dir.base.img" value="${basedir}/../projeto-exemplo/img" />  
    
    <property name="dir.deploy.css" value="${dir.deploy}/css" />    
    <property name="dir.base.css" value="${basedir}/../projeto-exemplo/css" />  

    <property name="dir.deploy.js"  value="${dir.deploy}/js"  />    
    <property name="dir.base.js"  value="${basedir}/../projeto-exemplo/js"  />  

    <property name="dir.deploy.app" value="${dir.deploy}/app" />    
    <property name="dir.base.app" value="${basedir}/../projeto-exemplo/app" />  
    
    <!-- INIT -->
    
    <!-- Iniciando o deploy -->
    <echo>Iniciando deploy do projeto ${project.name}</echo>
    <target name="deploy"
        description="realiza o deploy da aplicação"   
        depends="index, img, css, js, app, zip" >
        
        <echo>Deploy finalizado em ${dir.deploy}</echo>
    </target>   
    
    <target name="index" depends="clean"
        description="copia o arquivo index.php" >
        
        <echo>Copiando o arquivo index.php</echo>
        <copy file="${dir.base.index.php}"
            tofile="${dir.deploy.index.php}" 
            overwrite="true" />     
    </target>   
    
    <target name="img"
        description="copiando os arquivos da pasta img e enviado para a 
        pasta de deploy do projeto">
        
        <echo>Copiando os arquivos da pasta ${dir.base.img} para ${dir.deploy.img}
        </echo>
        <mkdir dir="${dir.deploy.img}" />

        <copy todir="${dir.deploy.img}">
            <fileset dir="${dir.base.img}" />
        </copy>
    </target>       
    
    <target name="css.copyright" 
        description="criando o copyright css">
    
        <echo>criando o copyright css</echo>
        <echo message="/* copyright ecss */${line.separator}" 
        file="${dir.deploy.css}/copyright.txt"/>
    </target>   

    <target name="css.move" depends="css.copyright"
        description="movendo os arquivos da pasta css para a 
        pasta de deploy do projeto e adicionando o copyright nos arquivos">
        
        <echo>Movendo os arquivos da pasta ${dir.deploy.css} 
        para ${dir.base.css}</echo>
        <copy todir="${dir.deploy.css}" >
            <fileset dir="${dir.base.css}" />
            <filterchain>
                <concatfilter prepend="${dir.deploy.css}/copyright.txt"/>
            </filterchain>
        </copy>
    </target>

    <target name="css.compact" depends="css.move" 
        description="concatena os css em um unico arquivo" >
        
        <echo>Construindo o css compactado</echo>
        <concat destfile="${dir.deploy.css}/system/style.css">
            <fileset dir="${dir.base.css}/system/" includes="*.css" />
        </concat>
        <echo>Operação de compactação do css realizada</echo>
    </target>   
    
    <target name="css.min" depends="css.compact" 
        description="minimiza os arquivos css" >
        
        <echo>Construindo o css.min</echo>
        <apply executable="java" parallel="false" verbose="true" 
            dest="${dir.deploy.css}/system">
            
            <fileset dir="${dir.deploy.css}/system" >
                <include name="style.css" />
            </fileset>
            <arg line="-jar" />
            <arg path="${YUI}" />
            <arg value="--charset" />
            <arg value="UTF-8" />
            <arg value="-o" />
            <targetfile />
            <mapper type="glob" from="style.css" to="style-min.css" />
        </apply>
        <echo>Operação css.min realizada</echo>
    </target>   
    
    <target name="css" depends="css.min" 
        description="excluir arquivos css não utilizados" >
        
        <echo>Excluindo arquivos css não utilizados</echo>
        <delete includeemptydirs="true">
            <fileset dir="${dir.deploy.css}/system">
                <include name="*.css"/>
                <exclude name="style-min.css"/>
            </fileset>
        </delete>       
    </target>   

    <target name="js.copyright" 
        description="criando o copyright js">
    
        <echo>criando o copyright js</echo>
        <echo message="/* copyright ejs */${line.separator}" 
        file="${dir.deploy.js}/copyright.txt"/>
    </target>   
    
    <target name="js.move" depends="js.copyright"
        description="movendo os arquivos da pasta js para a pasta de 
        deploy do projeto e adicionando o copyright nos arquivos">
    
        <echo>Movendo os arquivos da pasta ${dir.deploy.js} para ${dir.base.js}
        </echo>
        <copy todir="${dir.deploy.js}" >
            <fileset dir="${dir.base.js}" />
            <filterchain>
                <concatfilter prepend="${dir.deploy.js}/copyright.txt"/>
            </filterchain>
        </copy>
    </target>   

    <target name="js.compact" depends="js.move" 
        description="concatena os js em um unico arquivo" >
        
        <echo>Construindo o compact js</echo>
        <concat destfile="${dir.deploy.js}/system/compact.js">
            <fileset dir="${dir.deploy.js}/system/" includes="*.js" />
        </concat>
        <echo>Operação de compactação do js realizada</echo>
    </target>       
    
    <target name="js.min" depends="js.compact" 
        description="minimiza os arquivos js" >
        
        <echo>Construindo o js.min</echo>
        <apply executable="java" parallel="false" verbose="true" 
            dest="${dir.deploy.js}/system">
            
            <fileset dir="${dir.deploy.js}/system" >
                <include name="compact.js" />
            </fileset>
            <arg line="-jar" />
            <arg path="${YUI}" />
            <arg value="--charset" />
            <arg value="UTF-8" />
            <arg value="-o" />
            <targetfile />
            <mapper type="glob" from="compact.js" to="compact-min.js" />
        </apply>
        <echo>Operação js.min realizada</echo>
    </target>   

    <target name="js.loader" depends="js.min" 
        description="movendo arquivo js template para a pasta de deploy" >
    
        <echo>Movendo arquivo js template para a pasta ${dir.deploy.js}</echo>
        <copy todir="${dir.deploy.js}/others" overwrite="true" >
            <fileset dir="${basedir}/templates/js/" />
        </copy>
    </target>   

    <target name="js" depends="js.loader" 
        description="excluir arquivos js não utilizados" >
        
        <echo>Excluindo arquivos js não utilizados</echo>
        <delete includeemptydirs="true">
            <fileset dir="${dir.deploy.js}/system">
                <include name="*.js"/>
                <exclude name="compact-min.js"/>
            </fileset>
        </delete>   
    </target>   
    
    <target name="app"
        description="copiando os arquivos da pasta app e enviado para a 
        pasta de deploy do projeto">
        
        <echo>Copiando os arquivos da pasta ${dir.deploy.app}</echo>
        <mkdir dir="${dir.deploy.app}" />

        <copy todir="${dir.deploy.app}" >
            <fileset dir="${dir.base.app}" />
        </copy>
    </target>

    <target name="clean" 
        description="recriando diretório de deploy" >
        
        <reset-dir dir="${dir.deploy}" 
            description="recriando diretório de deploy" />     
    </target>       
    
    <macrodef name="reset-dir"
        description="reseta o diretório deploy" >
        
        <attribute name="dir" />
        <sequential>
            <delete dir="@{dir}" />
            <mkdir dir="@{dir}" />
        </sequential>
    </macrodef> 
    
    <target name="zip" 
        description="compacta o projeto em um arquivo ZIP">
        
        <echo>Compactando os arquivos</echo>        
        <zip 
        destfile="${dir.deploy}/../${project.folder.save}/${project.name}.${project.vs}.zip">
            <zipfileset dir="${dir.deploy}" prefix="${project.name}.${project.vs}" />
        </zip>

        <delete dir="${dir.deploy}" />
    </target>
    
</project>
Listagem 7. Arquivo deploy.xml

A Listagem 7 traz a target zip, responsável por zipar a release do projeto, também a target clean, responsável por deletar a pasta “deploy”.

Conclusão

No artigo foi abordada de forma prática e didática a utilização da ferramenta Ant, da comunidade Apache. Apresentando a equipes de desenvolvimento a possibilidade de criação de releases do projeto para disponibilização a clientes na implantação e atualização de produtos.

O projeto desenvolvido para o artigo pode ser visto no GitHub.