How to develope a method to substitute repetitive code block

浪尽此生 提交于 2019-12-12 04:16:56

问题


I am new in ant, so I wasn't able to find an approach to make my buld file a bit more elegant. I believe there is an approach to substitute repetitive block of code into my build. So here is build file:

<project basedir="../../../" name="do-report" default="zip-all">
    <xmlproperty keeproot="false" file="implementation/xml/ant/properties.xml"/>
    <!--    -->
    <taskdef resource="net/sf/antcontrib/antcontrib.properties">
        <classpath>
            <pathelement location="${infrastructure-base-dir}/apache-ant-1.9.6/lib/ant-contrib-0.3.jar"/>
        </classpath>
    </taskdef>
    <!--    -->
    <target name="clean">
        <delete dir="${dita-odt.path.odt-unzipped-base-dir}" includeemptydirs="true" failonerror="no"/>
        <delete dir="examples/intermediate/odt-files" includeemptydirs="true" failonerror="no"/>
    </target>
    <!--    -->
    <target name="unzip-writing-odt-file" depends="clean">
        <unzip src="${dita-odt.path.writing-odt}" dest="${dita-odt.path.writing-odt-unzipped}"/>
    </target>
    <!--    -->
    <target name="extract-common-paths" depends="unzip-writing-odt-file">
        <foreach target="copy-text-path" param="file">
            <path>
                <fileset dir="${dita-odt.path.text-xml-base-dir}">
                    <include name="**/content.xml"/>
                </fileset>
            </path>
        </foreach>
    </target>
    <!--    -->
    <target name="copy-text-path" description="copy text-xml path relative to text-xml-base-dir">
        <dirname property="text-absolute-dir-path" file="${file}"/>
        <property name="absolute-path-text-base-dir" location="${dita-odt.path.text-xml-base-dir}"/>
        <pathconvert property="common-path" dirsep="/">
            <path location="${text-absolute-dir-path}"/>
            <map from="${absolute-path-text-base-dir}/" to=""/>
        </pathconvert>
        <antcall target="copy-writing-unzipped">
            <param name="common-path" value="${common-path}"/>
        </antcall>
    </target>
    <!--    -->
    <target name="copy-writing-unzipped">
        <echo>${common-path}</echo>
        <copy todir="${dita-odt.path.odt-unzipped-base-dir}/${common-path}">
            <fileset dir="${dita-odt.path.writing-odt-unzipped}">
                <include name="**/*"/>
            </fileset>
        </copy>
    </target>
    <!--   -->
    <target name="transform-all" depends="extract-common-paths">
        <foreach target="transform" param="file">
            <path>
                <fileset dir="${dita-odt.path.text-xml-base-dir}">
                    <include name="**/content.xml"/>
                </fileset>
            </path>
        </foreach>
    </target>
    <!--   -->
    <target name="transform">
        <basename property="file-base-name" file="${file}"/>
        <dirname property="file-dir-absolute-path" file="${file}"/>
        <property name="text-xml-base-dir-absolute-path" location="${dita-odt.path.text-xml-base-dir}"/>
        <pathconvert property="common-path" dirsep="/">
            <path location="${file-dir-absolute-path}"/>
            <map from="${text-xml-base-dir-absolute-path}/" to=""/>
        </pathconvert>
        <!--Substitutes backslashes with forword slashes. Basedir is a reserved property that returns absolute path with separator symbols of the current OS.-->
        <pathconvert dirsep="/" property="base-dir-unix">
            <path location="${basedir}"/>
        </pathconvert>
        <echo>TRANSFORM TO: ${dita-odt.path.odt-unzipped-base-dir}/${common-path}/${file-base-name}</echo>
        <xslt in="${file}" out="${dita-odt.path.odt-unzipped-base-dir}/${common-path}/${file-base-name}" style="${dita-odt.path.text-odt-xsl}" extension=".xml" force="true">
            <param name="dir-path-styles-xml" expression="${dita-odt.path.odt-unzipped-base-dir}/${common-path}"/>
            <param name="project-base-dir-absolute-path" expression="${base-dir-unix}"/>
            <classpath location="${infrastructure-base-dir}/${dita-odt.text-odt-xsl.processor}"/>
        </xslt>
    </target>
    <!--   -->
    <target name="zip-all" depends="transform-all" description="Turns all unzipped text folders into ODT files">
        <foreach target="zip-odt" param="file">
            <path>
                <fileset dir="${dita-odt.path.odt-unzipped-base-dir}" includes="**/content.xml" excludes="writing/**"/>
            </path>
        </foreach>
    </target>
    <!--    -->
    <target name="zip-odt">
        <basename property="file-base-name" file="${file}"/>
        <dirname property="file-dir-absolute-path" file="${file}"/>
        <!--This property will be used to provided name for the produced ODT file. The document will have the same name as the folder that contains it.-->
        <basename property="odt-doc-name" file="${file-dir-absolute-path}.odt"/>
        <property name="odt-unzipped-base-dir-absolute-path" location="${dita-odt.path.odt-unzipped-base-dir}"/>
        <pathconvert property="common-path" dirsep="/">
            <path location="${file-dir-absolute-path}"/>
            <map from="${odt-unzipped-base-dir-absolute-path}/" to=""/>
        </pathconvert>
        <echo>COMMON PATH: ${common-path}</echo>
        <zip destfile="examples/intermediate/odt-files/${common-path}/${odt-doc-name}" basedir="${dita-odt.path.odt-unzipped-base-dir}/${common-path}" update="true"/>
    </target>
    <!--    -->
</project>

So this part of the script does pretty much the same, but shared among almost all the target in the project:

        <dirname property="file-dir-absolute-path" file="${file}"/>
        <property name="text-xml-base-dir-absolute-path" location="${dita-odt.path.text-xml-base-dir}"/>
        <pathconvert property="common-path" dirsep="/">
            <path location="${file-dir-absolute-path}"/>
            <map from="${text-xml-base-dir-absolute-path}/" to=""/>
        </pathconvert>

This part does nothing but to obtain part of a path. For example if ${file} stands for /folder/subfolder1/subfolder2 then take the path after /folder namely subfolder1/subfolder2 and assign it to a property. I this case that property is named common-path that holds same path for all the target. I examined MacroDef Task, but as far as I understand it doesn't return, only accepts some parameters in form of attributes. Anyway, any help would be much appreciated.


回答1:


You are on the right track in considering <macrodef> to reduce repetitive code.

While it's true that <macrodef> doesn't return anything, <macrodef> can be given the name of a property to set. For example...

<macrodef name="my-hello">
    <attribute name="person"/>
    <attribute name="output-property"/>
    <sequential>
        <property name="@{output-property}" value="Hello, @{person}!"/>
    </sequential>
</macrodef>

<my-hello person="Riko" output-property="say-hi-to-riko"/>
<echo>my-hello said: ${say-hi-to-riko}</echo>

...outputs...

[echo] my-hello said: Hello, Riko!

In this example, the caller of <my-hello> tells the macrodef to "return" its results in the say-hi-to-riko property.

Knowing this, several of the <target>s in your script can be converted to <macrodef>s that set properties...

<project name="ant-macrodef-pathconvert" default="extract-common-paths">
    <taskdef resource="net/sf/antcontrib/antlib.xml" />
    <property name="dita-odt.path.text-xml-base-dir" value="C:\temp\dita-odt"/>
    <macrodef name="my-pathconvert">
        <attribute name="file"/>
        <attribute name="common-path-property"/>
        <sequential>
            <!-- <local> allows multiple calls to a macrodef. -->
            <local name="file-dir-absolute-path"/>
            <echo>In my-pathconvert for @{file}</echo>
            <dirname property="file-dir-absolute-path" file="@{file}"/>
            <property name="text-xml-base-dir-absolute-path"
                location="${dita-odt.path.text-xml-base-dir}"/>
            <pathconvert property="@{common-path-property}" dirsep="/">
                <path location="${file-dir-absolute-path}"/>
                <map from="${file-dir-absolute-path}/" to=""/>
            </pathconvert>
        </sequential>
    </macrodef>
    <macrodef name="copy-text-path"
        description="copy text-xml path relative to text-xml-base-dir">
        <attribute name="file"/>
        <sequential>
            <local name="common-path"/>
            <echo>In copy-text-path for @{file}</echo>
            <my-pathconvert file="@{file}" common-path-property="common-path"/>
            <copy-writing-unzipped common-path="${common-path}"/>
        </sequential>
    </macrodef>
    <macrodef name="copy-writing-unzipped">
        <attribute name="common-path"/>
        <sequential>
            <echo>In copy-writing-unzipped for @{common-path}</echo>
            <echo>copy task goes here.</echo>
        </sequential>
    </macrodef>
    <target name="extract-common-paths">
        <for param="file">
            <path>
                <fileset dir="${dita-odt.path.text-xml-base-dir}">
                    <include name="**/content.xml"/>
                </fileset>
            </path>
            <sequential>
                <copy-text-path file="@{file}"/>
            </sequential>
        </for>
    </target>
</project>

In general, it's better to prefer calling <macrodef>s over calling <target>s directly. In the above example, <foreach> is replaced with <for> because <for> lets us call <macrodef>s.

Output

 [echo] In copy-text-path for C:\temp\dita-odt\dir1\content.xml
 [echo] In my-pathconvert for C:\temp\dita-odt\dir1\content.xml
 [echo] In copy-writing-unzipped for C:/temp/dita-odt/dir1
 [echo] copy task goes here.
 [echo] In copy-text-path for C:\temp\dita-odt\dir2\content.xml
 [echo] In my-pathconvert for C:\temp\dita-odt\dir2\content.xml
 [echo] In copy-writing-unzipped for C:/temp/dita-odt/dir2
 [echo] copy task goes here.


来源:https://stackoverflow.com/questions/34336012/how-to-develope-a-method-to-substitute-repetitive-code-block

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!