I am looping list of files inside base directory using for of Ant-Contrib library. I want to get the part of file path after base directory but without filename.
For example my base Directory is : C:\projects\Dev\Main\Sample Game\js
I have lot of js scripts and inside this folder and subfolders name like
C:\projects\Dev\Main\Sample Game\js\simple\welcome\ss.js
C:\projects\Dev\Main\Sample Game\js\hard\welcome\cc.js
C:\projects\Dev\Main\Sample Game\js\easy\welcome\ee.js
I want to get only \simple\welcome\. I am using the below code.
http://pastebin.com/TpqXBb27
<for param="filename">
<path id="project.fileset">
<fileset dir="${basedir}/js" includes="/*">
<include name="**/*.js" />
</fileset>
</path>
<sequential>
<basename property="file.#{filename}" file="#{filename}"/>
<propertyregex property="currentdirectory"
input="#{filename}"
regexp="${basedir}/js//([^//]*)//${file.#{filename}}"
select="\1"
casesensitive="false"
override="true" />
<echo message="FullPath:#{filename}" />
<echo message="Directory:${currentdirectory}" />
</sequential>
</for>
I don't know what regex I should provide there... I tried with regex ${basedir}/js//([^//]*)//${file.#{filename}}, but getting the below error
java.util.regex.PatternSyntaxException: Illegal/unsupported escape sequence near index 3
C:\projects\Dev\Main\Sample Game\js\simple\welcome\ss.js
Please give some suggestion for this regex
This sounds like more of a job for pathconvert rather than propertyregex
<for param="filename">
<path id="project.fileset">
<fileset dir="${basedir}/js" includes="/*">
<include name="**/*.js" />
</fileset>
</path>
<sequential>
<basename property="file.#{filename}" file="#{filename}"/>
<!-- dirname strips off the trailing file name, leaving the full dir -->
<dirname property="dir.#{filename}" file="#{filename}"/>
<pathconvert property="currentdirectory.#{filename}">
<file file="${dir.#{filename}}" />
<!-- pathconvert strips off the leading ${basedir}/js -->
<map from="${basedir}/js" to="" />
</pathconvert>
<echo message="FullPath:#{filename}" />
<echo message="Directory:${currentdirectory.#{filename}}" />
</sequential>
</for>
The problem is that you are on a PC, and when you use ${basedir}, it's giving you the ${basedir} with backward Windows slashes for directory separators. The <fileset/> is doing the same.
I ran into this very same situation, and I had to first do a regexreplace on my path, then do my substitution. Here's the code directly from my project:
<var name="dest.name" unset="true"/>
<var name="file.lastmodified" unset="true"/>
<var name="file.type" unset="true"/>
<file.mdate file="#{file}"
property="file.lastmodified"/>
<propertyregex property="file"
input="#{file}"
regexp="\\"
replace="/"
override="true"
defaultvalue="#{file}"/>
<propertyregex property="dest.name"
input="${file}"
regexp="^${fileset}/"
replace=""
override="true"/>
Note that I now have to use <var/> to unset the properties, so I can use them over and over in my <for> loop:
The first regexreplace will change
C:\projects\Dev\Main\Sample Game\js\simple\welcome\ss.js
to
C:/projects/Dev/Main/Sample Game/js/simple/welcome/ss.js
From there, you can use the basedir task to remove the script. Then, you just need to for the /js/ directory.
<regexreplace property="currentdirectory"
file="#{file}"
regex=".*/js/(.*)"
select="\1"
override="true"/>
Related
I have an ant build file in which:
<target name="foo">
<apply executable="bar" parallel="true">
<fileset dir="." includes="*.xxx" />
<srcfile prefix="--session " />
</apply>
</target>
This will call bar with a single argument of --session a.xxx for each file of the type .xxx in the current directory. How can I get ant to invoke bar with two arguments for each file of the type .xxx?
In the ideal situation bar would receive two arguments, --session and a.xxx for each file of the type .xxx.
It's a little late but I hope anyone who faces this problem in the future can consider my solution and hopefully solve your problem.
For my example, I am trying to execute yuicompressor with multiple options operating on multiple input files:
<apply executable="java" parallel="true">
<fileset dir="./js-ori">
<include name="**/*.js" />
</fileset>
<arg line="-jar" />
<arg path="yuicompressor.jar" />
<arg line="--nomunge" />
<arg line="--preserve-semi" />
<srcfile />
<arg line="-o" />
<arg line="'.js$:.min.js'" />
</apply>
Since apply command with 'parallel="true"' will only apply the options on the first input file, the result is not what is intended. Instead of having ANT pass in the input files, pass in the input files manually using < arg line >.
<!-- Get the fileset as a string -->
<fileset id="myFileSet" dir=".">
<include name="js/**/*.js" />
<exclude name="js/lib/**" />
</fileset>
<property name="fileset" refid="myFileSet" />
<!-- Replace all ';' of the string of files from fileset to your intended options -->
<replaceStringWithRegExp string="${fileset}"
searchPattern=";"
replacementPattern=" --nomunge --preserve-semi "
property="result"/>
<!-- We will disallow <apply> to take in input files by itself since we are already appending the input files manually. -->
<!-- Therefore we add 'addsourcefile="false"' -->
<apply executable="java" parallel="true" addsourcefile="false">
<fileset dir="./js">
<include name="**/*.js" />
<exclude name="lib/**" />
</fileset>
<arg line="-jar" />
<arg path="yuicompressor-2.4.7.jar" />
<arg line="-o" />
<arg line="'.js$:.min.js'" />
<arg line="${result}" /> <!-- pass in the string of options and file names -->
</apply>
This is my solution for executing yuicompressor once with multiple input files and options. I am unsure about other execution of .jar files but the solution should have a similar concept. If you find any part of the code that could be improved, please sound it out to me! Thank you!
Note: If you don't want to install ant-contrib for , you can use the replaceStringWithRegExp function created by Giorgio Ferrara in the link below.
Reference
Thanks Giorgio Ferrara for the replaceStringWithRegExp function!
You can use an extra <arg/> tag to include --session as a separate argument:
<target name="foo">
<apply executable="bar" parallel="false">
<fileset dir="." includes="*.xxx" />
<arg value="--session" />
<srcfile />
</apply>
</target>
I am signing my jars using following ant commands.
<signjar alias="${alias}" keypass="${keypass}"
storepass="${storepass}"
keystore="${keystorefile}"
signedjar="${dist.dir}/${jar.signed.fileName}"
lazy="true">
<fileset dir="${dist.dir}">
<include name="*.jar" />
<include name="lib/*.jar" />
</fileset>
</signjar>
For single file it is fine that I can change the name of the jars file after signing it,
but when I have multiple jars the above line is not useful, what i am trying to accomplish is ,
for example
If the unsigned jar file name is ab.jar after signing it I want to prependSigned_to it's name likeSigned_ab.jar` and so on for all the jars i have in my fileset.
Can anyone tell me how to do that ?
You can use the ant jar command/task like below in your build script :
<jar basedir="bin" destfile="Signed_${jar-name}.jar">
btw, you missed to type the command you're using, in your question.
The signjar task can take a mapper defining how to translate the input file name into an output file name:
<signjar alias="${alias}" keypass="${keypass}"
storepass="${storepass}"
keystore="${keystorefile}"
destdir="${dist.dir}"
lazy="true">
<fileset dir="${dist.dir}">
<include name="*.jar" />
<include name="lib/*.jar" />
<!-- since we're dumping signed JARs in the same dir as the source
ones, we need to prevent already-signed JARs from being signed
again. A better approach might be to put the Signed_* JARs in
a different directory -->
<exclude name="**/Signed_*" />
</fileset>
<regexpmapper handledirsep="yes"
from="^(.*?)/([^/]*)$$" to="\1/Signed_\2" />
</signjar>
May be you can write couple of macros & call 'signJarsParallel' macro once for every directory for which you want to sign jars.
This is not tested code. You can give it a try. It makes use running tasks parallely & hence increasing speed & signs to temporary-prefixed name you want :
<macrodef name="signMyJars">
<element name="myJar" implicit="true"/>
<sequential>
<signjar alias="${alias}" keypass="${keypass}"
storepass="${storepass}"
keystore="${keystorefile}"
lazy="true">
<myJar/>
</signjar>
</sequential>
</macrodef>
Call only below macro inside your ant target.
<macrodef name="signJarsParallel">
<attribute name="dirName"/>
<sequential>
<for param="file" parallel="true" threadCount="5">
<path>
<fileset dir="#{dirName}">
<include name="*.jar"/>
<include name="lib/*.jar"/>
</fileset>
</path>
<signMyJars>
<fileset file="Signed_#{file}.jar"/>
</signMyJars>
</for>
</sequential>
</macrodef>
I need to write an Ant target that appends together (comma-delimited) a list of '.jar' file names from a folder into a variable, which is later used as input to an outside utility.
I am running into barriers of scope and immutability. I have access to ant-contrib, but unfortunately the version I am stuck with does not have access to the 'for' task. Here's what I have so far:
<target name="getPrependJars">
<var name="prependJars" value="" />
<foreach param="file" target="appendJarPath">
<path>
<fileset dir="${project.name}/hotfixes">
<include name="*.jar"/>
</fileset>
</path>
</foreach>
<echo message="result ${prependJars}" />
</target>
<target name="appendJarPath">
<if>
<equals arg1="${prependJars}" arg2="" />
<then>
<var name="prependJars" value="-prependJars ${file}" />
</then>
<else>
<var name="prependJars" value="${prependJars},${file}" />
</else>
</if>
</target>
It seems that 'appendJarPath' only modifies 'prependJars' within its own scope. As a test, I tried using 'antcallback' which works for a single target call, but does not help me very much with my list of files.
I realize that I am working somewhat against the grain, and lexical scope is desirable in the vast majority of instances, but i really would like to get this working one way or another. Does anybody have any creative ideas to solve this problem?
You might be able to use the pathconvert task, which allows you to specify the separator character as comma.
<target name="getPrependJars">
<fileset id="appendJars" dir="${project.name}/hotfixes">
<include name="*.jar" />
</fileset>
<pathconvert property="prependJars" refid="appendJars" pathsep="," />
<echo message="prependJars: ${prependJars}" />
</target>
I'd simply write a custom task in Java that (1) takes the folder name, (2) assembles the result string and (3) stores it to the ${prependJars} property.
In ant you just define the task (taskdef) and use like all other tasks afterwards.
I did it once when I was faced with a simliar problem and found that it was very, very easy.
Here's the tutorial.
If a system path format is useful to you, you can use the following:
<target name="getPrependJars">
<path id="prepend.jars.path">
<fileset dir="${project.name}/hotfixes">
<include name="*.jar"/>
</fileset>
</path>
<property name="prependJars" value="${toString:prepend.jars.path}" />
<echo message="result ${prependJars}" />
</target>
My current build file has the following repetitive tasks:
<jar jarfile="${build.lib}/${prefix}-foo.jar">
<fileset dir="${build.classes}">
<include name="com/a/c/foo/**"/>
</fileset>
</jar>
<jar jarfile="${build.lib}/${prefix}-bar.jar">
<fileset dir="${build.classes}">
<include name="com/a/c/bar/**"/>
</fileset>
</jar>
... etc. The issue is that the build.xml must be modified for each new package or for each new sub-project. This is a frequent occurrence where I work.
I would like to replace this with logic that will dynamically generate the JARs and their file names based off of a "root" package. So, for example, I could set the root package to be com/a/c, and all packages directly under that package would get their own JAR. Note that all packages under "foo" or "bar" would just be part of "foo.jar" or "bar.jar".
I looked up for loop logic tasks for ANT. I found one in each ant-contrib and JWare/AntXtras, but I could not get either to work as desired.
I don't know about looping over and finding all package names, but you could use a macro to avoid code duplication.
I haven't tried this, but it could work
<macrodef name="build_jar">
<attribute name="name"/>
<sequential>
<jar jarfile="${build.lib}/${prefix}-#{name}.jar">
<fileset dir="${build.classes}">
<include name="com/a/c/#{name}/**"/>
</fileset>
</jar>
</sequential
</macrodef>
<target name="build_foo">
<build_jar name="foo"/>
</target>
<target name="build_bar">
<build_jar name="bar"/>
</target>
How about this:
<project name="dynjar" default="jar" basedir=".">
<property name="build.classes" value="${basedir}/classes"/>
<property name="build.lib" value="${basedir}/lib"/>
<property name="prefix" value="prefix"/>
<property name="root" value="com/a/c"/>
<target name="jar">
<!-- ${ant.file} is the name of the current build file -->
<subant genericantfile="${ant.file}" target="do-jar">
<!-- Pass the needed properties to the subant call. You could also use
the inheritall attribute on the subant element above to pass all
properties. -->
<propertyset>
<propertyref name="build.classes"/>
<propertyref name="build.lib"/>
<propertyref name="prefix"/>
<propertyref name="root"/>
</propertyset>
<!-- subant will call the "do-jar" target for every directory in the
${build.classes}/${root} directory, making the subdirectory the
basedir. -->
<dirset dir="${build.classes}/${root}" includes="*"/>
</subant>
</target>
<target name="do-jar">
<!-- Get the basename of the basedir (foo, bar, etc.) -->
<basename file="${basedir}" property="suffix"/>
<jar jarfile="${build.lib}/${prefix}-${suffix}.jar">
<fileset dir="${build.classes}">
<include name="${root}/${suffix}/**"/>
</fileset>
</jar>
</target>
</project>
I have a property, app.version, which is set to 1.2.0 (and, of course, always changing) and need to create zip file with name "something-ver-1_2_0". Is this possible?
You can use the pathconvert task to replace "." with "_" and assign to a new property:
<?xml version="1.0" encoding="UTF-8"?>
<project>
<property name="app.version" value="1.2.0"/>
<pathconvert property="app.version.underscore" dirsep="" pathsep="" description="Replace '.' with '_' and assign value to new property">
<path path="${app.version}" description="Original app version with dot notation" />
<!--Pathconvert will try to add the root directory to the "path", so replace with empty string -->
<map from="${basedir}" to="" />
<filtermapper>
<replacestring from="." to="_"/>
</filtermapper>
</pathconvert>
<echo>${app.version} converted to ${app.version.underscore}</echo>
</project>
Another approach is to filter the version number from a file to a property using a regular expression, as suggested in this example:
<loadfile srcfile="${main.path}/Main.java" property="version">
<filterchain>
<linecontainsregexp>
<regexp pattern='^.*String VERSION = ".*";.*$'/>
</linecontainsregexp>
<tokenfilter>
<replaceregex pattern='^.*String VERSION = "(.*)";.*$' replace='\1'/>
</tokenfilter>
<striplinebreaks/>
</filterchain>
</loadfile>
Since the property app.version is always changing i assume you don't want to hard code it into the properties files, rather pass it when you do the build. Further to this answer, you can try the following on the command line;
ant -f build.xml -Dapp.version=1.2.0
changing app.version to the one required then.
Edit:
Understood better your question from the feedback. Unfortunately ant does not have string manipulation tasks, you need to write you own task for this. Here is a close example.
It's possible using the zip task
<zip zipfile="something-ver-${app.version}.zip">
<fileset basedir="${bin.dir}" prefix="bin">
<include name="**/*" />
</fileset>
<fileset basedir="${doc.dir}" prefix="doc">
<include name="**/*" />
</fileset></zip>
For more information about the zip task: http://ant.apache.org/manual/Tasks/zip.html
Properties can't be changed but antContrib vars (http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html ) can.
Here is a macro to do a find/replace all on a var:
<macrodef name="replaceVarText">
<attribute name="varName" />
<attribute name="from" />
<attribute name="to" />
<sequential>
<local name="replacedText"/>
<local name="textToReplace"/>
<local name="fromProp"/>
<local name="toProp"/>
<property name="textToReplace" value = "${#{varName}}"/>
<property name="fromProp" value = "#{from}"/>
<property name="toProp" value = "#{to}"/>
<script language="javascript">
project.setProperty("replacedText",project.getProperty("textToReplace").split(project.getProperty("fromProp")).join(project.getProperty("toProp")));
</script>
<ac:var name="#{varName}" value = "${replacedText}"/>
</sequential>
</macrodef>
Then call the macro like:
<ac:var name="newFileName" value="${app.version}"/>
<current:replaceVarText varName="newFileName" from="." to="_" />
<echo>Filename will be ${newFileName}