Changing properties file inside a jar with Ant - ant

I have a settings in a properties file located within a jar that I wish to alter at build-time using ant. Ideally if I am able to search for a specific text in the properties file and replace it easily, I would like to do that but isn't sure how.
So I was thinking I can overwrite it with another properties file that has the new settings already predefined. The jar already exists in my directory and the hierarchy of my jar is as follows:
food.jar
/com/food/donut.properties
some file...
some file...
If I had another donut.properties file with a different setting located in a different directory. How can I overwrite it with ant?
Thanks for the help, much appreciated!
EDIT:
With the following code I was able to copy the properties file into the jar. But whenever I attempt to copy the new properties file into the same directory of the old properties file, it does not get replaced. (i.e. If i change the prefix to 'com' i can see the new properties file being inserted into the jar. If the prefix is changed to com/food, nothing is replaced. What am i doing incorrectly?
<jar destfile="${dist.dir}/food.jar" update="true">
<zipfileset file="donut.xml" prefix="com/food/" />
</jar>

needs Ant 1.8.x
Step 1)
edit your propertyfile, multiple nested entry elements possible :
<propertyfile file="/path/to/propertyfile/foo.properties">
<!-- will change an existing key named 'somekey' with the value 'foo' inplace -->
<entry key="somekey" value="foo"/>
</propertyfile>
see Ant Manual propertyfile
Step 2)
update your jar with the altered propertyfile :
<jar destfile="/path/to/your/foo.jar" update="true">
<fileset dir="/path/to/propertyfile" includes="*.properties"/>
</jar>
for renaming use nested mapper like that :
<jar destfile="/path/to/your/foo.jar" update="true">
<mappedresources>
<fileset dir="." includes="*.properties"/>
<globmapper from="*.properties" to="/com/xml/*.properties"/>
</mappedresources>
</jar

The ant documentation of the jar task says:
The update parameter controls what happens if the JAR file already
exists. When set to yes, the JAR file is updated with the files
specified. When set to no (the default) the JAR file is overwritten.
An example use of this is provided in the Zip task documentation.
Please note that ZIP files store file modification times with a
granularity of two seconds. If a file is less than two seconds newer
than the entry in the archive, Ant will not consider it newer.
You might need to make sure the properties file is newer than the one in the jar file. Using the touch task could solve the problem.
Or you might just unzip the jar in the temp directory, copy the properties file with the copy task and its overwrite attribute set to true, and re-jar the contents of the temp directory.

Related

Reading property names from a properties file before loading it (ANT)

I need to retrieve all the properties' names from a properties file before loading it (using Ant)
I'll go into detail to explain the whole process:
A first properties file (let's name it as a.properties) is read and
all its properties loaded as project's properties.
#a.properties's contents
myvar1=1
myvar2=someTextHere
A second file (let's say b.properties) has to be loaded on the
project. Some already-set properties can also be contained in this
second file, so what we have to do is to update such variables with
the value found on it (by means of the ant-contrib's var target)
#b.properties's contents
myvar1=2 #updated value for a property that's is already set on the project
myvar3=1,2,3,4,5,6
So the expected subset (from a ANT project's properties perspective)
of property/value pairs would be:
myvar1=2
myvar2=someTextHere
myvar3=1,2,3,4,5,6
We cannot change the order in which those files are loaded on the project, which would be the easiest way of solving the issue (because of the behavior adopted by Ant when setting's properties)
Any feedback will be highly appreciated.
Regards
I assume that you need to read properties from different files before you build your source code
<target name=-init-const-properties description="read all properties required">
<propertyfile file="AbsolutePathToPropertyFile" comment="Write meaningfull
about the properties">
<entry value="${myvar1}" key="VAR1"/>
<entry value="${myvar2}" key="VAR2"/>
</propertyfile>
</target>
Note: you need to add proper AbsolutePathToPropertyFileand comment if required
In the target -init-const-properties you can add as many files you want to read and use this target as dependent target in which you going to use these property values. hope this will answer your question
I recommend having a standard file for build defaults called "build.properties". If you need to override any settings, then create an optional file called "build-local.properties".
My advice is to keep build logic simple. Using the ant-contrib extension to make properties act like variables is rarely needed in my experience.
Example
├── build-local.properties
├── build.properties
└── build.xml
Running the project produces the following output, where the value "two" is substituted:
$ ant
build:
[echo] Testing one, dos, three
Delete the optional file and it goes back to default values:
$ rm build-local.properties
$ ant
build:
[echo] Testing one, two, three
build.xml
The secret is the order in which the property files are loaded. If they don't exist then they don't create properties.
<project name="demo" default="build">
<property file="build-local.properties"/>
<property file="build.properties"/>
<target name="build">
<echo message="hello ${myvar1}, ${myvar2}, ${myvar3}"/>
</target>
</project>
build.properties
myvar1=one
myvar2=two
myvar3=three
build-local.properties
myvar2=dos
Finally, the approach I followed was to specify the second properties file (b.properties) from the command line:
ant <my_target> -propertyfile b.properties
So that's work fine to me...
Thanks all of you for your help.

Zip task in Ant - incuding empty and non-empty subdirectories

Alright, I've been going slightly insane with this one - what bugs me more is that I'm sure a few years back I'd done something similar to what I'm trying to do now.
Let me say right off the bat, I am using ANT version 1.8.2, so I don't have the 1.6.2 issues with zip and empty folders. Most of my searching seems to bring up the 1.6.2 issue.
So, here's my build.xml snippet:
<target name="zip" depends="jar">
<echo>Creating zip file...</echo>
<zip destfile="${dist}/${zipfilename}">
<zipfileset dir="${dist}" includes="${jarfilename}" />
</zip>
<echo>...complete</echo>
</target>
This does what it's supposed to do, take the jar file from the {dist} directory, and put it in the zip so that the {dist} directory is NOT maintained - ie: the jar file gets extracted to wherever the zip file is.
HOWEVER, I would like to know how to do the following:
include a {config} directory and ALL the files within it except for one called "test-config.xml"
include two separate empty directories - say {subdir1} and {subdir2}. They may or may not have files in them, but I do NOT want ANY files in those directories when they get zipped.
For that second part with the empty directories, I'm perfectly content having the zip task create those in the zip itself without necessarily creating them on the local file system. In fact, the ideal would be if they'd be in the zip file and NOT be on the local file system - but I'll take whatever method I can get that works.
So, my local file system will look like so:
dist/MyJar.jar
config/config1.xml
config/config2.xml
config/test-config.xml
subdir1/ (may or may not exist and may or may not have files in it)
subdir2/ (may or may not exist and may or may not have files in it)
I want the ZIP file, when unzipped, to result in:
MyJar.jar
config/config1.xml
config/config2.xml
subdir1/
subdir2/
How do I accomplish this? I've tried variants of fileset, dirset, zipfileset, and am failing at every attempt. The best I've managed is to get the files in the {config} directory to get extracted as if the {config} directory doesn't exist... the hierarchy for that is NOT maintained, but I WANT it to be.
Here's one way you can use zipfileset to handle the config directory:
<zipfileset dir="." includes="config/*" excludes="config/test-config.xml"/>
The only way I can think of getting empty empty folders into the zip is to create them on the file system, add them using a zipfileset and then delete them once you have created the zip file.
Here is a fragment that does what you need (NOTE: I am using folder and file names based on your example; you can replace these with property references as needed):
<tempfile property="temp.file" destDir="." prefix="foo"/>
<mkdir dir="${temp.file}/subdir1"/>
<mkdir dir="${temp.file}/subdir2"/>
<zip destfile="${dist}/${zipfilename}">
<zipfileset dir="${dist}" includes="${jarfilename}"/>
<zipfileset dir="${temp.file}" includes="*"/>
<zipfileset dir="." includes="config/*" excludes="config/test-config.xml"/>
</zip>
<delete dir="${temp.file}"/>

Ant: Create directory containing file if it doesn't already exist?

Basically, I get a path like "C:\test\subfolder1\subfolder2\subfolder3\myfile.txt", but it's possible that subfolders 1-3 don't exist already, which means I'd get an exception if I try to write to the file.
Is there a way to create the directory structure the target file is in, either by using some task that creates the structure when it outputs to the file and then deleting the file, or by parsing the directory part of the path and using the mkdir task first?
Ant will create the full tree of directories for you when you use the <mkdir> task. So you just need to use the <dirname> task to get the directory name from the file name.
<dirname property="directoryProperty" file="${filePathProperty}"/>
<mkdir dir="${directoryProperty}" />
The first line extracts the directory portion of your file path and stores it in the directoryProperty property. The second line creates the directory (and any parent directories that don't exist).
This task works well
<mkdir dir="${file}/../"/>
Sometimes we could have an alternate choice, using touch task
<touch file="${file}" mkdirs="true" verbose="true"/>
This task should do the job but would have a side effect to create the file with zero size
Just make failonerror=false to avoid the error to stop the whole logic.
<delete includeemptydirs="true" failonerror="false">
<fileset dir="${builder-base.dir}" includes="**/*"/>
</delete>
Using the
<mkdir dir="${dir}"/ >
inside your <target> tag should work, but I am not sure what else you want to do along with mkdir?
I'm not 100% sure it'll work but you might be able to do something like the following to make the parent directory you're after:
<mkdir dir="${file}/../"/>
If that doesn't work straight off then it might be worth defining a property using the location syntax before creating a directory with the new property:
<property name="dir" location="${file}/../" />
<mkdir dir="${dir}" />
Well-behaved Ant tasks are generally expected to create any necessary directory structures unless there is a good reason not to.
Are you writing a task? If so you should add the directory creation logic to your task. If you are getting the task from a third party you should point this fact out to them and have them fix their task. Failing that Dan's solution should work.

ANT: How to call target for all build.xml in subdirectories?

How do you call a specific target in all build.xml located in all subdirectories using wildcards (ie not hard coding the subdirectory names)? The below answer is hardcoded. Is there a way to do it without hardcode?
Similar to this question: Pass ant target to multiple build.xml files in subdirectories
Use the Ant subant task like this:
<subant target="sometarget">
<fileset dir="." includes="*/build.xml" />
</subant>
If you include an "inheritall" attribute (same as how it's used in but defaults the opposite), you can share all your current project's properties and everything too. This also makes it very easy to overwrite tasks defined in your main build.xml file if you need to.
Read more about it here.
I'll setup different properties within my build.properties file. I use these to dynamically build paths in my targets.
Define the location of your build.properties file:
<!-- all properties are in build.properties -->
<property file="build.properties" />
Use those properties in your targets:
Properties in the build properties are similar to setting up an .ini file:
project.rootdir=c:/Deploy
project.tempbuilddir = c:/Deploy/Temp/Inetpub
project.builddir=c:/Deploy/Inetpub
# Build prefix will be added to that tags urls (.../tags/${project.buildprefix}Build_${today.date})
project.buildprefix=ACA_
I guess you could use a dynamic file as your properties file, if necessary, as long as you define the proper path to the file. You could point it to a server-side file to dynamically write your properties file (ColdFusion, PHP, JSP, whatever).
I've used ant-contrib's foreach task to do something like this.
http://ant-contrib.sourceforge.net/tasks/tasks/foreach.html
Sounds like a perfect candidate for the <subant> task.

How can I exclude a list of files (held in a file) from an Ant fileset?

Is there a way to have an Ant Fileset->IncludesFile attribute take a property file OR any other file that contains a list of Java class files to exclude?
Eg:
File A.properties OR A.java contains listing
abc.class
mno.class
xyz.class
Is there a way to say to point excludesFile to file A.properties.
<fileset dir="...">
<excludesFile file="A.properties" />
</fileset>
The behavior that I want is when Java runs, it excludes the Java files listed in this file (A.properties)
Hmm...not sure if it's case sensitive. The documentation at http://ant.apache.org/manual/Types/fileset.html shows "excludesfile", all lowercase, as with other ant directives.
I'm not sure exactly what you are asking. If you have a fileset which is including files you would like to exclude, and you want to specify that list of files to exclude in an external file, "excludesfile" is the correct way to do it.

Resources