Ant unzip task and only extracting files based on another directory

6.6k views Asked by At

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!

3

There are 3 answers

0
FanOfTamago On BEST ANSWER

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="&#xA;">
        <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~~~~&#xA;${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>
1
igor On

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>
2
Alex K On

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.