I have more than 30 odx-d files (odx-d is just xml file with different extension).
All files have common tags:
<DOC-REVISION>
<REVISION-LABEL>01.02.03-04</REVISION-LABEL>
<STATE>RELEASE</STATE>
<DATE>2018-11-14T16:26:00+01:00</DATE>
</DOC-REVISION>
At every release I need to change these values in all files.
Note: Manipulation using Java is not possible as while build just making zip of all these files not using Java to manipulate these files.
Please suggest a way to have one file (any file type you suggest) where I can have these values and place holders for the tags in all these files.
Thanks.!
This is doable with the following steps:
replace the common tag values with placeholders e.g. #revision#,
#state#, #date#
copy each file to a temporary location
perform the replacements in the copied files using a <replace file="${dest.file}"> task with nested <replacefilter .../> elements
zip the transformed files in the temporary location
For example, using a template file "template.xml" like this:
<DOC-REVISION>
<REVISION-LABEL>#revision#</REVISION-LABEL>
<STATE>#state#</STATE>
<DATE>#date#</DATE>
</DOC-REVISION>
you can set the real values with this ant target (skipping the zip part):
<target name="test">
<property name="my.revision" value="01.02.03-04"/>
<property name="my.state" value="RELEASE"/>
<tstamp>
<format property="my.date" pattern="yyyy-MM-dd hh:mm z"/>
</tstamp>
<property name="template.file" value="./template.xml"/>
<property name="dest.file" value="./doc.odx"/>
<delete file="${dest.file}" quiet="true"/>
<copy toFile="${dest.file}" file="${template.file}"/>
<replace file="${dest.file}">
<replacefilter token="#revision#" value="${my.revision}"/>
<replacefilter token="#state#" value="${my.state}"/>
<replacefilter token="#date#" value="${my.date}"/>
</replace>
</target>
Solution for multiple files.
Replace values with placeholders #revision#, #state#, #date# and place into template folder.
Perform the copy operation with filterset from template to dest directory.
Example:
Template dir: 'fromDir', destination: 'toDir'
1) Template files:
<DOC-REVISION>
<REVISION-LABEL>#revision#</REVISION-LABEL>
<STATE>#state#</STATE>
<DATE>#date#</DATE>
</DOC-REVISION>
2) Declare properties and perform test target operation.
<!-- Properties -->
<property name="version" value="01.02.03-04" />
<property name="state" value="RELEASE" />
<tstamp>
<format property="now" pattern="yyyy-MM-dd'T'HH:mm:ss.SSSXXX"/>
</tstamp>
<!-- Target -->
<target name="test">
<copy todir="${toDir}">
<fileset dir="${fromDir}" />
<filterset>
<filter token="revision" value="${version}" />
<filter token="state" value="${state}" />
<filter token="date" value="${now}" />
</filterset>
</copy>
</target>
Thanks!
Related
I have a property file (x.props) that contains properties required for an Ant build:
x.props:
prop1=something
prop2=somethingElse
set in build.xml:
<property file="x.props" />
The properties contained in x.props are then used in a path task:
<path id="project.class.path">
<pathelement location="${prop1}/important.jar"/>
<pathelement location="${prop2}/anotherImportant.jar"/>
</path>
Before compilation starts. I don't explicitly create these properties in build.xml
The x.props file can be different for each local user, but for server builds it doesn't change.
I created an x.props.template file to address the problem of users accidentally checking in or updating this file (but they need to be able to check it out). I want to be able to create an x.props file from the x.props.template (I set x.props as svn:ignore).
Users can save the template file as x.props and edit it and - theoretically, the server Ant build.xml can copy the template file to the server x.props if it doesn't exist.
But that's not happening. I tried using a target:
<target name="x-props-file" unless="prop1" description="create a
local.properties file if it doesn't exist">
<copy file="x.props.template" tofile="x.props" />
</target>
But it's called AFTER the path is set.
I tried creating the file as a condition:
<condition available="x.props">
<not>
<copy file="x.props.template" tofile="x.props" />
</not>
</condition>
But 'not' and 'condition' don't work with copy.
loadProperties will fail if the file isn't found - but it won't copy a file.
Ideally I'd like to be able to copy the new x.props right after the initial file load fails.
Is there any way around this?
ant version 1.1
java 7
Thanks
This would probably be simplest with ant-contrib's <if> task:
<if>
<not>
<available file="x.props" />
</not>
<then>
<copy file="x.props.template" tofile="x.props" />
</then>
</if>
Edit: I just rediscovered this answer that I gave years ago after a comment was added, and realized that there's a much better solution that doesn't rely on ant-contrib. It's probably way too late to be of much use to the original poster, but I figured I'd offer it up anyway in case it helps someone:
<property file="x.props" />
<property name="prop1" value="something" />
<property name="prop1" value="somethingElse" />
<path id="project.class.path">
<pathelement location="${prop1}/important.jar"/>
<pathelement location="${prop2}/anotherImportant.jar"/>
</path>
No need for an extra template file. Just attempt to load the property file first and set your defaults immediately after that, making use of Ant's inherent property immutability.
Conversely, if you really want to use a separate properties file to hold your default values, just do the same thing as above but replace the individual property assignments with another property file load:
<property file="x.props" />
<property file="default.props" />
By using following block of code in build.xml file
<propertyfile file="default.properties" comment="Default properties">
<entry key="source.dir" value="1" />
<entry key="dir.publish" value="1" />
<entry key="dir.publish.html" value="1" />
</propertyfile>
I am able to generate default.properties file with following file contents
source.dir=1
dir.publish=1
dir.publish.html=1
I want to know how can I add my comments in the generated file? E.g. the generated properties should have the following content:
# Default Configuration
source.dir=1
dir.publish=1
# Source Configuration
dir.publish.html=1
How can I do it dynamically using Ant's build.xml?
The property file task is for editing properties files. It contains all sorts of nice features that allow you to modify entries. For example:
<propertyfile file="build.properties">
<entry key="build_number"
type="int"
operation="+"
value="1"/>
</propertyfile>
I've incremented my build_number by one. I have no idea what the value was, but it's now one greater than what it was before.
Use the <echo> task to build a property file instead of <propertyfile>. You can easily layout the content and then use <propertyfile> to edit that content later on.
Example:
<echo file="build.properties">
# Default Configuration
source.dir=1
dir.publish=1
# Source Configuration
dir.publish.html=1
</echo>
Create separate properties files for each section. You're allowed a comment header for each type. Then, use to batch them together into one single file:
Example:
<propertyfile file="default.properties"
comment="Default Configuration">
<entry key="source.dir" value="1"/>
<entry key="dir.publish" value="1"/>
<propertyfile>
<propertyfile file="source.properties"
comment="Source Configuration">
<entry key="dir.publish.html" value="1"/>
<propertyfile>
<concat destfile="build.properties">
<fileset dir="${basedir}">
<include name="default.properties"/>
<include name="source.properties"/>
</fileset>
</concat>
<delete>
<fileset dir="${basedir}">
<include name="default.properties"/>
<include name="source.properties"/>
</fileset>
</delete>
Writing the properties file with multiple comments is not supported. Why ?
PropertyFile.java
public class PropertyFile extends Task {
/* ========================================================================
*
* Instance variables.
*/
// Use this to prepend a message to the properties file
private String comment;
private Properties properties;
The ant property file task is backed by a java.util.Properties class which stores comments using the store() method. Only one comment is taken from the task and that is passed on to the Properties class to save into the file.
The way to get around this is to write your own task that is backed by commons properties instead of java.util.Properties. The commons properties file is backed by a property layout which allows settings comments for individual keys in the properties file. Save the properties file with the save() method and modify the new task to accept multiple comments through <comment> elements.
According to the documentation of the PropertyFile task, you can append the generated properties to an existing file. You could have a properties file with just the comment line, and have the Ant task append the generated properties.
I am trying to get a ANT-Buildscript to count the lines that are stored inside a ANT-property. From the examples I got the way to count the lines in a file, like this:
<resourcecount count="0" when="eq">
<tokens>
<concat>
<filterchain>
<tokenfilter>
<linetokenizer/>
</tokenfilter>
</filterchain>
<fileset file="${file}" />
</concat>
</tokens>
</resourcecount>
Now I want to refer to a ANT-property instead of the file. Is there a way to do this? I know about the solution to write the contents of the property into a file using <echo file="${temp.file}">${the.property.with.many.lines}</echo> and using the code above after. But I wonder if there is a solution that works without a temporary file.
A propertyresource element may used in place of the fileset as follows:
<property name="lines"
value="line01${line.separator}line02${line.separator}line03"/>
<target name="count-lines">
<resourcecount property="line.count" count="0" when="eq">
<tokens>
<concat>
<filterchain>
<tokenfilter>
<stringtokenizer delims="${line.separator}" />
</tokenfilter>
</filterchain>
<propertyresource name="lines" />
</concat>
</tokens>
</resourcecount>
<echo message="${line.count}" />
</target>
Output
count-lines:
[echo] 3
BUILD SUCCESSFUL
Total time: 0 seconds
I would like to build two versions of my Androidapplication using an Apache ant file. The problem is, that both versions are identical except the advertisement in the lite version. I read about using Configurations with ant to build debug versions.
The following class defines some constants that can be referenced within the application.
public class Config {
// Whether or not to include logging in the app.
public final static boolean LOGGING = true;
}
And here is an example on how to use this constants to determine if logging is enabled or not.
if (Config.LOGGING) {
Log.d(TAG, "[onCreate] Success");
}
Now i can enable and disable logging in my properties file.
# Turn on or off logging.
config.logging=true
That does not work, because before using this config I have to create a second config file and use filterset and copy.
public class Config {
// Whether or not to include logging in the app.
public final static boolean LOGGING = #CONFIG.LOGGING#;
}
That's pretty easy, but how I could use this to build two versions of my application with and without advertisement. And how could I change the package names using ant, so the android market would accept both packages (Full and Lite).
Thank you, for your suggestions, but I still have some problems.
I managed to write some basic targets that cleanup my builds and copy all files needed to build the application in two folders /full and /lite. So I have two directories with the same content. Now I rename all matches of the applications package name in all *.java files and the AndroidManifest file (target prepare).
To really build two different version I would now have to include the code from my first post. But how do I have to do this and how can I build both versions in the release target and write the resulting *.apk files into the build directoy?
Finally ... Would that be all I have to do to build running *.apks that would be accepted by the android market?
<?xml version="1.0" encoding="UTF-8"?>
<project name="my.application" default="help" basedir=".">
<!-- Load the custom property files -->
<property file="build.properties" />
<property file="passwords.properties" />
<!-- Set global properties for this build -->
<property name="my.application.pkg" value="my.application"/>
<property name="my.application.pkg.full" value="my.application.full"/>
<property name="my.application.pkg.lite" value="my.application.lite"/>
<property name="my.application" location="."/>
<property name="my.application.build" location="build"/>
<property name="my.application.src" location="src"/>
<property name="my.application.res" location="res"/>
<property name="my.application.gen" location="gen"/>
<property name="my.application.full" location="full"/>
<property name="my.application.full.src" location="full/src"/>
<property name="my.application.full.res" location="full/res"/>
<property name="my.application.full.gen" location="full/gen"/>
<property name="my.application.full.build" location="full/build"/>
<property name="my.application.lite" location="lite"/>
<property name="my.application.lite.build" location="lite/build"/>
<property name="my.application.lite.src" location="lite/src"/>
<property name="my.application.lite.res" location="lite/res"/>
<property name="my.application.lite.gen" location="lite/gen"/>
<!-- Create and update the local.properties file -->
<loadproperties srcFile="local.properties" />
<!-- Load the ant.properties file -->
<property file="ant.properties" />
<!-- Load the project.properties file -->
<loadproperties srcFile="project.properties" />
<!-- Quick check on sdk.dir. -->
<fail
message="sdk.dir is missing."
unless="sdk.dir" />
<!-- Version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
<target name="release" depends="report, prepare">
<echo>Building the target!</echo>
</target>
<target name="prepare" depends="cleanup" >
<!-- Copy the Manifest.xml to the full copy -->
<copyfile src="${my.application}/AndroidManifest.xml"
dest="${my.application.full}/AndroidManifest.xml" />
<!-- Copy the source files to the full copy -->
<copy todir="${my.application.full.src}" overwrite="true">
<fileset dir="${my.application.src}" />
</copy>
<!-- Copy the resources to the full copy -->
<copy todir="${my.application.full.res}" overwrite="true">
<fileset dir="${my.application.res}" />
</copy>
<!-- Copy the generated to the full copy -->
<copy todir="${my.application.full.gen}" overwrite="true">
<fileset dir="${my.application.gen}" />
</copy>
<!-- Replace the package name in the full manifest file -->
<replaceregexp file="${my.application.full}/AndroidManifest.xml"
match='package="(.*)"'
replace='package="${my.application.pkg.full}"'
byline="false" />
<!-- Change the package name in all Java files -->
<replaceregexp flags="g" byline="false">
<regexp pattern="${my.application.pkg}" />
<substitution expression="${my.application.pkg.full}" />
<fileset dir="${my.application.full.src}" includes="**/*.java" />
</replaceregexp>
<!-- Copy the Manifest.xml to the lite copy -->
<copyfile src="${my.application}/AndroidManifest.xml"
dest="${my.application.lite}/AndroidManifest.xml" />
<!-- Copy the source files to the lite copy -->
<copy todir="${my.application.lite.src}" overwrite="true">
<fileset dir="${my.application.src}" />
</copy>
<!-- Copy the resources to the lite copy -->
<copy todir="${my.application.lite.res}" overwrite="true">
<fileset dir="${my.application.res}" />
</copy>
<!-- Copy the generated to the lite copy -->
<copy todir="${my.application.lite.gen}" overwrite="true">
<fileset dir="${my.application.gen}" />
</copy>
<!-- Replace the package name in the lite manifest file -->
<replaceregexp file="${my.application.lite}/AndroidManifest.xml"
match='package="(.*)"'
replace='package="${my.application.pkg.lite}"'
byline="false" />
<!-- Change the package name in all Java files -->
<replaceregexp flags="g" byline="false">
<regexp pattern="${my.application.pkg}" />
<substitution expression="${my.application.pkg.lite}" />
<fileset dir="${my.application.lite.src}" includes="**/*.java" />
</replaceregexp>
</target>
<!-- Deletes all directories, not needed anymore after compiling the source files -->
<target name="cleanup">
<!-- Delete the full version build dir -->
<delete dir="${my.application.full}"/>
<!-- Delete the lite version build dir -->
<delete dir="${my.application.lite}"/>
<!-- Delete the *.apk file -->
<delete file="my.application.full.apk"/>
<!-- Delete the *.apk file -->
<delete file="my.application.lite.apk"/>
</target>
</project>
There are a number of ways in which you could achieve what you require.
Here are a couple of ideas that I have used in the past,
1) Have two application 'heads' that pull in a common Android library.
Each head initializes static data that sets up the library to behave as either the lite or the full version of your application.
This has the advantage that you can perform the build from Eclipse projects as well as with Ant.
2) Have two seperate build targets that share common build targets to create two seperate apk files.
In the Ant build script have it build two versions of the APK.
One that is the full version and then the other which builds the lite version.
The difference between the two targets are that they build using slightly different files (either by copying, directing to diferent directories or modifying with scripts).
This can all be done in Ant using targets and properties.
If at the top level of your build you have a release target depending on two other targets.
e.g.
<target name="release"
depends="release-Full, release-Lite">
</target>
<target name="release-Full">
<ant antfile="thisbuild.xml" inheritAll="true" target="full">
<property name="MyCustomProperty" value="Full" />
</ant>
</target>
<target name="release-Lite">
<ant antfile="thisbuild.xml" inheritAll="true" target="lite">
<property name="MyCustomProperty" value="Lite" />
</ant>
</target>
You can then use these targets and properties to modify your build to do whatever you require to build each of the APK files.
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}