How to copy all files from multiple directories into a single directory using Ant - ant

I have a folder structure like
ant/
test1/
images/
1.png ...
test2/
images/
121.png ...
test3/
images/
173.gif ...
I want to read all the images from different different images folders and put them into one image folder under the ant folder.
I have written this code
<project name = "java-ant project" default = "copy-file">
<target name="copy-file">
<copy todir="D:/ant/images">
<fileset includes="**/images/" dir="D:/ant/"/></copy>
</target>
</project>
This copies successfully into the images folder, but keeps the source folder structure.
Like:
ant/
images/
test1/
images/
1.jpg ...
test2/
images/
121.jpg ...
My desired output is:
ant/
images/
1.jpg
121.png
173.gif
...

You can use something like this:
<property name="src.dir" value="D:/ant/"/>
<property name="dest.dir" value="D:/ant/images"/>
<copy todir="${dest.dir}">
<fileset dir="${src.dir}" includes="**/images/*">
<type type="file"/>
</fileset>
<mapper type="flatten" />
</copy>
The flatten mapper is the key part.
The type="file" element ensures that only files are copied. Without that you might also see (empty) directories copied.

Related

Copying only files which have another file as a sibling [based on extension]?

I am trying to use ANT to copy some files of a C++ build into another directory.
The output of the build looks like this:
/Build
/LibA
LibA.lib
LibA.pdb
/LibB
LibB.lib
LibB.pdb
/ProjA
myexe.exe
myexe.pdb
/Foo
foo.exe
foo.pdb
/...
Now, I would like to copy all *.exe files and their *.pdb files to another directory (but not the *.pdb files of the libs).
I tried with:
<copy todir="outdir">
<fileset dir="Build">
<include name="**/*.exe" />
<include name="**/*.pdb" />
</fileset>
</copy>
However, then I will also get the *.pdb files inside the LibA, LibB, ... folders.
Is there any way I can only copy the pdb-files which have an *.exe-file in the same directory as their sibling?
Unfortunately, the folders are not named in any way that would allow using wildcards based on the folder name.
Of course, I could list each file individually, such as:
<include name="ProjA/*.pdb" />
<include name="Foo/*.pdb" />
<!-- ... -->
However, I am thinking that maybe there is an elegant way where I can specify "copy all *.exe files and all *.pdb files which have an *.exe file next to them".
You could use the <present> selector to find the "sibling" files, something like this:
<copy todir="outdir">
<fileset dir="Build" includes="**/*.pdb">
<present targetdir="Build">
<mapper type="glob" from="*.pdb" to="*.exe" />
</present>
</fileset>
<fileset dir="Build" includes="**/*.exe" />
<flattenmapper />
</copy>
This will only copy the .pdb files with matching .exe files.
To keep it simple, use a separate fileset for the exe files.
The flatten mapper is only needed if you want to copy just the files ignoring the directory structure in the source.

Ant unzip task and only extracting files based on another directory

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.

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 Zip Extracted Parent Directory

I have several zip files that I need to unzip within an Ant target. All the zip files are in the same directory, and have the same internal directory and file structure.
So I am using the following snippet to unzip all the zip files in the directory, but each zip file does not contain a parent folder at the root, so each successive zip file is unzipped and overwrites the previous files.
<unzip dest="C:/Program Files/Samsung/Samsung TV Apps SDK/Apps">
<fileset dir=".">
<include name="**/*.zip"/>
</fileset>
</unzip>
Is there a better way to unzip a group of files, and create a directory to unzip them to that is based on the zip file name?
So, if the zip files are:
1.zip
2.zip
3.zip
then the content of each will be extracted to:
1/
2/
3/
Thanks
One solution might be to use the ant-contrib 'for' and 'propertyregex' tasks to do this:
<for param="my.zip">
<fileset dir="." includes="**/*.zip" />
<sequential>
<propertyregex property="my.zip.dir"
input="#{my.zip}"
regexp="(.*)\..*"
select="\1"
override="yes" />
<unzip src="#{my.zip}" dest="${my.zip.dir}" />
</sequential>
</for>
The 'propertyregex' strips the .zip extension from the zip file name to use as the target directory name.
Without ant-contrib:
https://stackoverflow.com/a/12169523/957081
<!-- Get the path of the war file. I know the file name pattern in this case -->
<path id="warFilePath">
<fileset dir="./tomcat/webapps/">
<include name="myApp-*.war"/>
</fileset>
</path>
<property name="warFile" refid="warFilePath" />
<!-- Get file name without extension -->
<basename property="warFilename" file="${warFile}" suffix=".war" />
<!-- Create directory with the same name as the war file name -->
<mkdir dir="./tomcat/webapps/${warFilename}" />
<!-- unzip war file -->
<unwar dest="./tomcat/webapps/${warFilename}">
<fileset dir="./tomcat/webapps/">
<include name="${warFilename}.war"/>
</fileset>
</unwar>

Ant - copy only file not directory

I need to copy all files in a folder except directory in that folder using Ant script.
Im using below script to do that.
<copy todir="targetsir">
<fileset dir="srcdir">
<include name="**/*.*"/>
</fileset>
</copy>
But it copies all files and directory in that folder.
how to restrict/filter directory in that folder?
thanks,
I think there is an easier way.
flatten="true" - Ignore directory structure of source directory, copy all files into a single directory, specified by the todir attribute. The default is false.
Do you mean that srcdir conatins sub-directories, and you you don't want to copy them, you just want to copy the files one level beneath srcdir?
<copy todir="targetsir">
<fileset dir="srcdir">
<include name="*"/>
<type type="file"/>
</fileset>
</copy>
That should work. The "**/*.*" in your question means "every file under every sub directory". Just using "*" will just match the files under srcdir, not subdirectories.
Edited to exclude creation of empty subdirectories.
I do not have enough reputation to comment, so I'm writing new post here. Both solutions to include name="*" or name="*.*" work fine in general, but none of them is exactly what you might expect.
The first creates empty directories that are present in the source directory, since * matches the directory name as well. *.* works mostly because a convention that files have extension and directories not, but if you name your directory my.dir, this wildcard will create an empty directory with this name as well.
To do it properly, you can leverage the <type /> selector that <fileset /> accepts:
<copy todir="targetsir">
<fileset dir="srcdir">
<include name="*"/>
<type type="file"/>
</fileset>
</copy>
Can you try
<copy todir="targetsir">
<fileset dir="srcdir">
<include name="*.*"/>
</fileset>
</copy>
** is used to match a directory structure.
<copy todir="targetsir" includeEmptyDirs="false">
<fileset dir="srcdir">
<include name="*"/>
</fileset>
</copy>
If your folder has many subdirectories and you don't want them to be copied (if you want only files) try this..
<target name="copy">
<copy todir="out" flatten="true">
<fileset dir="tn">
<filename name="**/cit.txt" />
</fileset>
</copy>
</target>
The secret is to use not fileset but dirset instead.

Resources