How do you extract from a binary file created with Ant <concat>? - ant

I have a binary file that was created with the Ant <concat> task:
<target name="bun.create">
<concat destfile="final.bun" binary="yes">
<filelist dir="scripts/" files="script.sh"/>
<filelist dir="working/" files="files.tgz"/>
</concat>
<chmod file="final.bun" perm="+x"/>
</target>
I have the final.bun file and am wondering how I can extract the script.sh and files.tgz from it, without executing it? I know the unzip command doesn't work.

I don't think there's any way to do this - at least not easily. I'm sure there are some old Unis heads who can use the dd utility to do this, but that is still a hack. What you have done is create a file format that doesn't really exist. It's like concating together a Word document with an Excel document.
In fact, I'm not even sure if the <concat> task wouldn't shred the binary file into an incomprehensible mess as it was trying to concatenate it.
If you must put both files together, use the <zip/>, or <tar/> task to combine both files together. Yes, I know that files.tgz is already a compressed archive, but this would be the best way to put those two files together.

Related

Replace a file in zip using Ant despite of timestamp

I want to replace 1-2 files in a huge archive using zip task (or any other ANT task that can do this). I know passing update=true parameter can do it but it is only if new file has grater timestamp than old file. I want to make sure that the file gets replaced even though it has old timestamp as compared to the file in existing archive.
I have gone through several posts where they suggest unzip-replace-rezip thing. However I want to avoid this if possible because my archive is huge (in GBs). Is there any other way which has minimum performance impact?
Other way I found was using zipfileset task as follows:
<zip destfile="tmp.jar">
<zipfileset src="src.jar">
<exclude name="abc.class" />
</zipfileset>
<zipfileset dir="${basedir}/myclasses" includes="abc.class" />
</zip>
<move file="tmp.jar" tofile="src.jar" />
Does this task do the same as unzip-delete-add-rezip for entire archive? Or is it more efficient in terms of time?

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}"/>

Multiple configuration files for the ProGuard Ant task

I am using the ProGuard ant task, and everything is great, except that my ProGuard configuration file is huge. Also, different tasks use different ProGuard configuration files, and there is a lot of copy-pasting that I would like to refactor into separate .pro files.
<taskdef resource="proguard/ant/task.properties" classpath="C:/Program Files/proguard4.7/lib/proguard.jar"/>
<target name="obfuscated_jar" depends="raw_jar">
<proguard configuration="core.pro lib1.pro lib2.pro">
<outjar path="prog_obfuscated.jar"/>
</proguard>
</target>
The above doesn't work, because it treats the multiple .pro files as one big filename. I'm a known idiot w.r.t. ant, am I missing something obvious? Thanks!
You can create a single main .pro file that contains -include options pointing to your actual .pro files.
This answer isn't great, but it works...
<taskdef resource="proguard/ant/task.properties" classpath="C:/Program Files/proguard4.7/lib/proguard.jar"/>
<target name="obfuscated_jar" depends="raw_jar">
<concat destfile="proguard_temp.pro">
<filelist dir="." files="core.pro,lib1.pro,lib2.pro"/>
</concat>
<proguard configuration="proguard_temp.pro">
<outjar path="prog_obfuscated.jar"/>
</proguard>
<delete file="proguard_temp.pro"/>
</target>
Looks like only one file allowed in configuration attribute.
Edited
And attributes allowed only on <proguard> element. I have another possible solution. Try to concatenate your config-files into one with Ant concat-task and pass this temporary file to <proguard configuration=""> attribute.
Also, it's possible to modify ProGuardTask-class to accept several files as arguments and concatenate them later. And same result could be achieved with Ant macrodef .

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.

How can I post-process files compiled using the Ant javac task?

I need the list of files that were compiled during this run. I want to feed this list to a subsequent post-processing step.
I have found an option to list (see listfiles option) the files compiled during this run, but it seems only good for displaying the list on console.
Any idea?
Edit: I am talking about incremental compiles, so taking a fileset of the build folder is not an option.
Edit: One idea seems to be custom logger but I am still looking for something simpler
Edit: Another idea is to use depend selector with FileSet before javac and somehow keep the list in memory, to be used after javac has executed
You simply can form a fileset about all class-files in the target-directory of the javac.
Edit: After the clarification I have to adjust my answer. I didn't such thing yet, but I would try my luck with selectors. The modified-selector looks like the one you want - a fileset of all class-files in a directory, that have changed since the last run. Here is a code-snippet:
<fileset dir="${build}">
<filename name="**/*.class"/>
<modified/>
</fileset>
It does not directly post-process the output of the javac-task, but should solve your problem.

Resources