Ivy: Jar Required for Processing, but not Compiling - ant

I have a project that depends upon two jars that are produced by us. I've placed those two jars in our repository, Ivy downloads them, and everything is fine with the compile and building the initial jar.
However, we have another jar that is an obfuscator we need to run against this jar. This is also in our repository, but it isn't needed for the compile. Instead, I simply run it as a program against the freshly built jar.
How should I classify this obfuscation jar's configuration? I can't say it's compile since it's not needed for the compilation. And, it shouldn't be in the runtime configuration either. That leaves us with provided, _optional, _master, or test.
I could create a special configuration for Jars that are required for building the software, but aren't required in the classpath, but I don't want to break our standard and create more than the basic configurations.
What's the best way to handle this?

Ivy configurations are designed to be flexible. Of course it makes perfect sense to standardize on the Maven scopes (especially when pulling from Maven repos) but I see no reason to limit your build, especially for dependencies only used by your build.
I typically create an extra configuration called "build" dedicated to pulling down items like ANT task jars:
<configurations>
<conf name="compile" description="Compile dependencies"/>
<conf name="runtime" description="Runtime dependencies" extends="compile"/>
<conf name="test" description="Test dependencies" extends="runtime"/>
<conf name="provided" description="Dependencies provided by target platform"/>
<conf name="build" description="Dependencies used by ANT build process"/>
</configurations>

If you need this jar only for your build-process an inline retrieve will do the job! It will help you to retrieve artifacts without the need of an ivy file.
This is really useful for jars needed for tasks, that you execute but have nothing to do with the artifact per se (findbugs, etc ..).
<ivy:retrieve organisation="foo" module="bar" inline="true" pattern="${my.install.dir}/[artifact].[ext]"/>
Another alternative is an inline ivy cachepath, where the jar is taken from the cache directly and not retrieved to your project.
<ivy:cachepath
organisation="org" module="module"
revision="latest.integration"
inline="true" pathid="project.compile.sourceprocessing.classpath"/>

Related

Ant+Ivy Jar Version

When I publish my artifact (some api jar), how do I specify version ?
is it revision attribute ? I want to have client-lib-1.0.jar
<ivy-module>
<info organisation="the.org" module="client-lib" revision ="1.0">
<info>
</ivy-module>
Firstly, you need to include a publications section, telling ivy what arifacts you are publishing as a module. Ivy is very flexible and quite capable of publishing modules with multiple files and/or types.
<publications>
<artifact name="client-lib" type="jar"/>
<artifact name="client-lib" type="jar" e:classifier="source"/>
<artifact name="client-lib" type="jat" e:classifier="javadocs"/>
</publications>
Secondly (and the answer to your question) the revision number of the published ivy file is decided at publish time. It gets set by the special "pubrevision" attribute of the publish task. Ivy will search the artifact pattern for the file(s) listed in the ivy file to be published.
<ivy:publish resolver="my-deploy" pubrevision="1.0">
<artifacts pattern="${build.dir}/[artifact](-[classifier]).[ext]"/>
</ivy:publish>
Under the hood a new ivy file is being generated and uploaded alongside the module's file.
How the file is stored in the repository is a matter decided by ivy resolver.
An issue you're likely to encounter is that few people host an Ivy repository these days. Instead Maven is the most common standard.
The following detailed detailed example(s) describes how this process works including the messy POM generation stuff (cause Maven doesn't understand ivy files):
how to publish 3rdparty artifacts with ivy and nexus
Convert ivy.xml to pom.xml

Is the [conf] token respected when publishing files using Ivy?

I'm learning Ivy (http://ant.apache.org/ivy/) and integrating it as part of our build process. It's going pretty well, but I'm stuck on something with the Ivy publish task. Specifically, I'd like to publish to the local repository with the following pattern (which includes the name of the current configuration):
${ivy.local.default.root}/[organisation]/[module]/[revision]/[type]s/[conf]/[artifact].[ext]
So I set up my custom resolver:
<filesystem name="modifiedLocalRepo">
<ivy pattern="${ivy.local.default.root}/[organisation]/[module]/[revision]/[type]s/[conf]/[artifact].[ext]" />
<artifact pattern="${ivy.local.default.root}/[organisation]/[module]/[revision]/[type]s/[conf]/[artifact].[ext]" />
</filesystem>
And configured the publish task:
<ivy:publish
settingsRef="ivy.ext.settings.custom" <!--Location of definition of modifiedLocalRepo-->
resolver="modifiedLocalRepo"
artifactspattern="bin/Debug/[module].[ext]"
pubrevision="1.1-Test"
overwrite="true"
conf="primary"
/>
And have the conf defined in the ivy.xml file:
<info organisation="Mine" module="Dependency"/>
<configurations defaultconf="primary"> <!--Don't think defaultconf should be necessary-->
<conf name="primary"/>
</configurations>
<publications>
<artifact name="Dependency" ext="dll" type="bin" conf="primary"/>
<artifact name="Dependency" ext="pdb" type="bin" conf="primary"/>
</publications>
I have the process working, ivy configured, resolved, the project building, and the artifacts published (using my custom resolver above). But the [conf] token is always resolving to "default." So the published directory has the structure:
\.ivy2\local\Mine\Dependency\1.1-Test\bins\default\
instead of the structure
\.ivy2\local\Mine\Dependency\1.1-Test\bins\primary\
I've been tinkering around with it, setting the conf value, defaultconf value, etc. everywhere they are valid but it's always "default."
I'm using ant to do the build, and have run in debug mode (-d), inspected the output and noticed nothing useful. I've looked through the output of <echoproperties\> and noticed nothing useful. I've read through the Ivy documentation and only found use of [conf] as a token in retrieve and report output.
I can attach the full xml files I'm using to do my limited test build if it would be useful.
Is the [conf] token valid/respected in the artifact pattern for an Ivy publish? If so, what am I missing? Thanks!
Update:
Was using Ivy 2.3.0-rc2 and decided to try to roll back and use Ivy 2.0.0. Same issue.
Take a look at my Ivy project in github. I set it up, so you can easily add it into an existing Ant project.
We use a Maven repository, so I have it setup to create a pom.xml, and then use mvn deploy:deploy-file to deploy it back to the Maven repository. We use Jenkins for our build, so we use Jenkins to run the mvn deploy-file to do the deployment. I guess we could use <ivy:publish>, but never really tried it.

Generate Ant tasks with macro

I've been searching for a possibility to generate ANT targets from top-level macro.
Details:
We have heterogenic build system. ANT+IVY is used as top-level (inherited solutin, can't be changed). Some projects are built via MSBuild, called from ANT via exec task. For each of these projects, there's at least two distinct calls to msbuild (wrapped with macro for brevity), one in "build" target, and one in "clean". Two of them are different only by "target" parameter. So I was guessing, if there's possibility for something like this:
Extension nodes:
<extensionpoint name="build-ext-point" />
<extensionpoint name="clean-ext-point" />
<target name="build" depends="build-ext-point" />
<target name="clean" depends="clean-ext-point" />
My magic macro:
<macrodef name="msbuild-proj" />
<attribute name="project" />
<sequential>
<target name="#{project}-build" >
<msbuild project="#{project}" target="Build" />
</target>
<target name="#{project}-clean" >
<msbuild project="#{project}" target="Clean" />
</target>
</sequential>
</macrodef>
How it would be used:
<msbuild-proj project="CPP-proj" />
Thanks!
P.S: Yeah I know that I can define those build and clean overridden, or via ext point, or whatever. The question is actually whether I can remove some code duplication.
UPD: I'd answer this by myself. At the point, there's no such possibility. Mainly, because Target class is a task container, but not a task. So, it cannot be placed into container. So I guess I'll write some kind of extensible task.
ANT has a couple of mechanisms for building modular builds.
First of all I think your main question was on how to build "extension points" to your build? The following ANT tasks are designed to import common build logic from another build file:
import
include
Since you're already planning to extend your build using macrodefs, I'd recommend packaging these as a reusable ANTlib. The ANTlib can live within your project, but it's really designed to be packaged within a jarfile which another build can pickup, for example by installing it in the standard ANT lib directory:
$ANT_HOME/lib
$HOME/.ant/lib
Finally, if you're already using ivy and you package your taskdefs as ANT libs, you could version your build logic by installing it in a Maven repository manager like Nexus. This addresses one of the key problems with large ANT builds. Over time they become so big it's impossible to change the common logic without impacting older builds (Demonstrating that the builds are not properly isolated from each other).
Actually done this.
Does its job, although some caveats are present.
For those interested: https://bitbucket.org/targetsan/ant-events

correct configurations for ivy transitive dependencies

My project is composed of n modules. One of these, let's say it is called my-first-module declares, amongst others, one dependency like:
<dependency org="com.mycompany.myproject" name="my-second-module" conf="default->default" rev="1.0-SNAPSHOT"/>
The artifacts are stored in an internal repository which is correctly working when retrieving jars.
For debug purpose i run:
ant -d | grep my-second-module
The output says:
sorting dependencies of com.mycompany.myproject#my-second-module / # of dependencies : 2
and that is correct, as the second module declares 2 external dependencies. I assume then ivy.xml for my-second-module is correctly fetched and parsed from the repository. Ivy then should know the dependencies of my-second-module
The problem is, ivy is not fetching those 2 transitive dependencies.
As you can see from the declaration I have specified I want to retrieve the default configuration, and it should be running transitive.
Impossible to diagnose anything without see how you've configured the projects.
The only advice I can offer is to generate an ivy dependency management report and take a look at the "default" configuration.
<target name="init" description="Resolve dependencies">
<ivy:resolve/>
<ivy:report todir="${build.dir}/ivy-report" graph="false"/>
..
..
</target>
Perhaps the transitive dependencies are being over-ridden by other resolved modules. For example it's possible for two modules to retrieve different revisions of the same module, in which case ivy will chose one and "evict" the other. Another possibility is a module declaring an exclusion, which would account for missing transitive dependencies.
Finally, let's be clear what you mean by "fetching".... Ivy will "resolve" dependencies, which means it will analyse each module and populate it's local cache with the various files. Ivy has a separate "retrieve" task for placing files into the local build workspace.
<ivy:retrieve pattern="${dist.dir}/WEB-INF/lib/[artifact].[ext]" conf="runtime"/>
So... This means when you run ivy, files may actually not be downloaded from the remote repository, because ivy already has them safely tucked away in it's cache. (normally located in $HOME/.ivy2/cache)

Is it possible to refer to a classpath defined in one build file from another build file?

In project A's build file, there is a <path>;
In project B's build file, I want to execute a tool class in project A by <java> task.
The <java> task need to use that path in its "classpathref" property.
The <path> in project A's build file is quite complicated so that I don't want to copy it to project B's build file.
So is it possible to refer to a classpath defined in one build file from another build file?
Using the import or include ANT tasks is the way to do this.... however, these are both designed build multi-module builds. It's generally a really bad idea to couple two different projects in this manner....
I understand the motivation, classpath management is one of the most important and error-prone parts of a Java build. My recommendation is to adopt Apache ivy and let it manage your build's 3rd party dependencies.
Example:
The ivy cachepath task to create your ANT path, using dependency declarations.
<ivy:cachepath pathid="test.path">
<dependency org="org.slf4j" name="slf4j-simple" rev="1.6.4" conf="default"/>
<dependency org="junit" name="junit" rev="4.10" conf="default"/>
</ivy:cachepath>
The jars themselves can be locally stored or retrieved from the Maven Central repository
Ant allows to import a project file into another. You may check section 'Resolving files against the imported file' as this will be needed in most cases.

Resources