ANT任务 - 多个文件 - 循环

时间:2015-02-24 15:43:18

标签: ant fileset xmltask

我要编写非常复杂的ant任务。我不得不制作单独的构建文件,剩下1个。 共有4个文件:

 buildpackage.bat, buildpackage.xml, buildpackage.txt, structure.xml

buildpackage.bat只是一个调用buildpackage.xml "ant -f buildpackage.xml"的ant文件。那样就好。

buildpackage.txt很简单,并且有逗号分隔的行:

server1,client1
server2,client2
genericserver,client[x]
server[x],client[x]

始终有服务器名称和客户端名称:

  • Server name可以是字母,数字和字母,但长度可变。

  • Client name - 仅限字母。

我需要将这些文件拆分为两个独立的变量:server.nameclient.name

我所做的是:

<loadfile property="buildpackage" srcFile="buildpackage.txt"/>    
<for list="${buildpackage}" param="depl.det" delimiter="${line.separator}">
 <sequential>
  <echo>
   Input:   @{deploy.details}
  </echo>
 </sequential>
</for>

我得到的结果是:

[echo] Input:   server_01,Client_01
[echo] Input:   server_02,Client_02
[echo] Input:   server_03,Client_03
[echo] Input:   clientserver,client_04

我希望server_01为parameter1,client_02为parameter2。

我将按顺序执行其他任务。我将文件从客户端[x]目录复制到服务器[x](这很简单,但如何将该字符串拆分为2个单独的变量?)。

现在是非常复杂的任务。

我也有structure.xml文件。结构是:

 <core>
   <clients>
     <client>
       <name>Client_01</name>
       <branding>brand_01</branding>
       <applications>
         <application>application_01</application>
       </applications>
       <solutions>
         <solution>solution01</solution>
       </solutions>
   </client>
   <client>
     <name>Client_07</name>
     <branding>brand_09</branding>
     <applications>
       <application>application_03</application>
     </applications>
     <solutions>
       <solution>solution01</solution>
       <solution>solution07</solution>
       <solution>solution08</solution>
     </solutions>
   </client>
  <clients>
 <core>

我有很多客户,应用程序,品牌,​​解决方案。每个客户只能有1个应用程序和1个品牌,但有多个解决方案。

根据以前的顺序任务(获取服务器和名称),我必须遍历该xml文件并获取每个匹配的客户端(来自上一个任务)

- branding
- application 
- solutions (multiple or one) 

我可以使用<xmlproperty>读取XML,但我不知道如何顺序执行(迭代)并获取匹配的属性。

我知道这很复杂。摘要是:

  1. 构建脚本启动
  2. 构建脚本从buildpackage.txt中提取数据为client.name和server.name
  3. 构建脚本从步骤2获取${client.name}作为参数并循环遍历structure.xml。它找到匹配的品牌/应用程序/解决方案,并为每个匹配的客户输出它。
  4. 输出:

    server.name
    client.name
    branding.name
    application name
    solution [X]
    solution [y]
    

    必须为每个服务器/客户端处理Ant。如果我有属性,我可以完成构建的其余部分并进行编译。我无法触摸structure.xml。我可以做我需要/想要buildpackage.cml和buildpackge.txt的所有内容。 Buildpackage.txt可以替换为.xml文件或任何文件(例如.properties)。它必须包含那两个值服务器和客户端。

    感谢您的帮助。

    修改

    现在我遇到了问题。 如果我将相同的应用程序2x放入构建文件中,则只构建第一个。 这是我的build.xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project name="DoTheJob" basedir="." xmlns:ac="antlib:net.sf.antcontrib" xmlns:if="ant:if" xmlns:unless="ant:unless">
        <!-- Define classpath and default locations-->
        <property name="root.dir" location="../.."/>
        <property name="dest.dir" location="packages"/>
        <property name="ant.lib.dir" location="../lib"/>
        <property name="repository_url" value="http://repository-url"/> 
        <path id="project.classpath">
            <fileset dir="${ant.lib.dir}">
            <include name="*.jar"/>
            </fileset>
            <fileset dir="${root.dir}/IIT/lib">
                <include name="*.jar"/>
            </fileset>
            <pathelement location="../savedjar/compiled.jar"/>
        </path>
        <path id="svnant.path">
            <fileset dir="../lib/">
                <include name="svnant.jar"/>
                <include name="svnClientAdapter.jar"/>
            </fileset>
        </path>
        <typedef resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="svnant.path" /> 
        <tstamp>
            <format property="build_time" pattern="YYYY MMMM dd HH:mm:ss"/>
        </tstamp>   
        <!-- Change characters to lowercase -->
        <scriptdef language="javascript" name="lowercase">
            <attribute name="string" />
            <attribute name="to" />
            project.setProperty(attributes.get("to"),attributes.get("string").toLowerCase());
        </scriptdef>
        <!-- Import XMLTask for XML transformations-->
        <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpathref="project.classpath"/>
        <!-- Define buildfiles locations-->
        <property name="structure.file" location="../structure.xml"/>
        <property name="buildpackage.file" location="buildpackage.txt"/>
        <!-- load client/server file-->
        <property file="${buildpackage.file}"/>
        <!-- loop over all clients --> 
        <xmltask source="${structure.file}">
        <call path="//client">
            <param path="name/text()" name="client"/>
            <param path="branding/text()" name="branding"/>
            <param path="applications/application/text()" name="application"/>
                <actions>
                    <!-- loop through all XML properties only when @{client} condition is matched --> 
                    <ac:if>
                        <isset property="@{client}"/>
                        <then>
                            <echo>=====================================================</echo>
                            <echo>Building package for @{client} on ${@{client}}       </echo>
                            <echo>=====================================================</echo>
                            <!-- creating destination directories -->                           
                            <delete dir="${build.dir}/@{client}"/>
                            <mkdir dir="${dest.dir}/@{client}"/> 
                            <echo>=====================================================</echo>
                            <echo>Copy application files code/temaplates to destination</echo>
                            <echo>=====================================================</echo>                      
                            <!-- creating code build directory -->
                            <mkdir dir="${dest.dir}/@{client}/code"/> 
                            <!-- copy application code --> 
                            <echo>copy application code</echo>
                            <copy todir="${dest.dir}/@{client}/code/application/@{application}" overwrite="yes">
                                <fileset dir="${root.dir}/client-source/application/@{application}" includes="**/*.*"/>
                            </copy>
                            <!-- copy application templates --> 
                            <mkdir dir="${dest.dir}/@{client}/app/@{client}"/> 
                            <echo>copy application templates</echo>
                            <copy todir="${dest.dir}/@{client}/app/@{client}" overwrite="yes">
                                <fileset dir="${root.dir}/applications/apps/@{application}" includes="**/*.*"/>
                            </copy>
                            <echo>===================================================</echo>
                            <echo>copy Solutions files code/temaplates to destination</echo>
                            <echo>===================================================</echo>    
                            <!-- nested xmltask for loop over solutions -->
                            <xmltask source="${structure.file}">
                                <call path="/core/clients/client[name/text()='@{client}']/*/solution">
                                    <param path="text()" name="solution"/>
                                        <actions>
                                            <!-- making sure that solution is lowercase -->
                                            <lowercase string="@{solution}" to="solution.lowercase" />
                                            <echo>copy solutions code</echo>
                                            <!-- copy solutions code -->
                                            <copy todir="${dest.dir}/@{client}/code/solutions/${solution.lowercase}" overwrite="yes">
                                                <fileset dir="${root.dir}/client-source/solutions/${solution.lowercase}" includes="**/*.*"/>
                                            </copy>
                                            <!-- copy solutions templates -->
                                            <echo>copy Solutions templates</echo>
                                            <copy todir="${dest.dir}/@{client}/app/@{client}" overwrite="yes">
                                                <fileset dir="${root.dir}/applications/solutions/${solution.lowercase}" includes="**/*.*"/>
                                            </copy>
                                        </actions>
                                </call>
                            </xmltask>
                            <echo>==============================================</echo>
                            <echo>copy Client files code/temaplates to destination</echo>
                            <echo>==============================================</echo> 
                            <!-- copy branding directory --> 
                            <copy todir="${dest.dir}/@{client}/app/@{client}" overwrite="yes">
                                <fileset dir="${root.dir}/applications/brandings/@{branding}" includes="**/*.*"/>
                            </copy>                         
                            <!-- copy client code --> 
                            <copy todir="${dest.dir}/@{client}/code/client/@{client}" overwrite="yes">
                                <fileset dir="${root.dir}/client-source/client/@{client}" includes="**/*.*"/>
                            </copy>                         
                            <!-- set templates directory --> 
                            <copy todir="${dest.dir}/@{client}/app/@{client}" overwrite="yes">
                                <fileset dir="${root.dir}/applications/clients/@{client}" includes="**/*.*"/>
                            </copy>         
                            <echo>==============================================</echo>
                            <echo>compiling code                                </echo>
                            <echo>==============================================</echo> 
                            <!-- making classes directory --> 
                            <mkdir dir="${dest.dir}/@{client}/classes"/>
                            <javac destdir="${dest.dir}/@{client}/classes" classpathref="project.classpath" debug="on" fork="true" includeantruntime="false" memoryinitialsize="256m" memorymaximumsize="1024m">
                                <src path="${dest.dir}/@{client}/code/"/>
                            </javac>
                            <echo>==============================================</echo>
                            <echo>creating Client.jar                           </echo>
                            <echo>==============================================</echo> 
                            <!-- jar classes directory --> 
                            <jar jarfile="${dest.dir}/@{client}/app/Client.jar" basedir="${dest.dir}/@{client}/classes"/>
                            <!-- reaplce text in files --> 
                            <replaceregexp byline="true">
                                <regexp pattern="@ReleaseDate@"/>
                                <substitution expression="${build_time}"/>
                                <fileset dir="${dest.dir}/@{client}/app/@{client}/templates/">
                                    <include name="*.htm"/>
                                    <include name="*.html"/>            
                                    <include name="*.ini"/>
                                </fileset>
                            </replaceregexp>
                            <!-- get svn info --> 
                            <svn username="********" password="************" javahl="false" svnkit="false">
                                <info target="${repository_url}" />
                            </svn>
                            <!-- creating Client.ini file --> 
                            <touch file="${dest.dir}/@{client}/app/Client.ini"/>
                            <concat destfile="${dest.dir}/@{client}/app/Client.ini" append="true">releaseDate=${build_time}${line.separator}</concat>
                            <concat destfile="${dest.dir}/@{client}/app/Client.ini" append="true">svnrevision=${svn.info.lastRev}${line.separator}</concat>
                            <!-- ziping package --> 
                            <zip destfile="${dest.dir}/@{client}/@{client}.zip" basedir="${dest.dir}/@{client}/app/" />
                            <echo>==============================================</echo>
                            <echo>sending @{client}.zip to the server via scp      </echo>
                            <echo>==============================================</echo> 
                            <!-- scp file to remote server -->
                            <property name="scp_username" value="**********"/>
                            <property name="scp_password" value="**********"/>
                            <property name="scp_server" value="${@{client}}"/>
                            <property name="scp_remote_directory" value="*********"/>
                            <scp trust="true" verbose="true" localFile="${dest.dir}/@{client}/@{client}.zip" remoteTodir="${scp_username}:${scp_password}@${scp_server}:${scp_remote_directory}"/>  
                            <echo>${line.separator}${line.separator}${line.separator}</echo>
                        </then>
                    </ac:if> 
                </actions>
            </call>
        </xmltask>
    </project>
    

    如果我尝试构建buildpackage.txt文件

    client1=server1
    client2=server1
    client1=server2
    

    我知道了 client1-&gt; server1,client2-&gt; server1但......没有客户端1到server2

    EDIT2

    全部修复。 scp任务的解决方案是:

           <!-- scp file to remote server -->
            <property name="scp_username" value="XXX"/>
            <property name="scp_password" value="YYY"/>
            <property name="scp_remote_directory" value="path"/>
            <for list="${@{client}}" delimiter="=" param = "val">
                <sequential>
                <property name="token" value="@"/>
                <scp trust="true" verbose="true" localFile="${dest.dir}/@{client}/@{client}.zip" remoteTodir="${scp_username}:${scp_password}${token}@@{val}:${scp_remote_directory}"/> 
            </sequential>
            </for>
    

    一切正常。 谢谢你的帮助

1 个答案:

答案 0 :(得分:1)

对于任何xmldriven构建,我建议使用ant addon xmltask,所以类似于:
(假设buildpackage.txt和structure.xml中的客户端名称相似 - 您的代码段有多个名称Client_01,client1 ..!?)

<project>
 <!-- Import XMLTask -->
 <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>

 <!-- make buildpackage.txt a valid propertyfile to get the job done
      f.e. server1,client1 will get client1=server1 etc. ..
      to make server easily accessible within xml loop
 -->
 <replaceregexp
   file="buildpackage.txt"
   match="(.+),(.+)"
   replace="\2=\1"
   byline="true" />

 <!-- now load that file -->
 <property file="buildpackage.txt"/>

 <!-- loop over all clients --> 
 <xmltask source="structure.xml">
  <call path="//client">
   <param path="name/text()" name="client"/>
   <param path="branding/text()" name="branding"/>
   <param path="applications/application/text()" name="application"/>

   <!-- inside action adress params with @{..} syntax ! -->
   <actions>
    <!-- the copy (or whatever) action
         here demonstrated with echoxml -->
   <echoxml>
    <!-- access the corresponding server (set via buildpackage.txt)
         with nested ${@{..}} syntax ! -->
    <copy todir="//${@{client}}/share">
     <fileset dir="@{client}/somedir"/>
    </copy>
   </echoxml>

   <echo>${@{client}}${line.separator}@{client}${line.separator}@{application}${line.separator}@{branding}</echo>

   <!-- another nested xmltask for loop over solutions -->
   <xmltask source="structure.xml">
    <call path="//client[name/text()='@{client}']/*/solution">
     <param path="text()" name="solution"/>
      <actions>
       <echo>@{solution}${line.separator}</echo>
      </actions>
     </call>
   </xmltask>

   </actions>
  </call>
 </xmltask>
</project>

如果可能,您应该将buildpackage.txt创建为有效的属性文件
格式=&gt;客户端[x] =服务器[x]立即。
然后你需要的只是xmltask。将所有步骤完成到嵌套操作部分,如echoxml / copy所示。

输出:

<?xml version="1.0" encoding="UTF-8"?>
<copy todir="//server1/share">
  <fileset dir="client1/somedir" />
</copy>
     [echo] server1
     [echo] client1
     [echo] application_03
     [echo] brand_01
     [echo] solution01
<?xml version="1.0" encoding="UTF-8"?>
<copy todir="//server4/share">
  <fileset dir="client4/somedir" />
</copy>
     [echo] server4
     [echo] client4
     [echo] application_03
     [echo] brand_09
     [echo] solution01
     [echo] solution07
     [echo] solution08
BUILD SUCCESSFUL

- 关于条件操作的问题后编辑,仅在设置了$ {@ {client}}时

如果propertyfile buildpackage.txt包含错误的属性,则表示server = client而不是client = server,f.e。 :

Sol-e-45-D=PRODUCTION1
CONNECTION=PRODUCTION3
PRODUCTION4=DFHH
PRODUCTION5=MEGA-5

你需要一些if isset逻辑。最好是使用new if/unless feature(与ant191一起介绍),如果你对ant&gt; = 1.9.3,f.e。 :

<!-- you need to activate that feature via namespaces -->
<project
  xmlns:if="ant:if"
  xmlns:unless="ant:unless"
>

 <!-- Import XMLTask -->
 <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask"/>

 <!-- load propertyfile with client=server mappings -->
 <property file="buildpackage.txt"/>

 <!-- loop over all clients -->
 <xmltask source="structure.xml">
  <call path="//client">
   <param path="name/text()" name="client"/>
   <param path="branding/text()" name="branding"/>
   <param path="applications/application/text()" name="application"/>

   <!-- inside action adress params with @{..} syntax ! -->
   <actions>
    <!-- the copy (or whatever) action
         here demonstrated with echoxml -->
   <echoxml if:set="@{client}">
    <!-- access the corresponding server (set via buildpackage.txt)
         with nested ${@{..}} syntax ! -->
    <copy todir="//${@{client}}/share">
     <fileset dir="@{client}/somedir"/>
    </copy>
   </echoxml>

   <echo if:set="@{client}">${@{client}}${line.separator}@{client}${line.separator}@{application}${line.separator}@{branding}</echo>

   <!-- another nested xmltask for loop over solutions -->
   <xmltask source="structure.xml">
    <call path="//client[name/text()='@{client}']/*/solution">
     <param path="text()" name="solution"/>
      <actions>
       <echo if:set="@{client}">@{solution}${line.separator}</echo>
      </actions>
     </call>
   </xmltask>

   </actions>
  </call>
 </xmltask>
</project>

注意=&gt; xmltask调用也有一个if属性,但是在启动循环时不知道客户端名称,不能使用<call path="//client" if="@{client}">
输出:

<?xml version="1.0" encoding="UTF-8"?>
<copy todir="//PRODUCTION1/share">
  <fileset dir="Sol-e-45-D/somedir" />
</copy>
     [echo] PRODUCTION1
     [echo] Sol-e-45-D
     [echo] Sol-e-45-D
     [echo] Branding-BLUE
     [echo] Sol-e-45-D
<?xml version="1.0" encoding="UTF-8"?>
<copy todir="//PRODUCTION3/share">
  <fileset dir="CONNECTION/somedir" />
</copy>
     [echo] PRODUCTION3
     [echo] CONNECTION
     [echo] Sol-e-45-D
     [echo] Branding-BLUE
     [echo] Sol-e-45-D

否则当绑定到ant&lt; = 1.9.3时,你可以使用antcontrib作为任务,因为你已经在你的代码片段中有了taskdef:

<if>
 <isset property="@{client}"/>
  <then>
   <!-- ... -->
  </then>
</if> 

当心,你的antcontrib taskdef定义错误 !!,antcontrib.properties只包含ant&lt;的taskdef。 1.6,声明它(假设antcontrib.jar已经在路径上):

  <project xmlns:ac="antlib:net.sf.antcontrib">

    <ac:if>
    ...

或没有名称空间:

  <project>

  <!-- Import AntContrib -->
  <taskdef resource="net/sf/antcontrib/antlib.xml"/>
  ...