How do you configure Apache Ivy to remove orphan artifacts? - java

Let's say I have an ivy.xml that contains the following:
<dependency org="checkstyle" name="checkstyle" rev="4.3" />
And then I want to upgrade to Checkstyle 4.4, so I change my ivy.xml to contain:
<dependency org="checkstyle" name="checkstyle" rev="4.4" />
After a retrieve with the first configuration, I have the file checkstyle-4.3.jar. After the second configuration, I also have the file checkstyle-4.4.jar, and the file checkstyle-4.3.jar still exists.
Is there a way to have Ivy realize that the old file is an orphan, and remove it from the lib directory? The idea is that I don't want my developers' disk space usage to drastically increase every time I upgrade a tool.
Ideally I'd also want it removed from the local repository as well. I do realize that the intent of the local repository is that it is shared among projects, so it would not make sense to remove anything, as it would not know if the artifact was still in use in other projects. But there must be some kind of prune procedure...

I've been using Ivy 2.0.0, so I don't know if this applies to the version you're using.
The Ivy retrieve task has a sync attribute. Set this to true and unused/unknown files in your retrieved directory (lib in your case) will be removed. Keep in mind this will mean any manually copied artifacts in this directory which Ivy doesn't specifically resolve will be removed.
Also, note that if you use the sync option but Ivy resolves no dependencies (empty or missing ivy.xml, for example), the retrieve directory will be deleted.

Related

Ivy Install task fails with JSCH SFTP error 4 first time, but is successful on subsequent attempts

I am trying to use the ANT Ivy install task to copy a library from one repository to the other.
Some example code within my ANT target:
<ivy:install organisation="testOrg" module="testModuleName" revision="1.2.3" from="fromRepo" to="toRepo"/>
The fromRepo and toRepo are defined in a local ivysettings.xml file.
The resolve (from fromRepo) of the library is successful but the install to toRepo fails, with an SFTP Code 4 error.
impossible to install testOrg#testModuleName;1.2.3: java.io.IOException: Failure
at org.apache.ivy.plugins.repository.sftp.SFTPRepository.put(SFTPRepository.java:164)
at org.apache.ivy.plugins.repository.AbstractRepository.put(AbstractRepository.java:130)
at org.apache.ivy.plugins.resolver.RepositoryResolver.put(RepositoryResolver.java:234)
at org.apache.ivy.plugins.resolver.RepositoryResolver.publish(RepositoryResolver.java:215)
at org.apache.ivy.core.install.InstallEngine.install(InstallEngine.java:150)
at org.apache.ivy.Ivy.install(Ivy.java:537)
at org.apache.ivy.ant.IvyInstall.doExecute(IvyInstall.java:102)
at org.apache.ivy.ant.IvyTask.execute(IvyTask.java:271)
...
Caused by: 4: Failure
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2833)
at com.jcraft.jsch.ChannelSftp.mkdir(ChannelSftp.java:2142)
at org.apache.ivy.plugins.repository.sftp.SFTPRepository.mkdirs(SFTPRepository.java:186)
at org.apache.ivy.plugins.repository.sftp.SFTPRepository.mkdirs(SFTPRepository.java:184)
at org.apache.ivy.plugins.repository.sftp.SFTPRepository.put(SFTPRepository.java:160)
... 37 more
However if I simply run the same target again, the install completes successfully!
It seems to be some issue with creating a directory, from com.jcraft.jsch.ChannelSftp.mkdir(ChannelSftp.java:2142) in the stacktrace.
After running the 1st time, the testOrg/testModuleName directory exists (only testOrg having previously existed).
The 2nd time running the testOrg/testModuleName/1.2.3 directory is created (along with the library artifacts).
If after running the 1st time I delete the testOrg/testModuleName directory it created, it will continue to return the code 4 error.
My ANT library directory contains: jsch-0.1.50.jar which I assume it is using to upload to the destination Ivy Server.
In addition I am using:
Ant 1.8.4
Ivy 2.4.0
Java 1.7.0_80
By debugging the Ivy SFTP source code that creates the new directories on the destination toRepo repository, I was able to see why this was happening.
The code is in the method: SFTPRepository.mkdirs() this recursively calls itself to make each directory in the path if they do not exist.
For my example the directory being uploaded was:
/toRepo/testOrg/testModuleName//1.2.3/
You can see the double slash: // in the middle of the path.
The meant that the mkdirs() method tried to create the testModuleName directory twice. The 2nd time failed which caused the code 4 error.
The reason there is a double slash in the path is because there is no branch for this artifact.
Within my ivy settings file the sftp resolver (for my toRepo repository) artifact patterns were configured to:
<ivy pattern="/toRepo/[organisation]/[module]/[branch]/[revision]/ivy-[revision].xml"/>
<artifact pattern="/toRepo/[organisation]/[module]/[branch]/[revision]/[artifact]-[revision].[ext]"/>
The /[branch]/ part of the pattern is what was generating the // in the path.
There are 2 configurations, one for the ivy.xml file itself and the other for all other artifacts.
Ivy patterns allow the use of parenthesis for optional parts of the pattern.
So changing my configuration to:
<ivy pattern="/toRepo/[organisation]/[module](/[branch])/[revision]/ivy-[revision].xml"/>
<artifact pattern="/toRepo/[organisation]/[module](/[branch])/[revision]/[artifact]-[revision].[ext]"/>
Fixed the issue and the ivy install functioned as expected.
This means that for antifacts where there is no branch defined (like 3rd party artifacts), then the branch directory will not be included in the path.

Gradle remove version number from the dependency name

I would like to use derbyrun.jar created by the Apache Derby project in my application in order to run a derby database as a Windows or Linux service.
The problem is that derbyrun.jar references in its manifest other derby jars without any version number in their names, like Class-Path: derby.jar derbyclient.jar derbytools.jar derbynet.jar. While my application (with many subprojects) uses "maven/gradle" format derby-10.13.1.1.jar, derbyclient-10.13.1.1.jar, etc..
Is there a simple way in gradle to name those derby jars without a version number, like
compile("org.apache.derby:derby:10.11.1.1") {
artifact {
name = 'derby'
}
}
that should result in just derby.jar.
I do not like an idea of renaming derby-10.13.1.1.jar into derby.jar in a separate task as we reference those artifact names in many places using configurations.runtime, etc. (e.g. when deploying or creating manifest files for our own jars). And this renaming approach seems to complicate the script unnecessary (+ all the future maintenance effort when the derby version will be changed).
Is there a better way to achieve this? Sure, the mentioned above artifact { name = 'derby' } does not remove the version number from the jar's file name.

Use Ivy API to obtain latest version of a dependency?

We have a simple Ivy repository we host off of an in-house server (Apache httpd serving up JARs and their XML Ivy descriptors).
I now have a need to programmatically determine what the latest version of a dependency is in our repo. Thus if we have two versions of Mockito, our repo might look like:
mockito/ ==> organisation
mockito-all ==> module
1.9.4/ ==> revision #
mockito-all-1.9.4.jar
mockito-all-1.9.4-ivy.xml
1.9.5/
mockito-all-1.9.5.jar
mockito-all-1.9.5-ivy.xml
It would be nice if, from Java, I can use Ivy to determine that "1.9.5" is the latest version of the mockito/mockito-all module that we have.
This would likely not be an Ant task, and instead would likely be some custom Java code using the classes that exist inside ivy.jar.
Any ideas? Thanks in advance!
I believe you can use latest.integration revision value to specify the absolute latest version needed. For example, specify your Ivy dependency like so:
<dependency org="mockito" name="mockito-all" rev="latest.integration" />
You can also specify latest.milestone or latest.release if you don't want the "edge" version. Here is a good explanation on the rev value: http://ant.apache.org/ivy/history/latest-milestone/ivyfile/dependency.html
So I found your question looking to do the same thing and after some research found that in Ivy 2.4, such a thing exists.
http://ant.apache.org/ivy/history/latest-milestone/use/checkdepsupdate.html
Here is a sample step:
<target name="ivy.outdated" description="Check ivy for outdated jars">
<ivy:resolve/>
<ivy:checkdepsupdate showTransitive="false" revisionToCheck="latest.release"/>
</target>

How to get jar library name and version from String library name?

I have many jar files in my directory:
some-lib-2.0.jar
some-lib-2.1-SNAPSHOT.jar
some-lib-3.RELEASE.jar
some-lib-R8.jar
some-lib-core-1.jar
some-lib-2.patch2.jar
some-lib-2-alpha-4.jar
some-lib.jar
some-lib2-4.0.jar
How can I get library name and version from file name?
Is regex ((?:(?!-\d)\S)+)-(\S*\d\S*(?:-SNAPSHOT)?).jar$ valid for extract name and version?
The version number in the JAR file name is merely a convention and a default for Maven-built JARs. It may have been overridden, and it is not always reliable reading the version number from just the file name.
A more reliable way for reading version number from JAR is to look inside the JAR file. Here you have a couple of options depending on how the JAR was built:
look at META-INF/maven/.../pom.properies and pom.xml and read the version from that - this should be present for Maven-built binaries
sometimes version number if present in META-INF/MANIFEST.MF under Specification-Version or Implementation-Version properties
If this fails, then fall back to reading version number from the JAR name since there is no other information available.
Naming policy could differ across different libraries, so you aren't able to extract name/version from package name using one rule, for details you should check project docs.
In case of Maven you are able to configure the final name of built artifact with finalName pom.xml configuration option. Maven docs provide nice introduction into pom structure. Below is the example from docs:
<build>
...
<finalName>${artifactId}-${version}</finalName>
...
</build>

can I use 2 ivy files?

I'm creating a build environment for third party developers. I want to provide them with an ivy.xml which a 3rd party shouldn't change and also a ivy-custom.xml which they should change.
<target name="resolve" depends="download-ivy">
<ivy:resolve file="ivy.xml"/>
<ivy:resolve file="ivy-custom.xml"/>
</target>
This doesn't seem to work, though. The ivy-custom.xml seems to usurp the original ivy.xml. Does anyone know of a way to do this? Thanks.
You may consider split it into 2 separate modules. The first one is with dependency of your ivy.xml and publish it into your maven repository. (said org="com.abc", name="your-module", version 1.0)
Then you may let your 3rd party developers use ivy-custom.xml that also resolve "your-module" as one of the dependency.
<dependency org="com.abc" name="your-module" rev="1.0" transitive="true"/>
This assume your developer have access to your repository.

Categories