Ant unzip task and only extracting files based on another directory - ant

I have a zip file and, separately, a directory that contains some files. From the zip file I'd like to extract only those files that exist in the directory (performing a filename transformation on the files as they are being extracted..basically, I'm making backups of those files).
There is no problem doing something similar with a <copy> that has a fileset with a <present> element, but it doesn't seem to be working for me with unzip:
<unzip src="${cur.srcdir.live}" dest="${cur.srcdir.archive-files.dir}" overwrite="true">
<fileset dir=".">
<present present="both" targetdir="${cur.srcdir}" />
<type type="file" />
</fileset>
<globmapper from="*" to="*.${backup.suffix}" />
</unzip>
Has anyone done something like this before? This is Ant 1.8.0. Thanks!

I was able to solve my problem by "faking" the <present> selector that can be used in <copy>. Here's how:
First I used pathconvert to create a list of the files in my folder:
<pathconvert property="extract.list" pathsep="
">
<path>
<fileset dir="${extract.src.dir}" includes="${extract.src.dir.relpath}">
<type type="file" />
</fileset>
</path>
<map from="${extract.src.dir}\" to="" />
</pathconvert>
Notice the user of a map to have the list be relative paths instead of absolute paths. Plus, the delimiter is a newline.
Then this list gets written to a file:
<echo file="${props.tmp.file}" message="~~~~noop~~~~
${extract.list}" append="false" />
I put that "nooop" entry in there so that the file always has at least one line. This is important because of our next step where we use this as an includesfile. If the includesfile is empty, Ant interprets that as "allow anything"...but we want to make sure that an empty list results in nothing getting extracted from the zip.
Last step is to extract from the zip using our temp file from above as an includes file. The globmapper renames the files upon extraction, to the appropriate backup names:
<unzip src="${extract.archive}" dest="${extract.dest.dir}" overwrite="true">
<patternset>
<includesfile name="${props.tmp.file}" />
</patternset>
<globmapper from="*" to="*.${backup.suffix}" />
</unzip>

Adding this here in case someone needs to change the directory structure on extraction. I've spent so much trying to make this working. Ant Unzip task accepts cutdirsmapper.
<unzip dest="${build.dir}/packages">
<fileset dir="${src.dir}/packages" includes="*.pkg" />
<!-- Exctract build folder contents also moving one level up. -->
<cutdirsmapper dirs="1" />
<patternset>
<include name="build/" />
</patternset>
</unzip>

You can try calling unzip command via exec task.
The sample that I checked on Windows that refresh only changed files in dest.folder:
<property name="zip.file_name" value="Archive.zip"/>
<property name="src.folder" value="d:\"/>
<property name="dest.folder" value="d:\55"/>
<target name="unzip">
<echo>unzip -fo ${src.folder}${zip.file_name}</echo>
<exec dir="${dest.folder}" executable="cmd.exe" output="${src.folder}operation_result.txt">
<arg line="/c unzip -fo ${src.folder}${zip.file_name}"/>
</exec>
</target>
If you want to stay your original files you can use this command:
<arg line="/c unzip -foB ${src.folder}${zip.file_name}"/>
In case using -B parameter your original files (stored in folder) will be renamed - the tilde symbol will be appended. You get two sets of files - extracted from archive and old original files.
After that you can rename files with the help of move task.

Related

No overwrite on Ant UNZIP

I want to unzip a file, but if some file exists, this mustn´t be replaced.
I tried this:
<unzip src="compress.zip" dest="dirTo" overwrite="false">
<patternset>
<include name="dirFrom/**"/>
</patternset>
"dirFrom", is the name from the directory IN the compress file, what I want to extract. I use "overwrite" to false, but it doesn´t work, and it ovewrites.
I have a directory, and this has different subdirectories. I want one of those subdirectories, with it´s files and sub-subdirectories.
I found how to do it.
1st, I extract everything to auxiliar directory.
2nd, I make a loop, to compare file by file, if that file exists.
3rd, If the file doesn´t exists, I copy it.
<unzip src="compressFile.zip" dest="dirAux">
<patternset>
<include name="mySubDir/**"/>
</patternset>
</unzip>
<fileset id="fileset1" dir="dirAux/mySubDir" />
<property name="newContentMySubDir" refid="fileset1"/>
<for param="nameFile" list="${newContentMySubDir}" delimiter=";">
<sequential>
<if>
<not><available file="${finalDir}/mySubDir/#{nameFile}" type="file"/></not>
<then>
<copy tofile="${finalDir}/mySubDir/#{nameFile}" file="dirAux/mySubDir/#{nameFile}"/>
</then>
</if>
</sequential>
</for>
Setting overwrite to false will only prevent to overwrite destination file if it is newer than source file. For more complex filtering, you have to use copy task with a zipfilset as it is explain in ant documentation (see unzip task -- in section Related tasks). For exemple, following code should not extract files from a zip file if they already exist in the destination directory (respecting source directories layout):
<copy todir="${target.dir}">
<zipfileset src="${zip.file}">
<patternset>
<include name="**/*.*"/>
</patternset>
<present targetdir="${target.dir}" present="srconly"/>
</zipfileset>
</copy>

Expanding * in Ant copy task

In ant copy task, in destination location there is a "random number" folder in the path. When i try to put a * in the path to handle it, Ant takes it literally, ie doesnt expand it, but creates a folder called "*" and copies there. How do I tell Ant to expand the * to actual folder name there (there is only 1 folder in there, so * wont expand to multiple folders)
<property name="dest" value="a/*/b/my.jar" />
<property name="src" value="my.jar" />
<copy file="${src}" tofile="${dest}" overwrite="true" verbose="true"/>
The copy task doesn't support wildcards in the tofile attribute. If the destination directory exists, but the destination file may not, then you can use a dirset to capture the directory. Something like:
<dirset dir="${basedir}" id="dest.dir">
<include name="a/*/b" />
</dirset>
<property name="dest" value="${toString:dest.dir}/my.jar"/>
<property name="src" value="my.jar" />
<copy file="${src}" tofile="${dest}" overwrite="true" verbose="true"/>
Instead of using the property helper (${toString:....}) syntax you might use the pathconvert task:
<pathconvert property="destdir" refid="dest.dir"/>
<property name="dest" value="${destdir}/my.jar"/>

Relocate contents of dynamic folder

I have a zip file which has one base folder inside it with other content inside that. I don't always know what that base folder is going to be called until I unzip it.
I'd like to move that base folder, and rename it at the same time, in ant - but can't seem to find out how. I've written code to extract the contents of the zip file to ${local.sdk.dir}/temp/ but from here i can't work out how to rename/move the extracted folder
<move todir="${local.sdk.dir}/${remote.sdk.file.name}">
<fileset dir="${local.sdk.dir}/temp/<WHAT_DO_I_PUT_HERE?>"></fileset>
</move>
also tried
<move todir="${local.sdk.dir}/${remote.sdk.file.name}" includeEmptyDirs="yes" verbose="true">
<fileset dir="${local.sdk.dir}/temp/" >
<include name="**/*" />
</fileset>
</move>
and played about with this, but closest I can get without ant throwing an error is to copy the contents of the temp dir, not the base folder within temp.
You can do all this in one step - copy from the zip file and rename the files changing the dir name as you copy. The copy task accepts a nested resource collection, so you can use a zipfileset to specify the files to copy directly from the zip file.
In order to rename the files as they are copied, you can use a mapper, which the copy task also takes as a nested element. In this case, a cutsdirmapper looks like the tool for the job.
So, if I've understood what you want to do correctly, something like this should work:
<copy todir="${local.sdk.dir}/${remote.sdk.file.name}">
<zipfileset src="${your.zip.file}" />
<cutdirsmapper dirs="1" />
</copy>
cutdirsmapper is only available in Ant 1.8.2 onward, so if you're using an earlier version, you could try a regexpmapper:
<regexpmapper from="[^/]*(.*)" to="\1" />
Similar to this question
<target name="relocate_sdk_folder">
<path id="sdk_folder_name">
<dirset dir="${local.sdk.dir}/temp/">
<include name="*"/>
</dirset>
</path>
<property name="sdk_folder_name" refid="sdk_folder_name" />
<echo message="renaming ${sdk_folder_name} to ${remote.sdk.file.name}" />
<move file="${sdk_folder_name}" tofile="${local.sdk.dir}/${remote.sdk.file.name}" />
</target>

Ant unzip task - how can I exclude the archive name from extracted hierarchy?

How can I exclude the archive name from the file hierarchy after an ant unzip task?
For example, once ant's run the unzip task in the folder C:\temp, I want all the files from the archive archive, but instead I get C:\temp\t\file.tmp.
Can I effectively exclude the base directory inside the archive?
Use a mapper specify how the files should look in the destination directory:
<unzip src="t.zip" dest="temp">
<globmapper from="t/*" to="*"/>
</unzip>
A better solution now is the cutdirsmapper:
<unzip src="t.zip" dest="temp">
<cutdirsmapper dirs="1"/>
</unzip>
I use:
<mapper type="flatten" />
See also https://www.safaribooksonline.com/library/view/ant-the-definitive/0596001843/ch04s10.html
The flatten mapper removes all path information from filenames.
For example in build.xml:
<target name="extract-xsd">
<unzip src="./cache/nl.packagename.example/xx/jars/somepackage.jar" dest="repository">
<mapper type="flatten" />
<patternset>
<include name="**/Example.xsd"/>
<include name="**/Example.wsdl"/>
</patternset>
</unzip>
</target>
As a result, the Example.xsd and Example.wsdl are put in the repository folder directly.

How do I build an Ant TarTask for this tar command?

tar zcvf Test.tar.gz /var/trac/test /var/svn/test
So far I have:
<target name="archive" depends="init">
<tar compression="gzip" destfile="test.tar.gz">
<tarfileset dir="/">
<include name="/var/trac/test" />
</tarfileset>
<tarfileset dir="/">
<include name="/var/trac/svn" />
</tarfileset>
</tar>
</target>
With debugging on, it always says "No sources found" so I'm a bit perplexed on what to do next.
There are several things here that can go wrong:
Are /var/trac/test and /var/svn/test files or directories? Real tar would work fine with both; your task - the way it's written right now - would only work with files but not folders.
Do you (or, rather, does Ant process) have adequate permissions?
<include> elements contain patterns, which are generally relative to base dir. You're specifying them as absolute.
I would rewrite the above as:
<target name="archive" depends="init">
<tar compression="gzip" destfile="test.tar.gz">
<tarfileset dir="/var/trac" prefix="/var/trac">
<include name="test/**" />
<include name="svn/**" />
</tarfileset>
</tar>
</target>
prefix allows you to explicitly specify the path with which files in Tar archive should begin.
/** within <include> tells Ant to take all the files from that folder and all its subfolders. If /var/trac/test and /var/svn/test are indeed files and not folders then you can omit that.

Resources