ivy-resolver 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +20 -0
- data/ivy-resolver.gemspec +25 -0
- data/jars/Rakefile +21 -0
- data/lib/ivy-resolver.rb +6 -0
- data/lib/ivy/resolver.rb +110 -0
- data/lib/ivy/resolver/artifact.rb +13 -0
- data/lib/ivy/resolver/dsl.rb +70 -0
- data/lib/ivy/resolver/version.rb +8 -0
- data/spec/ivy_resolver_spec.rb +112 -0
- data/spec/spec_helper.rb +18 -0
- data/spec_files/Jarfile +6 -0
- data/spec_files/org/example/test/0.0.1/.gitignore +2 -0
- data/spec_files/org/example/test/0.0.1/IvyResolverTestClass.java +8 -0
- metadata +81 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Shaun Mangelsdorf
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
task :resolve_resolver do
|
4
|
+
jar_path = File.expand_path(File.join(File.dirname(__FILE__), 'jars'))
|
5
|
+
|
6
|
+
mkdir_p jar_path
|
7
|
+
require "net/http"
|
8
|
+
|
9
|
+
ivy_version = Ivy::Resolver::IVY_VERSION
|
10
|
+
print "Downloading ivy #{ivy_version}... "
|
11
|
+
|
12
|
+
Net::HTTP.start 'repo1.maven.org' do |http|
|
13
|
+
resp = http.get "/maven2/org/apache/ivy/ivy/#{ivy_version}/ivy-#{ivy_version}.jar"
|
14
|
+
raise 'Failed' unless resp.is_a? Net::HTTPOK
|
15
|
+
puts 'Succeeded.'
|
16
|
+
open File.join(jar_path, "ivy-#{ivy_version}.jar"), 'wb' do |file|
|
17
|
+
file.write resp.body
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "ivy/resolver/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ivy-resolver"
|
7
|
+
s.version = Ivy::Resolver::VERSION
|
8
|
+
s.extensions = ['jars/Rakefile']
|
9
|
+
s.authors = ["Shaun Mangelsdorf"]
|
10
|
+
s.email = ["s.mangelsdorf@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{Resolve JAR files using Ivy under the covers}
|
13
|
+
s.description = %q{Provides a Bundler-like interface to resolve JARs with Ivy}
|
14
|
+
|
15
|
+
s.rubyforge_project = "ivy-resolver"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib", "jars"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
s.add_development_dependency "rspec", '~> 2.8.0'
|
24
|
+
# s.add_runtime_dependency "rest-client"
|
25
|
+
end
|
data/jars/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
desc 'Install the required JAR file for Ivy'
|
2
|
+
task :default do
|
3
|
+
jar_path = File.dirname(__FILE__)
|
4
|
+
$: << File.expand_path(File.join(jar_path, '..', 'lib'))
|
5
|
+
|
6
|
+
require 'fileutils'
|
7
|
+
require 'net/http'
|
8
|
+
require 'ivy/resolver/version'
|
9
|
+
|
10
|
+
FileUtils.mkdir_p jar_path
|
11
|
+
|
12
|
+
ivy_version = Ivy::Resolver::IVY_VERSION
|
13
|
+
|
14
|
+
Net::HTTP.start 'repo1.maven.org' do |http|
|
15
|
+
resp = http.get "/maven2/org/apache/ivy/ivy/#{ivy_version}/ivy-#{ivy_version}.jar"
|
16
|
+
raise 'Failed' unless resp.is_a? Net::HTTPOK
|
17
|
+
open File.join(jar_path, "ivy-#{ivy_version}.jar"), 'wb' do |file|
|
18
|
+
file.write resp.body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/ivy-resolver.rb
ADDED
data/lib/ivy/resolver.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# Released under the MIT license. See the MIT-LICENSE file for details
|
2
|
+
|
3
|
+
module Ivy
|
4
|
+
class Resolver
|
5
|
+
autoload :DSL, 'ivy/resolver/dsl'
|
6
|
+
autoload :Artifact, 'ivy/resolver/artifact'
|
7
|
+
|
8
|
+
java_import Java::org.apache.ivy.Ivy
|
9
|
+
java_import Java::org.apache.ivy.core.settings.IvySettings
|
10
|
+
java_import Java::org.apache.ivy.core.module.descriptor.Configuration
|
11
|
+
java_import Java::org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor
|
12
|
+
java_import Java::org.apache.ivy.core.module.id.ModuleRevisionId
|
13
|
+
java_import Java::org.apache.ivy.core.module.id.ModuleId
|
14
|
+
java_import Java::org.apache.ivy.core.resolve.ResolveOptions
|
15
|
+
|
16
|
+
|
17
|
+
java_import Java::org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter
|
18
|
+
def dump
|
19
|
+
file = Java::java.io.File.create_temp_file('ivy', '.xml')
|
20
|
+
XmlModuleDescriptorWriter.write module_descriptor, file
|
21
|
+
puts File.open(file.absolute_path, 'r').read
|
22
|
+
file.delete
|
23
|
+
end
|
24
|
+
|
25
|
+
class <<self
|
26
|
+
@@instance = nil
|
27
|
+
|
28
|
+
def setup
|
29
|
+
@@instance ||= new
|
30
|
+
raise 'No Jarfile in the current directory' unless File.exists? 'Jarfile'
|
31
|
+
|
32
|
+
@@instance.configure File.open('Jarfile', 'r').read
|
33
|
+
@@instance.resolve
|
34
|
+
end
|
35
|
+
|
36
|
+
def require
|
37
|
+
setup unless @@instance and @@instance.configured?
|
38
|
+
@@instance.artifacts.each(&:require)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_accessor :module
|
43
|
+
attr_accessor :artifacts
|
44
|
+
|
45
|
+
def initialize(root=File.dirname($0), opts={})
|
46
|
+
@root = root
|
47
|
+
@opts = opts
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_default_resolver?
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def settings
|
55
|
+
@settings ||= IvySettings.new
|
56
|
+
end
|
57
|
+
|
58
|
+
def configuration(name='default')
|
59
|
+
@configurations ||= {}
|
60
|
+
@configurations[name] ||= Configuration.new(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def module_descriptor
|
64
|
+
@module_descriptor ||= DefaultModuleDescriptor.newDefaultInstance(module_revision_id)
|
65
|
+
end
|
66
|
+
|
67
|
+
def module_revision_id
|
68
|
+
@module_revision_id ||= ModuleRevisionId.new(module_id, self.module[2])
|
69
|
+
end
|
70
|
+
|
71
|
+
def module_id
|
72
|
+
raise 'Project name not declared yet.' unless self.module
|
73
|
+
@module_id ||= ModuleId.new *self.module[0..1]
|
74
|
+
end
|
75
|
+
|
76
|
+
def configure(src=nil, &bl)
|
77
|
+
@configured = true
|
78
|
+
|
79
|
+
dsl = DSL.new(self)
|
80
|
+
dsl.instance_eval src unless src.nil?
|
81
|
+
dsl.instance_eval &bl if block_given?
|
82
|
+
end
|
83
|
+
|
84
|
+
def configured?
|
85
|
+
!!@configured
|
86
|
+
end
|
87
|
+
|
88
|
+
def resolve(opts={})
|
89
|
+
ivy = Ivy.new_instance @settings
|
90
|
+
report = ivy.resolve module_descriptor, resolve_options(opts)
|
91
|
+
@artifacts ||= report.all_artifacts_reports.collect do |artifact_report|
|
92
|
+
Artifact.new artifact_report
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def resolve_options(opts)
|
98
|
+
{
|
99
|
+
:check_if_changed => false,
|
100
|
+
:download => true,
|
101
|
+
:output_report => false,
|
102
|
+
:refresh => false,
|
103
|
+
:use_cache_only => false,
|
104
|
+
:validate => false
|
105
|
+
}.merge(opts).inject(ResolveOptions.new) do |resolve_options, (option, value)|
|
106
|
+
resolve_options.send :"set_#{option}", value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Released under the MIT license. See the MIT-LICENSE file for details
|
2
|
+
|
3
|
+
class Ivy::Resolver
|
4
|
+
class Artifact
|
5
|
+
def initialize(artifact_report)
|
6
|
+
@artifact_report = artifact_report
|
7
|
+
end
|
8
|
+
|
9
|
+
def require
|
10
|
+
Kernel.require @artifact_report.local_file.absolute_path
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Released under the MIT license. See the MIT-LICENSE file for details
|
2
|
+
|
3
|
+
class Ivy::Resolver
|
4
|
+
class DSL
|
5
|
+
java_import Java::org.apache.ivy.plugins.resolver.URLResolver
|
6
|
+
java_import Java::org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor
|
7
|
+
java_import Java::org.apache.ivy.core.module.id.ModuleRevisionId
|
8
|
+
|
9
|
+
def initialize(resolver, configuration='default')
|
10
|
+
@resolver = resolver
|
11
|
+
@count = 0
|
12
|
+
@configuration = resolver.configuration configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
def project(group, artifact, version)
|
16
|
+
@resolver.module = [group, artifact, version]
|
17
|
+
end
|
18
|
+
|
19
|
+
def source(url, opts={})
|
20
|
+
opts = default_source_opts(url).merge(opts)
|
21
|
+
|
22
|
+
URLResolver.new.tap do |resolver|
|
23
|
+
resolver.m2compatible = opts[:maven]
|
24
|
+
resolver.name = opts[:name]
|
25
|
+
resolver.add_artifact_pattern opts[:pattern]
|
26
|
+
|
27
|
+
yield resolver if block_given?
|
28
|
+
|
29
|
+
@resolver.settings.add_resolver resolver
|
30
|
+
@resolver.settings.default_resolver = opts[:name] if opts[:default]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def jar(group, artifact, version='latest', opts={})
|
35
|
+
opts = default_artifact_opts.merge opts
|
36
|
+
revision = ModuleRevisionId.newInstance group, artifact, version
|
37
|
+
dependency = DefaultDependencyDescriptor.new @resolver.module_descriptor, revision,
|
38
|
+
opts[:force], opts[:changing], opts[:transitive]
|
39
|
+
|
40
|
+
opts[:configurations].each do |configuration|
|
41
|
+
if configuration.is_a? Array
|
42
|
+
dependency.add_dependency_configuration *configuration
|
43
|
+
else
|
44
|
+
dependency.add_dependency_configuration configuration, configuration
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@resolver.module_descriptor.add_dependency dependency
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def default_source_opts(url)
|
53
|
+
{
|
54
|
+
:maven => true,
|
55
|
+
:name => "repository#{@count += 1}",
|
56
|
+
:pattern => "#{url}/[organisation]/[module]/[revision]/[artifact](-[revision]).[ext]",
|
57
|
+
:default => !@resolver.has_default_resolver?
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def default_artifact_opts
|
62
|
+
{
|
63
|
+
:transitive => true,
|
64
|
+
:force => false,
|
65
|
+
:changing => false,
|
66
|
+
:configurations => ['*']
|
67
|
+
}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# Released under the MIT license. See the MIT-LICENSE file for details
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Ivy::Resolver do
|
6
|
+
include Java
|
7
|
+
|
8
|
+
before :each do
|
9
|
+
@organisation = 'org.example'
|
10
|
+
@name = 'test'
|
11
|
+
@revision = '0.0.1'
|
12
|
+
@artifact_path = spec_files_path 'org/example/test/0.0.1'
|
13
|
+
@artifact = "#{@name}-#{@revision}.jar"
|
14
|
+
%x[cd #{@artifact_path}; rm -f #{@artifact}; javac *.java; zip #{@artifact} *.class]
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can be instantiated' do
|
18
|
+
subject.should be_a Ivy::Resolver
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'returns a settings object' do
|
22
|
+
subject.settings.should be_a org.apache.ivy.core.settings.IvySettings
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'creates a new configuration object' do
|
26
|
+
c = subject.configuration('new')
|
27
|
+
c.name.should == 'new'
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with a defined module' do
|
31
|
+
before :each do
|
32
|
+
subject.module = [@organisation, @name, @revision]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'creates a module id' do
|
36
|
+
subject.module_id.tap do |obj|
|
37
|
+
obj.should be_a org.apache.ivy.core.module.id.ModuleId
|
38
|
+
obj.name.should == @name
|
39
|
+
obj.organisation.should == @organisation
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'creates a module revision id' do
|
44
|
+
subject.module_revision_id.tap do |obj|
|
45
|
+
obj.should be_a org.apache.ivy.core.module.id.ModuleRevisionId
|
46
|
+
obj.name.should == @name
|
47
|
+
obj.organisation.should == @organisation
|
48
|
+
obj.revision.should == @revision
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'creates a module descriptor' do
|
53
|
+
subject.module_descriptor.should be_a org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'invokes the DSL' do
|
57
|
+
subject.module = nil
|
58
|
+
# Scoping is weird because of the instance_eval, we can't reach the test
|
59
|
+
# instance variables from inside this block
|
60
|
+
subject.configure do
|
61
|
+
project 'org.example', 'test', '0.0.1'
|
62
|
+
end
|
63
|
+
|
64
|
+
subject.module.should == ['org.example', 'test', '0.0.1']
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'with a configured resolver' do
|
69
|
+
before :each do
|
70
|
+
subject.configure do
|
71
|
+
project 'org.example', 'test-resolver', '0.0.1'
|
72
|
+
source "file:" + File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_files'))
|
73
|
+
jar 'org.example', 'test', '0.0.1', :changing => true
|
74
|
+
end
|
75
|
+
end
|
76
|
+
it 'resolves a jar file' do
|
77
|
+
result = subject.resolve
|
78
|
+
result.should be_a Array
|
79
|
+
result.first.should be_a Ivy::Resolver::Artifact
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'requires the artifact' do
|
83
|
+
result = subject.resolve
|
84
|
+
result.first.require
|
85
|
+
Java::IvyResolverTestClass.new.test_value.should be_a String
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with a jruby project' do
|
90
|
+
around :each do |example|
|
91
|
+
old_pwd = Dir.pwd
|
92
|
+
|
93
|
+
begin
|
94
|
+
Dir.chdir spec_files_path
|
95
|
+
example.run
|
96
|
+
ensure
|
97
|
+
Dir.chdir old_pwd
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'runs setup' do
|
102
|
+
result = Ivy::Resolver.setup
|
103
|
+
result.should be_a Array
|
104
|
+
result.first.should be_a Ivy::Resolver::Artifact
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'requires the artifacts' do
|
108
|
+
Ivy::Resolver.require
|
109
|
+
Java::IvyResolverTestClass.new.test_value.should be_a String
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Released under the MIT license. See the MIT-LICENSE file for details
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
|
6
|
+
Bundler.require :test
|
7
|
+
|
8
|
+
require 'ivy-resolver'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
def spec_files_path(subpath=nil)
|
12
|
+
path = File.expand_path File.join(File.dirname(__FILE__), '..', 'spec_files')
|
13
|
+
if subpath
|
14
|
+
path = File.join(path, subpath)
|
15
|
+
end
|
16
|
+
path
|
17
|
+
end
|
18
|
+
end
|
data/spec_files/Jarfile
ADDED
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ivy-resolver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Shaun Mangelsdorf
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2012-01-19 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.8.0
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
description: Provides a Bundler-like interface to resolve JARs with Ivy
|
27
|
+
email:
|
28
|
+
- s.mangelsdorf@gmail.com
|
29
|
+
executables: []
|
30
|
+
|
31
|
+
extensions:
|
32
|
+
- jars/Rakefile
|
33
|
+
extra_rdoc_files: []
|
34
|
+
|
35
|
+
files:
|
36
|
+
- .gitignore
|
37
|
+
- Gemfile
|
38
|
+
- MIT-LICENSE
|
39
|
+
- Rakefile
|
40
|
+
- ivy-resolver.gemspec
|
41
|
+
- jars/Rakefile
|
42
|
+
- lib/ivy-resolver.rb
|
43
|
+
- lib/ivy/resolver.rb
|
44
|
+
- lib/ivy/resolver/artifact.rb
|
45
|
+
- lib/ivy/resolver/dsl.rb
|
46
|
+
- lib/ivy/resolver/version.rb
|
47
|
+
- spec/ivy_resolver_spec.rb
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
- spec_files/Jarfile
|
50
|
+
- spec_files/org/example/test/0.0.1/.gitignore
|
51
|
+
- spec_files/org/example/test/0.0.1/IvyResolverTestClass.java
|
52
|
+
homepage: ""
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
- jars
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: "0"
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project: ivy-resolver
|
76
|
+
rubygems_version: 1.8.9
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Resolve JAR files using Ivy under the covers
|
80
|
+
test_files: []
|
81
|
+
|