Split organization name into nested folders using ivy:retrieve - ant

In ivy I can set a retrieve pattern in order to copy all my dependencies somewhere I want to.
For example:
<ivy:retrieve pattern="${local-maven2-dir}/[organisation]/[module]/[revision]/[module]-[revision].[ext]" conf="compile" type="jar,bundle" sync="true"/>
I wonder is it possible to treat organization not as a folder, but as a set of nested folders, and keep in deepest folder (which is revision) the jar package, just like jars are stored in maven default repo.
So, basically I want to have jars located in paths like
com/yahoo/platform/yui/yuicompressor/2.4.7
and not like
com.yahoo.platform.yui/yuicompressor/2.4.7
PS: involving groovy scripting counts as a valid solution as well, it's just that I have no idea how can groovy be involved here.

Actually, it's quite easy and already documented in Ivy (look near the bottom of the page). You can use [orgPath]:
<ivy:retrieve conf="compile"
type="jar,bundle"
sync="true"
pattern="${local-maven2-dir}/[orgPath]/[module]-[revision].[ext]"/>

The following example uses groovy.
David W. offers a far simpler solution, relying on a new "orgPath" pattern token introduced in ivy 2.3.
Example
Produces the following output
├── build
│   ├── com
│   │   └── yahoo
│   │   └── platform
│   │   └── yui
│   │   └── yuicompressor
│   │   └── 2.4.7
│   │   └── yuicompressor-2.4.7.jar
│   └── rhino
│   └── js
│   └── 1.6R7
│   └── js-1.6R7.jar
├── build.xml
└── ivy.xml
build.xml
<project name="demo" default="retrieve" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:resolve/>
<ivy:cachepath pathid="build.path" conf="build"/>
</target>
<target name="retrieve" depends="resolve">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<ivy:artifactproperty conf="compile" name="index.[module].[artifact]" value="[module].[artifact]"/>
<ivy:artifactproperty conf="compile" name="[module].[artifact].organisation" value="[organisation]"/>
<ivy:artifactproperty conf="compile" name="[module].[artifact].module" value="[module]"/>
<ivy:artifactproperty conf="compile" name="[module].[artifact].artifact" value="[artifact]"/>
<ivy:artifactproperty conf="compile" name="[module].[artifact].revision" value="[revision]"/>
<ivy:artifactproperty conf="compile" name="[module].[artifact].ext" value="[ext]"/>
<ivy:artifactproperty conf="compile" name="[module].[artifact].cachefile" value="${ivy.cache.dir}/[organisation]/[module]/jars/[artifact]-[revision].[ext]"/>
<groovy>
modules = properties.findAll { it.toString().startsWith("index.") }
modules.each { key, value ->
def organisation = properties[value+".organisation"].replace(".","/")
def module = properties[value+".module"]
def artifact = properties[value+".artifact"]
def revision = properties[value+".revision"]
def ext = properties[value+".ext"]
def cachefile = properties[value+".cachefile"]
ant.copy(file:cachefile, tofile:"build/${organisation}/${module}/${revision}/${artifact}-${revision}.${ext}")
}
</groovy>
</target>
</project>
ivy.xml
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="build" description="Build dependencies"/>
<conf name="compile" description="Compile classpath"/>
</configurations>
<dependencies>
<!-- build dependencies -->
<dependency org="org.codehaus.groovy" name="groovy-all" rev="2.1.1" conf="build->default"/>
<!-- compile dependencies -->
<dependency org="com.yahoo.platform.yui" name="yuicompressor" rev="2.4.7" conf="compile->default"/>
</dependencies>
</ivy-module>

Related

ANT Ivy: How to retrieve a library and put its transitive dependencies in different folder

I am working on a project analysing libraries in Maven repo. I am using Ivy to retrieve the library(e.g. log4j) from Maven repo. But Ivy also downloads its transitive dependencies in the same folder! How do I separate them?
The secret is configuration mappings, a powerful concept in ivy. When downloading from an ivy repository, configurations allow you to configure different combinations of files that can be downloaded. For example you could specify you want just the module's published files, or the published files with all their dependencies. It's a very flexible capability.
When ivy downloads from Maven repositories it used the ibiblio resolver. Maven repositories do not support configurations so ivy makes them up and has a standard set which I have documented in more detail here:
How are maven scopes mapped to ivy configurations by ivy
Long story short when you specify a dependency the configuration mapping tells ivy which remote files to retrieve from the remote repository. I would advice you to always specify a configuration and gain more control. Once you understand configurations you understand ivy.
Examples
No configurations
Without a mapping all files associated with the remote Maven module are retrieved.
├── build.xml
└── lib
├── activation-1.1.jar
├── geronimo-jms_1.1_spec-1.0.jar
├── javaee-api-5.0-2.jar
├── log4j-1.2.17.jar
├── log4j-1.2.17-javadoc.jar
├── log4j-1.2.17-sources.jar
└── mail-1.4.3.jar
Build file:
<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:retrieve pattern="lib/[artifact]-[revision](-[classifier]).[ext]">
<dependency org="log4j" name="log4j" rev="1.2.17"/>
</ivy:retrieve>
</target>
</project>
Specify the "master" configuration
When ivy reads a remote Maven module the "master" configuration is the remote module's file only, with no dependencies
├── build.xml
└── lib
└── log4j-1.2.17.jar
Build file:
<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:retrieve pattern="lib/[artifact]-[revision](-[classifier]).[ext]">
<dependency org="log4j" name="log4j" rev="1.2.17" conf="master"/>
</ivy:retrieve>
</target>
</project>
Notes:
The conf="master" mapping tells ivy to retrieve from the remote master configuration
Using an ivy file
This is a more complex example that demonstrates the real power of ivy and how multiple configurations and mappings can be specified. Here I have two directories. One with just the log4j jar the second additionally containing the remote module's "optional" dependencies. If you look at the remote POM you'll see they have a different scope.
├── build.xml
├── ivy.xml
├── lib1
│   └── log4j-1.2.17.jar
└── lib2
├── activation-1.1.jar
├── geronimo-jms_1.1_spec-1.0.jar
├── log4j-1.2.17.jar
└── mail-1.4.3.jar
Build file
<project name="demo" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
<target name="resolve">
<ivy:resolve/>
<ivy:retrieve pattern="lib1/[artifact]-[revision](-[classifier]).[ext]" conf="noDependencies"/>
<ivy:retrieve pattern="lib2/[artifact]-[revision](-[classifier]).[ext]" conf="withDependencies"/>
</target>
</project>
ivy file
<ivy-module version="2.0">
<info organisation="com.myspotontheweb" module="demo"/>
<configurations>
<conf name="noDependencies" description="File grouping that has no transitive dependencies"/>
<conf name="withDependencies" description="File grouping that contains dependencies"/>
</configurations>
<dependencies>
<dependency org="log4j" name="log4j" rev="1.2.17" conf="noDependencies->master; withDependencies->master,optional"/>
</dependencies>
</ivy-module>

Copying files from source directory to destination directory using ant

I want to copy some specific files from source directory to destination directory on below condition using ANT.
Source folder contains the following files
35001_abc.sql
38001_abc.sql
38002_abc.sql
39001_abc.sql
I want to copy the files with filenames starting with 36000 and above.
The Output directory should contain the following files
38001_abc.sql
38002_abc.sql
39001_abc.sql
One idea is to use a regular expression on the filename to restrict ranges of digits.
Example
├── build.xml
├── src
│   ├── 35001_abc.sql
│   ├── 38001_abc.sql
│   ├── 38002_abc.sql
│   ├── 39001_abc.sql
│   ├── 41001_abc.sql
│   └── 46001_abc.sql
└── target
├── 38001_abc.sql
├── 38002_abc.sql
├── 39001_abc.sql
├── 41001_abc.sql
└── 46001_abc.sql
build.xml
<project name="demo" default="copy">
<property name="src.dir" location="src"/>
<property name="build.dir" location="target"/>
<target name="copy">
<copy todir="${build.dir}" overwrite="true" verbose="true">
<fileset dir="${src.dir}">
<filename regex="^(3[6-9]|[4-9]\d)\d{3}_abc.sql$"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="${build.dir}"/>
</target>
</project>

Write folder name and their sizes in a file using Ant

I need some help with Ant. I want to create a file using Ant, which to contain some names and the size in kb of some folders and also to contain other kind of data(not size) but with the same pattern.
Something like this:
build.date=April 01, 2000
folder1=10000
folder2=59093
folder3=646854
folder4=14897123
And also to make the sum of some folder sizes(for example foldersum=folder1+folder2) and write that in the file:
build.date=April 01, 2000
folder1=10000
folder2=59093
folder3=646854
folder4=14897123
foldersum=folder1+folder2
ANT is not a programming language. The best way to do this is to embed a scripting language, for example groovy.
Example
Given the following directory structure
├── build.xml
├── folder1
│   ├── file1.txt
│   ├── file2.txt
│   └── file3.txt
├── folder2
│   ├── file4.txt
│   └── file5.txt
└── folder3
└── file6.txt
Produces a file called "build-report.txt"
build.date=April 09,2015
folder1=1
folder2=1
folder3=1
foldersum=3
build.xml
<project name="demo" default="build">
<available classname="org.codehaus.groovy.ant.Groovy" property="groovy.installed"/>
<target name="build" depends="init">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
<dirset id="dirs" dir="." includes="folder*"/>
<groovy>
import java.text.SimpleDateFormat
def sdf = new SimpleDateFormat("MMMM dd,yyyy")
new File("build-report.txt").withWriter { w ->
w.println "build.date=${sdf.format(new Date())}"
def total = 0
ant.project.references.dirs.each {
def dir = new File(it.toString())
def size = dir.directorySize()
w.println "${dir.name}=${size}"
total += size
}
w.println "foldersum=${total}"
}
</groovy>
</target>
<target name="init" unless="groovy.installed">
<mkdir dir="${user.home}/.ant/lib"/>
<get dest="${user.home}/.ant/lib/groovy.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.4.3/groovy-all-2.4.3.jar"/>
<fail message="Groovy installed run build again"/>
</target>
</project>

Reading File from directory and sort using ant

I have a list of files in a directory . I have to read all the file names and extract the file name in a sorted order. How can I do that using ant script
You did not specify the sort criteria. Lots of options available see the resource documentation in the ANT manual
https://ant.apache.org/manual/Types/resources.html
Example
├── build.xml
└── src
├── data1
│   ├── file1.txt
│   ├── file2.txt
│   └── file3.txt
├── data2
│   ├── file4.txt
│   └── file5.txt
└── data3
└── file6.txt
Running the project prints the list of files sorted in reverse order based on modified date
build:
[echo] Files: /../src/data2/file4.txt:/../src/data3/file6.txt:/../src/data2/file5.txt:/../src/data1/file3.txt:/../src/data1/file2.txt:/../src/data1/file1.txt
build.xml
<project name="demo" default="build">
<target name="build">
<sort id="src.files">
<fileset dir="src" />
<reverse xmlns="antlib:org.apache.tools.ant.types.resources.comparators">
<date />
</reverse>
</sort>
<pathconvert targetos="unix" property="srcFiles" refid="src.files"/>
<echo message="Files: ${srcFiles}"/>
</target>
</project>

Copying files in fileset if a file of the same name exists with a specific suffix at the end

I am using a third party build script creates minified js files with the minified file called 'someFile.js' and an unminified version called 'someFile.js.uncompressed.js'. I need one of my tasks in the build.xml to copy only the js files that have a partner '.uncompressed.js' file to another location. For example, given a directory structure like this:
- rootDirectory
- minified.js
- minified.js.uncompressed
- unminified.js
- anotherDirectory
- anotherMinified.js
- anotherMinified.js.uncompressed.js
- unminified.js
- anotherUnminified.js
the destination directory should end up like this:
- rootDirectory
- minified.js
- anotherDirectory
- anotherMinified.js
Is there any way to accomplish this with ant? I am using ant 1.8.1.
Thanks in advance for any help!
You can use an Ant <present> selector to do this. For example:
<copy todir="dest">
<fileset dir="src">
<present targetdir="src">
<mapper type="glob" from="*" to="*.uncompressed.js" />
</present>
</fileset>
</copy>
In this case the targetdir in the selector is the same as the root directory of the fileset.
What this does is copy any file in the src directory tree where a file with the same name, with .uncompressed.js appended also present.
You could use a custom scriptselector for your fileset.
Example
├── build.xml
├── src
│   └── rootDirectory
│   ├── anotherDirectory
│   │   ├── anotherMinified.js
│   │   ├── anotherMinified.js.uncompressed
│   │   ├── anotherUnminified.js
│   │   └── unminified.js
│   ├── minified.js
│   ├── minified.js.uncompressed
│   └── unminified.js
└── target
└── rootDirectory
├── anotherDirectory
│   └── anotherMinified.js
└── minified.js
build.xml
<project name="demo" default="copy-files">
<target name="copy-files">
<copy todir="target">
<fileset dir="src">
<scriptselector language="javascript">
importClass(java.io.File);
var testForFile = new File("src/" + filename + ".uncompressed");
self.setSelected(testForFile.exists());
</scriptselector>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="target"/>
</target>
</project>
Notes:
This should work without the need for additional jars. Javascript is supported by modern JVMs.

Resources