7

I find the Ivy API to be immensely complicated.

What is the simplest possible snippet to retrieve an artifact from Maven Central into a specific local directory using Ivy 100% programmatically (no Ant, no Xml files, ...)?

For the sake of an example say retrieving commons-logging:commons-logging:1.1:jar into /my/destination.

Axel Fontaine
  • 34,542
  • 16
  • 106
  • 137
  • Why is Ivy a requirement? Are other libraries/code snippets acceptable? – kdgregory Mar 24 '13 at 15:10
  • Sure, if you have an alternative solution that caches locally and ensures downloads do not get corrupted, that's fine too. – Axel Fontaine Mar 24 '13 at 15:41
  • 1
    I was originally going to recommend [Aether](http://www.sonatype.org/aether), but then I looked at their [examples](http://git.eclipse.org/c/aether/aether-demo.git/tree/) and [API](http://download.eclipse.org/aether/aether-core/0.9.0.M2/apidocs/), and realized why people make fun of Java programmers. – kdgregory Mar 25 '13 at 12:26
  • If you do need the local cache, I'd suggest adapting the [Dependencies](http://maven.apache.org/ant-tasks/examples/dependencies.html) task from the Maven Ant Tasks. While this would take more code than I'd want to write for an answer, it looks very straightforward (if you haven't developed an Ant task in the past, start with the `doExecuteResolution()` method of [DependenciesTask.java](http://svn.apache.org/viewvc/maven/ant-tasks/trunk/src/main/java/org/apache/maven/artifact/ant/DependenciesTask.java?view=markup)). The code looks straightforward, but you have to build an in-memory Maven POM. – kdgregory Mar 25 '13 at 12:32
  • We have a local build system here (that I've inherited), and using Ivy programmatically. You're right, complicated, poorly documented. I, for the life of me, can't figure out how to get it to download the source code along with the compiled. – ticktock Nov 03 '14 at 23:10

2 Answers2

10

I have been working on using Ivy to remotely resolve artifacts (and dependencies) from Maven repository. Here is one code sample that downloads one artifact (w/o dependencies).

If you need dependencies, you need to adapt the dependency descriptor.

Some note:

  1. Ivy uses a cache to store previously retrieved artifacts and their "ivy translations" (you will find ivy modules derived from Maven artifacts in the cache)

  2. The general concept is that you programmatically create an Ivy module that has dependencies on Maven repository stored "pseudo-modules" (i.e. there is a mapping under the hood implemented by the resolver - I believe).

  3. In general a good starting point, if you want to know how to programmatically use Ivy, is the main class org.apache.ivy.Main.


        public static void main(String[] args) throws Exception {

        String groupId = "org.springframework";
        String artifactId = "spring-context-support";
        String version = "4.0.2.RELEASE";
        File   out = new File("out");

        // create an ivy instance
        IvySettings ivySettings = new IvySettings();
        ivySettings.setDefaultCache(new File("ivy/cache"));

        // use the biblio resolver, if you consider resolving 
        // POM declared dependencies
        IBiblioResolver br = new IBiblioResolver();
        br.setM2compatible(true);
        br.setUsepoms(true);
        br.setName("central");

        ivySettings.addResolver(br);
        ivySettings.setDefaultResolver(br.getName());

        Ivy ivy = Ivy.newInstance(ivySettings);

        // Step 1: you always need to resolve before you can retrieve
        //
        ResolveOptions ro = new ResolveOptions();
        // this seems to have no impact, if you resolve by module descriptor (in contrast to resolve by ModuleRevisionId)
        ro.setTransitive(true);
        // if set to false, nothing will be downloaded
        ro.setDownload(true);

        // 1st create an ivy module (this always(!) has a "default" configuration already)
        DefaultModuleDescriptor md = DefaultModuleDescriptor.newDefaultInstance(
            // give it some related name (so it can be cached)
            ModuleRevisionId.newInstance(
                groupId, 
                artifactId+"-envelope", 
                version
            )
        );

        // 2. add dependencies for what we are really looking for
        ModuleRevisionId ri = ModuleRevisionId.newInstance(
            groupId, 
            artifactId,
            version
        );
        // don't go transitive here, if you want the single artifact
        DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(md, ri, false, false, false);

        // map to master to just get the code jar. See generated ivy module xmls from maven repo
        // on how configurations are mapped into ivy. Or check 
        // e.g. http://lightguard-jp.blogspot.de/2009/04/ivy-configurations-when-pulling-from.html
        dd.addDependencyConfiguration("default", "master");
        md.addDependency(dd);

        // now resolve
        ResolveReport rr = ivy.resolve(md,ro);
        if (rr.hasError()) {
            throw new RuntimeException(rr.getAllProblemMessages().toString());
        }

        // Step 2: retrieve
        ModuleDescriptor m = rr.getModuleDescriptor();

        ivy.retrieve(
            m.getModuleRevisionId(),
            out.getAbsolutePath()+"/[artifact](-[classifier]).[ext]",
            new RetrieveOptions()
                // this is from the envelop module
                .setConfs(new String[]{"default"})
        );
    }

gnomie
  • 439
  • 5
  • 16
  • How might we get it to also download the sources for the group/artifact/version? – ticktock Nov 04 '14 at 00:40
  • `ResolveOptions`'s `transitive` and `download` flags have default values `true`, so there's no need to call their setters. – lyomi Dec 12 '14 at 05:42
  • how would you add credentials to your ivy settings? – Chris Bolton Jan 26 '16 at 18:37
  • 1
    Sorry can't help with these questions. We moved on to eclipse aether for remote maven repo access. Don't remember exactly why, but something was seriously missing in ivy (which may have changed by now of course). – gnomie Jan 27 '16 at 07:14
  • I could pass credential using CredentialsStore. ```CredentialsStore.INSTANCE.addCredentials(null, host, username, password)``` – Shkredov S. Apr 22 '20 at 09:43
8

The simplest way to retrieve an artifact (and it's dependencies) is to use ivy from the command-line

java -jar ivy.jar -dependency commons-logging commons-logging 1.1 -retrieve "/my/destination/[artifact](-[classifier]).[ext]"

This will retrieve the files into the directory "/my/destination".

Other examples:

Community
  • 1
  • 1
Mark O'Connor
  • 76,015
  • 10
  • 139
  • 185
  • This is stretching the "100% programmatically" a little, as it avoids the API altogether. – Axel Fontaine Mar 24 '13 at 23:17
  • @AxelFontaine Gets the job done :-) If you follow the first example list I do have a groovy example which calls ivy tasks. Personally I've never had the need to use ivy's Java API. As David stated it's poorly documented in any case. – Mark O'Connor Mar 24 '13 at 23:53