ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Matt Lyon" <m...@stargus.com>
Subject <foreach> & <propertycopy> (was 'RE: Automated source config model?')
Date Thu, 05 Sep 2002 16:22:29 GMT
DD,

Thanks for the information! The issue I was facing seemed to be due to property scope/flow
control. I had placed a task to read in properties from an external properties file inside
an init target, which did not allow the subsequent targets to work the <propertycopy>
magic of expanding nested properties in that same property file which you so eloquently described.
If I place the  <property file="config.properties"/> at the <project> level in
my buildfile and not inside any target, that gets me past the problem.

However, I'm still stuck on a <propertycopy> issue. Using Matt McHenry's model again,
if I have an external properties file that lists the following:

#The list of modules
components=platform,ui,content

#The tag for the 'platform' module
platform.tag=V1_0_6_183
#The platform directories
platform.dirs=starman/src/com/stargus/platform

#The tag for the 'ui' module
ui.tag=V1_0_6_183
#The ui directories
ui.dirs=starman/src/com/stargus/web,starman/src/web

#The tag for the 'content' module
content.tag=V1_0_7_184
#The content directories
content.dirs=starman/src/com/stargus/platform/content

And a build.xml which contains the following target sequence:

  <!-- Targets to check out the souce code from CVS. --> 
  <target name="checkout" 
          depends="init" 
          description="Checks out tagged directories listed in the build_config.properties
file.">
    <foreach list="${components}"
             target="checkout-dirs"
             param="component"/>
  </target>

  <target name="checkout-dirs"> 
    <propertycopy name="complist"
                  from="${component}.dirs"/>
    <propertycopy name="comptag"
                  from="${component}.tag"/>
    <foreach list="${complist}"
             target="checkout-dir"
             param="ckout.pkg"/>
  </target>

  <target name="checkout-dir-tag"
          if="comptag">
    <echo message="checking out ${ckout.pkg} with tag ${comptag}"/>
    <cvs cvsRoot="${cvsRoot}"
         dest="${src}"
         command="co -P -r ${comptag} ${ckout.pkg}"/>
  </target> 

  <target name="checkout-dir-notag" 
          unless="comptag">
    <echo message="NOTE: no tag defined for ${ckout.pkg}; checking out from main code line"/>

    <cvs cvsRoot="${cvsRoot}"
         dest="${src}"
         command="co -PA ${ckout.pkg}"/>
  </target>

  <target name="checkout-dir" depends=checkout-dir-tag,checkout-dir-no-tag"/>


What I'm finding is that the ${complist} property value is passed to the checkout-dir tag
as param ${ckout.pkg} with the expected <foreach> iterations performed, but the checkout-dir-tag
target is never executed because the ${comptag} property value is either not getting defined
by <propertycopy> or is not recognized by the checkout-dir composite target due to some
sort of flow control or property scope issue. How can I force the setting and propagation
of the ${comptag} property value to the subsequent targets?

Matt
-----Original Message-----
From: Dominique Devienne [mailto:DDevienne@lgc.com]
Sent: Wednesday, September 04, 2002 5:43 PM
To: 'Ant Users List'
Subject: RE: Automated source config model?


The <foreach> sets the 'component' param (not property, but the distinction
is small), passed to the 'checkout-dirs' target. This target in turn doesn't
use the 'component.dirs' property, it uses the 'component' property, to
lookup the '${component}.dirs' property, where ${component} is resolved to
its value (for example, acme.dirs). This is the bit of magic <propertycopy>
does, allowing nested properties (it's equivalent to the illegal
${${component}.dirs}).

I don't thing this has anything to do with property immutability.

Hope this helps. --DD

-----Original Message-----
From: Matt Lyon [mailto:matt@stargus.com] 
Sent: Wednesday, September 04, 2002 4:19 PM
To: Ant-User (E-mail)
Subject: RE: Automated source config model?

Matt,
 
Thanks for the information. What I don't understand about your approach is
how the foreach task in your checkout target can pass a param to the
propertycopy task to define the value which it is supposed to then associate
with the matching property value in from the propfile to create a new
property. Specifically, I'm referring to
 
  <!-- targets to check out the souce code from cvs --> 
  <target name="checkout" depends="init" 
          description="checks out tagged directories listed in the
propfile"> 
    <record name="${cvslogfile}" append="true" action="start"/> 
    <foreach list="${components}" target="checkout-dirs" param="component"/>
 
^
    <antcall target="checkout-build" inheritAll="true"/> 
    <record name="${cvslogfile}" action="stop"/> 
  </target> 
 
and 

  <target name="checkout-dirs"> 
    <propertycopy name="complist" from="${component}.dirs"/>
                                                         ^
    <propertycopy name="comptag" from="${component}.tag" silent="true"/> 
    <foreach list="${complist}" target="checkout-dir" param="ckout.pkg"/> 
  </target> 
 
There's probably a really simple explanation, but I'm missing something
conceptually here. If I try something similar my build bombs out because the
value of ${component.dirs} is not defined for the checkout-dirs target. Is
this due to property immutability holes being plugged in Ant 1.5?
 
Matt

-----Original Message-----
From: McHenry, Matt [mailto:mmchenry@carnegielearning.com]
Sent: Tuesday, September 03, 2002 5:07 PM
To: Matt Lyon
Cc: Ant Users List
Subject: RE: Automated source config model?



> Thanks for the information. I would be interested in seeing how you
implemented what you have if > you can give me a high level view without
ruffling any feathers. Thanks.

        Okay, here's an example java properties file that defines a set of
deliverables built from several components, each checked out from CVS with a
different tag.

        (This is a bit more than what you want, as it's geared towards
checking out into a sandbox directory where the build happens, then
collecting all the deliverables into a holding directory so that the
installer project can find them.)


#the deliverable files 
deliverables.files=dist/lib1.jar,dist/lib2.jar 

#you can also specify entire directories 
#deliverables.dirs 

#the list of components -- details of each are specified below 
components=platform,ui,content 

#the buildfile 
build.file=build.xml 
build.file.tag=BUILDFILE_03 
build.dir=src 
build.target=jars 

#the tag for the 'platform' component 
platform.tag=PLATFORM_17 
#the directories under CVS covered by that tag 
platform.dirs=src/platform,src/foo 

#the tag for the 'ui' component 
ui.tag=UI_08 
#the directories under CVS covered by that tag 
ui.dirs=src/ui,src/util 

#leave the tag undefined to check out 
#to the edge of the main trunk 
#content.tag= 
content.dirs=content/site1,content/site1,content/site3 

        The following ant project will process this sort of properties file.
You can just use the 'checkout' target to pull stuff from CVS, or if you
also want to build according to the build.* properties, you can use the
'call-build' or 'copy-delivs' targets.


<project name="cvsbuild" default="copy-delivs" basedir="."> 

  <!-- This ant file defines targets used to check out code and a 
  build file from CVS, call a target in that build file, and copy the 
  deliverables created by that build file into a deliverables 
  directory.  The build file can also be left out if all of the 
  deliverables are retrieved directly from CVS.  This is useful for 
  e.g. straight text files, or third-party binaries. 

  When using this ant file, the property 'propfile' must be defined on 
  the command line (e.g. ant -Dpropfile=java-tags.txt).  This property 
  is the name of an ant properties file.  The propfile is basically a 
  list of CVS modules, and tags corresponding to one or more of the 
  modules. 

  For a given tagged module, two properties should be defined: 
   <module>.tag: the cvs tag for this module 
   <module>.dirs: a comma-separated list of directories which make up 
                  this module 
  The <module>.tag property may be left undefined, in which case the 
  module will be checked out to the edge of the tree. 

  The propfile must define the following special property: 
   components: a comma-separated list of the <module> tags to be used 
               in the build. 

  At least one of these two properties must be defined as well: 
   deliverables.files: a comma-separated list of paths to individual 
                       deliverable files (typically .zip files) 
   deliverables.dirs: a comma-separated list of paths to deliverable 
                      directories.  This is used to pull an entire 
                      directory out of CVS into the deliverables 
                      directory. 

  If the deliverables must be constructed via a buildfile, the 
  propfile should define the following four special properties: 
   build.file: the name of the ant build file for this project.  The 
               path to this file is constructed as 
               ${build.dir}/${build.file}. 
   build.dir: the base directory to use when calling ant using 
              ${build.file}. 
   build.target: the name of the target (defined in ${build.file}) to 
                 build 
   build.file.tag: the cvs tag to use when checking out the build 
                   file. 
  The build.file.tag property may be left undefined, in which case the 
  build file will be checked out to the edge of the tree. 

  This ant file also defines a target to tag the modules listed in a 
  propfile.  Typically this is used once a build (the copy-delivs 
  target) has succeeded to mark the source code as stable & as part of 
  whatever release is being built. 

  --> 

  <taskdef name="foreach" 
           classname="org.apache.tools.ant.taskdefs.optional.ForEach"/> 
  <taskdef name="propertycopy" 
           classname="org.apache.tools.ant.taskdefs.optional.PropertyCopy"/>


  <!-- the temporary directory where we'll check out the modules --> 
  <property name="cvstree" value="${basedir}/cvstree"/> 

  <!-- the directory where the deliverables will be stored --> 
  <property name="deliv.dir" value="${basedir}/deliv"/> 

  <!-- file where cvs actions are logged --> 
  <property name="cvslogfile" value="cvslog"/> 

  <!-- file where the results of building target ${build.target} in 
  ${build.file} are logged --> 
  <property name="buildlogfile" value="buildlog"/> 

  <!-- load in the properties from the propfile --> 
  <property file="${propfile}"/> 


  <target name="check-for-tagname" unless="tagname" 
          description="checks that the 'tagname' property has been defined">

    <echo message="You must define the 'tagname' property on the command
line.  For example:"/> 
    <echo message="   ant -Dtagname=STABLE_2002"/> 
    <fail message="The 'tagname' property has not been defined."/> 
  </target> 

  <target name="check-for-propfile" 
          description="checks that the file 'propfile' exists"> 
    <available file="${propfile}" type="file" property="propfile-ok"/> 
    <antcall target="fail-no-propfile"/> 
  </target> 

  <target name="fail-no-propfile" unless="propfile-ok" 
          description="presents an error message to the user if 'propfile'
is invalid"> 
    <echo message="You must define the 'propfile' property on the command
line.  For example:"/> 
    <echo message="   ant -Dpropfile=tags.txt"/> 
    <echo message="will build according to the tags in the file tags.txt"/> 
    <fail message="The 'propfile' property has not been defined, or points
to a non-existent file."/> 
  </target> 

  <target name="init" depends="check-for-propfile"> 
    <mkdir dir="${cvstree}"/> 
  </target> 


  <!-- targets to check out the souce code from cvs --> 
  <target name="checkout" depends="init" 
          description="checks out tagged directories listed in the
propfile"> 
    <record name="${cvslogfile}" append="true" action="start"/> 
    <foreach list="${components}" target="checkout-dirs" param="component"/>

    <antcall target="checkout-build" inheritAll="true"/> 
    <record name="${cvslogfile}" action="stop"/> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the checkout wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="checkout-build" if="build.file"> 
    <propertycopy name="comptag" from="build.file.tag" silent="true"/> 
    <antcall target="checkout-dir" inheritAll="true"> 
      <param name="ckout.pkg" value="${build.dir}/${build.file}"/> 
    </antcall> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the checkout wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="checkout-dirs"> 
    <propertycopy name="complist" from="${component}.dirs"/> 
    <propertycopy name="comptag" from="${component}.tag" silent="true"/> 
    <foreach list="${complist}" target="checkout-dir" param="ckout.pkg"/> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the checkout-dirs wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="checkout-dir-tag" if="comptag"> 
    <echo message="checking out ${ckout.pkg} with tag ${comptag}"/> 
    <cvs dest="${cvstree}" quiet="true" failonerror="true" 
         command="checkout -P -r ${comptag} &quot;${ckout.pkg}&quot;"/> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the checkout-dirs wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="checkout-dir-notag" unless="comptag"> 
    <echo message="NOTE: no tag defined for ${ckout.pkg}; checking out to
edge of tree"/> 
    <cvs dest="${cvstree}" quiet="true" failonerror="true" 
         command="checkout -PA &quot;${ckout.pkg}&quot;"/> 
  </target> 

  <target name="checkout-dir"
depends="checkout-dir-tag,checkout-dir-notag"/> 


  <!-- targets to tag the souce code in cvs --> 
  <target name="tag" depends="init,check-for-tagname" 
          description="tags directories listed in the propfile"> 
    <record name="${cvslogfile}" append="true" action="start"/> 
    <foreach list="${components}" target="tag-dirs" param="component"/> 
    <antcall target="tag-build" inheritAll="true"/> 
    <record name="${cvslogfile}" action="stop"/> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the tag wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="tag-build" if="build.file"> 
    <antcall target="tag-dir" inheritAll="true"> 
      <param name="ckout.pkg" value="${build.dir}/${build.file}"/> 
    </antcall> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the tag wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="tag-dirs"> 
    <propertycopy name="complist" from="${component}.dirs"/> 
    <foreach list="${complist}" target="tag-dir" param="ckout.pkg"/> 
  </target> 

  <!-- WARNING: this depends on init, but it should only be called by 
  the tag-dirs wrapper task, so we're going to leave the explicit 
  dependency off for efficiency --> 
  <target name="tag-dir"> 
    <echo message="tagging ${ckout.pkg} with tag ${tagname}"/> 
    <cvs dest="${cvstree}" quiet="true" failonerror="true" 
         command="tag -F ${tagname} &quot;${ckout.pkg}&quot;"/> 
  </target> 


  <!-- a target to call out to the build.xml we've gotten out of CVS --> 
  <target name="call-build-bf" depends="init,checkout" if="build.file" 
          description="executes the selected target on the checked-out build
file"> 
    <record name="${buildlogfile}" append="true" action="start"/> 
    <echo message="calling target ${build.target} in buildfile
${build.dir}/${build.file}"/> 
    <ant antfile="${build.file}" dir="${cvstree}/${build.dir}"
target="${build.target}" inheritAll="false"/> 
    <record name="${buildlogfile}" action="stop"/> 
  </target> 

  <target name="call-build-nobf" unless="build.file" 
          description="makes a note in the log file that no build file is
being called"> 
    <echo message="NOTE: No build file is defined, so no call to it is being
made."/> 
    <echo message="      Deliverables are assumed to have been checked out
directly from CVS."/> 
  </target> 

  <target name="call-build" depends="call-build-bf,call-build-nobf" 
          description="meta-target to call out to a build file, if one is
defined"/> 

  <!-- targets to copy the deliverables to where they belong --> 
  <target name="init-deliv" description="creates the 'deliv.dir' directory">

    <mkdir dir="${deliv.dir}"/> 
  </target> 

  <target name="copy-delivs"
depends="call-build,init-deliv,copy-deliv-files,copy-deliv-dirs" 
          description="meta-target to copy the deliverables"/> 

  <target name="copy-deliv-files" if="deliverables.files" 
          description="copies each of the deliverable files"> 
    <foreach list="${deliverables.files}" target="copy-deliv-file"
param="deliv"/> 
  </target> 

  <target name="copy-deliv-dirs" if="deliverables.dirs" 
          description="copies each of the deliverable directories"> 
    <foreach list="${deliverables.dirs}" target="copy-deliv-dir"
param="deliv"/> 
  </target> 

  <target name="copy-deliv-file"> 
    <echo message="copying deliverable file(s): ${deliv}"/> 
    <copy todir="${deliv.dir}" flatten="true"> 
      <fileset dir="${cvstree}"> 
        <include name="${deliv}"/> 
      </fileset> 
    </copy> 
  </target> 

  <target name="copy-deliv-dir"> 
    <echo message="copying deliverable dir(s): ${deliv}"/> 
    <copy todir="${deliv.dir}/${deliv}" flatten="false"> 
      <fileset dir="${cvstree}/${deliv}"/> 
    </copy> 
  </target> 


  <!-- housekeeping targets --> 
  <target name="clean-comps" depends="init" 
          description="removes all checked-out components from the temporary
cvs tree, including the build file"> 
    <foreach list="${components}" target="clean-dirs" param="component"/> 
    <antcall target="clean-buildfile" inheritAll="true"/> 
  </target> 

  <target name="clean-buildfile" 
          description="removes the checked-out build file"> 
    <echo message="deleting file ${build.dir}/${build.file}"/> 
    <delete file="${cvstree}/${build.dir}/${build.file}"/> 
  </target> 

  <target name="clean-dirs"> 
    <propertycopy name="complist" from="${component}.dirs"/> 
    <foreach list="${complist}" target="clean-dir-or-file"
param="clean.pkg"/> 
  </target> 

  <target name="decide-dir-or-file"> 
    <available file="${cvstree}/${clean.pkg}" type="dir"
property="tgt-is-dir"/> 
  </target> 

  <target name="clean-dir" if="tgt-is-dir"> 
    <echo message="deleting directory ${clean.pkg}"/> 
    <delete dir="${cvstree}/${clean.pkg}"/> 
  </target> 

  <target name="clean-file" unless="tgt-is-dir"> 
    <echo message="deleting file ${clean.pkg}"/> 
    <delete file="${cvstree}/${clean.pkg}"/> 
  </target> 

  <target name="clean-dir-or-file"
depends="decide-dir-or-file,clean-dir,clean-file"/> 

  <target name="clean-delivs-dirs" if="deliverables.dirs"> 
    <foreach list="${deliverables.dirs}" target="clean-delivs-dir"
param="dir"/> 
  </target> 

  <target name="clean-delivs-dir"> 
    <echo message="deleting dir ${dir}"/> 
    <delete dir="${cvstree}/${dir}"/> 
  </target> 

  <target name="clean-delivs-files" if="deliverables.files"> 
    <foreach list="${deliverables.files}" target="clean-delivs-file"
param="file"/> 
  </target> 

  <target name="clean-delivs-file"> 
    <echo message="deleting file ${file}"/> 
    <delete dir="${cvstree}/${file}"/> 
  </target> 

  <target name="clean-delivs"
depends="init,clean-delivs-dirs,clean-delivs-files" 
          description="removes all deliverables from the temporary cvs
tree"/> 

  <target name="clean" description="removes the entire temp cvs tree"> 
    <delete dir="${cvstree}"/> 
  </target> 

</project> 


Matt McHenry 
Software Developer 
Carnegie Learning 
(412)690-2442 x150 


--
To unsubscribe, e-mail:   <mailto:ant-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-user-help@jakarta.apache.org>


--
To unsubscribe, e-mail:   <mailto:ant-user-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-user-help@jakarta.apache.org>


Mime
View raw message