4

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!

FanOfTamago
  • 120
  • 1
  • 6
  • It seems to be that unzip task does not support expression like you post. May be you should unzip archive to temp folder and then copy files in refresh mode (with help of present condition) to destination folder – Alex K Oct 18 '11 at 10:41
  • Appreciate the thought. As a last resort I will fully unzip the archive, but since sometimes these archives are large (and just for the sake of elegance in general) I was hoping to avoid that. – FanOfTamago Oct 18 '11 at 14:37
  • I see. I've bookmarked your question. May be you should run unzip as command with -f option (freshen existing files)? I mean that you can use `exec` task: http://ant.apache.org/manual/Tasks/exec.html – Alex K Oct 18 '11 at 14:41

3 Answers3

2

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>
igor
  • 5,351
  • 2
  • 26
  • 22
  • I think this is the better solution. It works! However you could have explain that "dirs" attribute, specify how many nested dirs will be removed from the result. – Pavoletto May 23 '19 at 13:22
2

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>
FanOfTamago
  • 120
  • 1
  • 6
1

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.

Alex K
  • 22,315
  • 19
  • 108
  • 236
  • The problem is I don't want to freshen the existing files. I want to extract the matching files for backup purposes. So, let's say the zip file contains A, B and C. Now let's say my source directory (outside the zip) contains A and C. I want to extract A and C from the zip file into files A.backup and C.backup. You can see from my Question how I have the globmapper for that purpose and this technique works great with filesets in general. If you see a way to accomplish this using exec and the unzip process, please let me know! – FanOfTamago Oct 18 '11 at 15:57
  • Thanks; I see what you are saying but took another approach to avoid using exec. See the other answer. I appreciate your brainstorming on this with me, though! – FanOfTamago Oct 19 '11 at 16:33