doubleshot 0.1.0-java → 0.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/Doubleshot +21 -10
- data/README.textile +13 -5
- data/bin/doubleshot +9 -1
- data/ext/java/Aether.java +199 -0
- data/ext/java/ManualWagonProvider.java +24 -0
- data/ext/java/SimpleRepositoryListener.java +77 -0
- data/lib/doubleshot.rb +155 -9
- data/lib/doubleshot/cli.rb +2 -1
- data/lib/doubleshot/cli/options.rb +3 -1
- data/lib/doubleshot/commands/build.rb +47 -9
- data/lib/doubleshot/commands/gem.rb +30 -9
- data/lib/doubleshot/commands/init.rb +41 -10
- data/lib/doubleshot/commands/install.rb +4 -4
- data/lib/doubleshot/commands/jar.rb +60 -2
- data/lib/doubleshot/commands/pom.rb +29 -0
- data/lib/doubleshot/commands/test.rb +85 -32
- data/lib/doubleshot/compiler.rb +20 -17
- data/lib/doubleshot/compiler/classpath.rb +46 -0
- data/lib/doubleshot/configuration.rb +158 -8
- data/lib/doubleshot/dependencies/dependency.rb +16 -15
- data/lib/doubleshot/dependencies/dependency_list.rb +20 -5
- data/lib/doubleshot/dependencies/gem_dependency.rb +35 -0
- data/lib/doubleshot/dependencies/gem_dependency_list.rb +1 -1
- data/lib/doubleshot/dependencies/jar_dependency.rb +64 -1
- data/lib/doubleshot/dependencies/jar_dependency_list.rb +1 -1
- data/lib/doubleshot/jar.rb +13 -2
- data/lib/doubleshot/lockfile.rb +108 -0
- data/lib/doubleshot/pom.rb +42 -0
- data/lib/doubleshot/readonly_collection.rb +6 -2
- data/lib/doubleshot/resolver.rb +22 -0
- data/lib/doubleshot/resolver/jar_resolver.rb +36 -0
- data/lib/doubleshot/setup.rb +1 -47
- data/lib/ruby/blank.rb +3 -3
- data/lib/ruby/pathname.rb +8 -4
- data/lib/ruby/time.rb +1 -2
- data/target/doubleshot.jar +0 -0
- data/test/compiler/classpath_spec.rb +74 -0
- data/test/compiler_spec.rb +89 -10
- data/test/configuration/source_locations_spec.rb +2 -2
- data/test/configuration_spec.rb +115 -17
- data/test/dependencies/dependency_list_spec.rb +26 -4
- data/test/dependencies/dependency_spec.rb +19 -18
- data/test/dependencies/gem_dependency_list_spec.rb +0 -0
- data/test/dependencies/gem_dependency_spec.rb +54 -0
- data/test/dependencies/jar_dependency_list_spec.rb +0 -0
- data/test/dependencies/jar_dependency_spec.rb +62 -1
- data/test/dependencies_spec.rb +4 -4
- data/test/doubleshot_spec.rb +34 -2
- data/test/helper.rb +36 -1
- data/test/lockfile_spec.rb +236 -0
- data/test/pom_spec.rb +66 -0
- data/test/readonly_collection_spec.rb +10 -3
- data/test/resolver/jar_resolver_spec.rb +34 -0
- data/test/resolver_spec.rb +25 -0
- metadata +28 -28
- data/ext/java/Empty.java +0 -0
data/Doubleshot
CHANGED
@@ -1,21 +1,33 @@
|
|
1
|
-
# encoding:
|
1
|
+
# encoding: utf-8
|
2
2
|
|
3
3
|
Doubleshot.new do |config|
|
4
4
|
|
5
|
+
config.project = "doubleshot"
|
6
|
+
config.group = "org.sam.doubleshot"
|
7
|
+
config.version = "0.2.0"
|
8
|
+
|
5
9
|
config.gem "bundler", ">= 0"
|
6
|
-
|
7
|
-
|
10
|
+
|
8
11
|
config.gem "rdoc", ">= 2.4.2"
|
9
12
|
config.gem "perfer", ">= 0"
|
10
13
|
config.gem "minitest", ">= 3.0.1"
|
11
14
|
config.gem "minitest-wscolor", ">= 0"
|
12
|
-
config.gem "listen", ">= 0"
|
13
|
-
config.gem "rb-fsevent", "
|
15
|
+
config.gem "listen", ">= 0.5.3"
|
16
|
+
config.gem "rb-fsevent", ">= 0.9.1"
|
14
17
|
config.gem "simplecov", ">= 0"
|
15
|
-
|
18
|
+
|
19
|
+
config.jar "org.sonatype.aether:aether-api:jar:1.13.1"
|
20
|
+
config.jar "org.sonatype.aether:aether-util:jar:1.13.1"
|
21
|
+
config.jar "org.sonatype.aether:aether-impl:jar:1.13.1"
|
22
|
+
config.jar "org.sonatype.aether:aether-connector-file:jar:1.13.1"
|
23
|
+
config.jar "org.sonatype.aether:aether-connector-asynchttpclient:jar:1.13.1"
|
24
|
+
config.jar "org.sonatype.aether:aether-connector-wagon:jar:1.13.1"
|
25
|
+
config.jar "org.apache.maven:maven-aether-provider:jar:3.0.4"
|
26
|
+
config.jar "org.apache.maven.wagon:wagon-file:jar:2.2"
|
27
|
+
config.jar "org.apache.maven.wagon:wagon-http:jar:2.2"
|
28
|
+
config.jar "org.apache.maven.wagon:wagon-provider-api:jar:2.2"
|
29
|
+
|
16
30
|
config.gemspec do |spec|
|
17
|
-
spec.name = "doubleshot"
|
18
|
-
spec.version = "0.1.0"
|
19
31
|
spec.summary = "Doubleshot is a build and dependency tool for mixed Java and Ruby projects"
|
20
32
|
spec.description = <<-DESCRIPTION
|
21
33
|
Doubleshot will download dependencies on demand, compile your Java sources and
|
@@ -27,7 +39,6 @@ DESCRIPTION
|
|
27
39
|
spec.author = "Sam Smoot"
|
28
40
|
spec.email = "ssmoot@gmail.com"
|
29
41
|
spec.license = "MIT-LICENSE"
|
30
|
-
spec.executables = ["doubleshot"]
|
31
42
|
end
|
32
43
|
|
33
|
-
end
|
44
|
+
end
|
data/README.textile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
h1. Doubleshot
|
2
2
|
|
3
|
-
Latest test results
|
3
|
+
Latest test results:
|
4
4
|
|
5
5
|
!https://secure.travis-ci.org/sam/doubleshot.png(Build Status)!:http://travis-ci.org/sam/doubleshot
|
6
6
|
|
@@ -131,6 +131,10 @@ Doubleshot also provides a @doubleshot@ bin file. Running @doubleshot test@ in y
|
|
131
131
|
|
132
132
|
This is the typical use-case for day to day development of new projects/features when using Doubleshot to manage your build process. It allows you to write and test new code, without ever having to restart your Java VM, saving you ten seconds or so for every run, encouraging continuous testing so you can spend more time writing code, and less time waiting for processes to load.
|
133
133
|
|
134
|
+
For your continuous testing/integration (CI) environment, you can also run all your tests just once by using the --ci-test option:
|
135
|
+
|
136
|
+
bc. doubleshot test --ci-test
|
137
|
+
|
134
138
|
h2. Packaging
|
135
139
|
|
136
140
|
# TODO: This is all out of date...
|
@@ -177,23 +181,27 @@ Bundler includes a @bundle show some_gem@ command that shows you the path where
|
|
177
181
|
|
178
182
|
It's our opinion that you don't _need_ this functionality, and it opens the window to abuse, so we're not implementing it.
|
179
183
|
|
180
|
-
h2.
|
184
|
+
h2. I just ran @doubleshot install@ and I'm not sure what happened?
|
181
185
|
|
182
186
|
With Bundler it's common to:
|
183
187
|
|
184
188
|
# @bundle install@ to inspect your Gemfile and download/install any missing dependencies
|
185
189
|
# @require "bundler/setup"@ to check/require dependencies at runtime
|
186
190
|
|
187
|
-
With Doubleshot you'll:
|
191
|
+
With Doubleshot you'll just:
|
188
192
|
|
189
|
-
bc. require "doubleshot
|
193
|
+
bc. require "doubleshot"
|
194
|
+
|
195
|
+
In your @test/helper.rb@ (or whatever common file you use for test bootstrapping). Or you can run @doubleshot test@.
|
190
196
|
|
191
197
|
Doubleshot will first see if all it's dependencies are available, and if not, install any that are missing. So you don't have to manually run an installation step.
|
192
198
|
|
199
|
+
If you run @doubleshot help@ you'll see that the @install@ command actually packages up your project as a Gem and installs it locally. So @doubleshot install@ is analogous to @gem install@, *not* @bundle install@.
|
200
|
+
|
193
201
|
bq.. But I just want to install my Gem dependencies on a remote server and not actually attempt to run any code!
|
194
202
|
*-- Said No One Ever*
|
195
203
|
|
196
|
-
p. If you _really_ want to pre-download your dependencies just run @
|
204
|
+
p. If you _really_ want to pre-download your dependencies just run @doubleshot build@ in your project's home-directory. Dependencies will be installed as part of the build process.
|
197
205
|
|
198
206
|
h2. What if I want to create a unified JAR containing all my dependencies?
|
199
207
|
|
data/bin/doubleshot
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
#!/usr/bin/env jruby
|
2
2
|
|
3
|
+
# encoding: utf-8
|
4
|
+
|
3
5
|
require "pathname"
|
4
6
|
require Pathname(__FILE__).dirname.parent + "lib/doubleshot"
|
5
7
|
require Pathname(__FILE__).dirname.parent + "lib/doubleshot/cli"
|
6
8
|
|
7
|
-
|
9
|
+
result = Doubleshot::CLI::start
|
10
|
+
|
11
|
+
case result
|
12
|
+
when Numeric then exit result
|
13
|
+
when nil then exit 0
|
14
|
+
else puts(result.inspect) and exit 1
|
15
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
// This class was lifted from the JBundler project:
|
2
|
+
// https://github.com/mkristian/jbundler
|
3
|
+
|
4
|
+
package org.sam.doubleshot;
|
5
|
+
|
6
|
+
import java.io.File;
|
7
|
+
import java.util.ArrayList;
|
8
|
+
import java.util.Collections;
|
9
|
+
import java.util.Iterator;
|
10
|
+
import java.util.LinkedList;
|
11
|
+
import java.util.List;
|
12
|
+
import java.util.HashMap;
|
13
|
+
|
14
|
+
import org.apache.maven.repository.internal.MavenRepositorySystemSession;
|
15
|
+
import org.apache.maven.repository.internal.MavenServiceLocator;
|
16
|
+
import org.sonatype.aether.RepositorySystem;
|
17
|
+
import org.sonatype.aether.RepositorySystemSession;
|
18
|
+
import org.sonatype.aether.artifact.Artifact;
|
19
|
+
import org.sonatype.aether.collection.CollectRequest;
|
20
|
+
import org.sonatype.aether.collection.DependencyCollectionException;
|
21
|
+
import org.sonatype.aether.connector.wagon.WagonProvider;
|
22
|
+
import org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory;
|
23
|
+
import org.sonatype.aether.graph.Dependency;
|
24
|
+
import org.sonatype.aether.graph.DependencyNode;
|
25
|
+
import org.sonatype.aether.impl.Installer;
|
26
|
+
import org.sonatype.aether.installation.InstallRequest;
|
27
|
+
import org.sonatype.aether.installation.InstallationException;
|
28
|
+
import org.sonatype.aether.repository.LocalRepository;
|
29
|
+
import org.sonatype.aether.repository.LocalRepositoryManager;
|
30
|
+
import org.sonatype.aether.repository.RemoteRepository;
|
31
|
+
import org.sonatype.aether.resolution.DependencyRequest;
|
32
|
+
import org.sonatype.aether.resolution.DependencyResolutionException;
|
33
|
+
import org.sonatype.aether.spi.connector.RepositoryConnectorFactory;
|
34
|
+
import org.sonatype.aether.spi.locator.ServiceLocator;
|
35
|
+
import org.sonatype.aether.util.artifact.DefaultArtifact;
|
36
|
+
import org.sonatype.aether.util.graph.PreorderNodeListGenerator;
|
37
|
+
|
38
|
+
public class Aether {
|
39
|
+
|
40
|
+
private DependencyNode node;
|
41
|
+
private RepositorySystem repoSystem;
|
42
|
+
private RepositorySystemSession session;
|
43
|
+
private List<Artifact> artifacts = new LinkedList<Artifact>();
|
44
|
+
private List<RemoteRepository> repos = new LinkedList<RemoteRepository>();
|
45
|
+
private Installer installer;
|
46
|
+
|
47
|
+
public Aether(String localRepo, boolean verbose, boolean offline){
|
48
|
+
ServiceLocator locator = newServiceLocator();
|
49
|
+
repoSystem = locator.getService( RepositorySystem.class );
|
50
|
+
installer = locator.getService( Installer.class );
|
51
|
+
|
52
|
+
session = newSession( repoSystem, localRepo, verbose, offline );
|
53
|
+
|
54
|
+
RemoteRepository central = new RemoteRepository( "central", "default", "http://repo1.maven.org/maven2/" );
|
55
|
+
repos.add(central);
|
56
|
+
}
|
57
|
+
|
58
|
+
private ServiceLocator newServiceLocator() {
|
59
|
+
MavenServiceLocator locator = new MavenServiceLocator();// when using maven 3.0.4
|
60
|
+
//locator.addService( RepositoryConnectorFactory.class, FileRepositoryConnectorFactory.class );
|
61
|
+
locator.addService( RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class );
|
62
|
+
|
63
|
+
locator.setServices( WagonProvider.class, new ManualWagonProvider() );
|
64
|
+
|
65
|
+
return locator;
|
66
|
+
}
|
67
|
+
|
68
|
+
private RepositorySystemSession newSession( RepositorySystem system, String localRepoPath, boolean verbose,
|
69
|
+
boolean offline ) {
|
70
|
+
MavenRepositorySystemSession session = new MavenRepositorySystemSession();
|
71
|
+
|
72
|
+
LocalRepository localRepo = new LocalRepository( localRepoPath );
|
73
|
+
session.setLocalRepositoryManager( system.newLocalRepositoryManager( localRepo ) );
|
74
|
+
session.setRepositoryListener( new SimpleRepositoryListener(verbose, session.getLocalRepositoryManager()) );
|
75
|
+
session.setOffline(offline);
|
76
|
+
return session;
|
77
|
+
}
|
78
|
+
|
79
|
+
public void addArtifact(String coordinate){
|
80
|
+
artifacts.add(new DefaultArtifact(coordinate));
|
81
|
+
}
|
82
|
+
|
83
|
+
public void addRepository(String id, String url){
|
84
|
+
repos.add(new RemoteRepository(id, "default", url));
|
85
|
+
}
|
86
|
+
|
87
|
+
public void resolve() throws DependencyCollectionException, DependencyResolutionException {
|
88
|
+
if (artifacts.size() == 0){
|
89
|
+
throw new IllegalArgumentException("no artifacts given");
|
90
|
+
}
|
91
|
+
|
92
|
+
CollectRequest collectRequest = new CollectRequest();
|
93
|
+
for( Artifact a: artifacts ){
|
94
|
+
collectRequest.addDependency( new Dependency( a, "compile" ) );
|
95
|
+
}
|
96
|
+
|
97
|
+
for( RemoteRepository r: repos ){
|
98
|
+
collectRequest.addRepository( r );
|
99
|
+
}
|
100
|
+
|
101
|
+
node = repoSystem.collectDependencies( session, collectRequest ).getRoot();
|
102
|
+
|
103
|
+
DependencyRequest dependencyRequest = new DependencyRequest( node, null );
|
104
|
+
|
105
|
+
repoSystem.resolveDependencies( session, dependencyRequest );
|
106
|
+
}
|
107
|
+
|
108
|
+
public List<RemoteRepository> getRepositories(){
|
109
|
+
return Collections.unmodifiableList( repos );
|
110
|
+
}
|
111
|
+
|
112
|
+
public List<Artifact> getArtifacts(){
|
113
|
+
return Collections.unmodifiableList( artifacts );
|
114
|
+
}
|
115
|
+
|
116
|
+
public String getClasspath() {
|
117
|
+
PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
|
118
|
+
node.accept( nlg );
|
119
|
+
|
120
|
+
StringBuilder buffer = new StringBuilder( 1024 );
|
121
|
+
|
122
|
+
for ( Iterator<DependencyNode> it = nlg.getNodes().iterator(); it.hasNext(); )
|
123
|
+
{
|
124
|
+
DependencyNode node = it.next();
|
125
|
+
if ( node.getDependency() != null )
|
126
|
+
{
|
127
|
+
Artifact artifact = node.getDependency().getArtifact();
|
128
|
+
// skip pom artifacts
|
129
|
+
if ( artifact.getFile() != null && !"pom".equals(artifact.getExtension()))
|
130
|
+
{
|
131
|
+
buffer.append( artifact.getFile().getAbsolutePath() );
|
132
|
+
if ( it.hasNext() )
|
133
|
+
{
|
134
|
+
buffer.append( File.pathSeparatorChar );
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
}
|
139
|
+
|
140
|
+
return buffer.toString();
|
141
|
+
}
|
142
|
+
|
143
|
+
public HashMap getClasspathMap() {
|
144
|
+
PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
|
145
|
+
node.accept( nlg );
|
146
|
+
|
147
|
+
HashMap<String,String> map = new HashMap<String,String>();
|
148
|
+
|
149
|
+
for ( Iterator<DependencyNode> it = nlg.getNodes().iterator(); it.hasNext(); ) {
|
150
|
+
DependencyNode node = it.next();
|
151
|
+
if ( node.getDependency() != null ) {
|
152
|
+
Artifact artifact = node.getDependency().getArtifact();
|
153
|
+
// skip pom artifacts
|
154
|
+
if ( artifact.getFile() != null && !"pom".equals(artifact.getExtension())) {
|
155
|
+
map.put(artifact.toString(), artifact.getFile().getAbsolutePath());
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
return map;
|
161
|
+
}
|
162
|
+
|
163
|
+
public List<String> getResolvedCoordinates() {
|
164
|
+
List<String> result = new ArrayList<String>();
|
165
|
+
|
166
|
+
PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
|
167
|
+
node.accept( nlg );
|
168
|
+
|
169
|
+
for ( DependencyNode node: nlg.getNodes() )
|
170
|
+
{
|
171
|
+
if ( node.getDependency() != null )
|
172
|
+
{
|
173
|
+
Artifact artifact = node.getDependency().getArtifact();
|
174
|
+
if ( artifact.getFile() != null)
|
175
|
+
{
|
176
|
+
StringBuilder coord = new StringBuilder(artifact.getGroupId()).append(":").append(artifact.getArtifactId())
|
177
|
+
.append(":").append(artifact.getExtension()).append(":").append(artifact.getVersion());
|
178
|
+
result.add(coord.toString());
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
return result;
|
184
|
+
}
|
185
|
+
|
186
|
+
public void install(String coordinate, String file) throws InstallationException{
|
187
|
+
LocalRepositoryManager lrm = session.getLocalRepositoryManager();
|
188
|
+
|
189
|
+
Artifact artifact = new DefaultArtifact(coordinate);
|
190
|
+
|
191
|
+
File dstFile = new File( lrm.getRepository().getBasedir(), lrm.getPathForLocalArtifact( artifact ) );
|
192
|
+
if (!dstFile.exists() ){
|
193
|
+
artifact = artifact.setFile(new File(file));
|
194
|
+
InstallRequest request = new InstallRequest();
|
195
|
+
request.addArtifact(artifact);
|
196
|
+
installer.install(session, request);
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
// This class was lifted from the JBundler project:
|
2
|
+
// https://github.com/mkristian/jbundler
|
3
|
+
|
4
|
+
package org.sam.doubleshot;
|
5
|
+
|
6
|
+
import org.apache.maven.wagon.Wagon;
|
7
|
+
import org.apache.maven.wagon.providers.http.HttpWagon;
|
8
|
+
import org.sonatype.aether.connector.wagon.WagonProvider;
|
9
|
+
|
10
|
+
public class ManualWagonProvider implements WagonProvider {
|
11
|
+
|
12
|
+
public Wagon lookup( String roleHint )
|
13
|
+
throws Exception {
|
14
|
+
if ( "http".equals( roleHint ) ) {
|
15
|
+
return new HttpWagon();
|
16
|
+
}
|
17
|
+
return null;
|
18
|
+
}
|
19
|
+
|
20
|
+
public void release( Wagon wagon ) {
|
21
|
+
|
22
|
+
}
|
23
|
+
|
24
|
+
}
|
@@ -0,0 +1,77 @@
|
|
1
|
+
// This class was lifted from the JBundler project:
|
2
|
+
// https://github.com/mkristian/jbundler
|
3
|
+
|
4
|
+
package org.sam.doubleshot;
|
5
|
+
|
6
|
+
import java.io.PrintStream;
|
7
|
+
|
8
|
+
import org.sonatype.aether.AbstractRepositoryListener;
|
9
|
+
import org.sonatype.aether.RepositoryEvent;
|
10
|
+
import org.sonatype.aether.repository.LocalRepositoryManager;
|
11
|
+
import org.sonatype.aether.repository.RemoteRepository;
|
12
|
+
|
13
|
+
public class SimpleRepositoryListener extends AbstractRepositoryListener {
|
14
|
+
|
15
|
+
private PrintStream out = System.out;
|
16
|
+
private PrintStream err = System.err;
|
17
|
+
private final boolean verbose;
|
18
|
+
private LocalRepositoryManager lrm;
|
19
|
+
|
20
|
+
public SimpleRepositoryListener(LocalRepositoryManager lrm) {
|
21
|
+
this(false, lrm);
|
22
|
+
}
|
23
|
+
|
24
|
+
public SimpleRepositoryListener(boolean verbose, LocalRepositoryManager lrm) {
|
25
|
+
this.verbose = verbose;
|
26
|
+
this.lrm = lrm;
|
27
|
+
}
|
28
|
+
|
29
|
+
public void artifactDescriptorInvalid(RepositoryEvent event) {
|
30
|
+
err.println("artifact descriptor invalid: " + event.getArtifact()
|
31
|
+
+ " : " + event.getException().getMessage());
|
32
|
+
}
|
33
|
+
|
34
|
+
public void artifactDescriptorMissing(RepositoryEvent event) {
|
35
|
+
err.println("artifact descriptor missing: " + event.getArtifact());
|
36
|
+
}
|
37
|
+
|
38
|
+
public void artifactInstalled(RepositoryEvent event) {
|
39
|
+
if (verbose) {
|
40
|
+
out.println("artifact installed: " + event.getArtifact() + " : "
|
41
|
+
+ event.getFile());
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
public void artifactResolved(RepositoryEvent event) {
|
46
|
+
if (verbose) {
|
47
|
+
out.println("artifact resolved: " + event.getArtifact() + " : "
|
48
|
+
+ event.getRepository().getId());
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
public void artifactDownloading(RepositoryEvent event) {
|
53
|
+
out.println("downloading " + toUrl(event));
|
54
|
+
}
|
55
|
+
|
56
|
+
private String toUrl(RepositoryEvent event) {
|
57
|
+
RemoteRepository repository = (RemoteRepository) event.getRepository();
|
58
|
+
String path = lrm.getPathForRemoteArtifact(event.getArtifact(), repository, null);
|
59
|
+
String url = repository.getUrl() + "/" + path;
|
60
|
+
return url;
|
61
|
+
}
|
62
|
+
|
63
|
+
public void artifactDownloaded(RepositoryEvent event) {
|
64
|
+
out.println("artifact downloaded: " + event.getArtifact());
|
65
|
+
}
|
66
|
+
|
67
|
+
public void metadataInvalid(RepositoryEvent event) {
|
68
|
+
err.println("metadata invalid: " + event.getMetadata());
|
69
|
+
}
|
70
|
+
|
71
|
+
public void metadataResolved(RepositoryEvent event) {
|
72
|
+
if (verbose) {
|
73
|
+
out.println("metadata resolved: " + event.getMetadata() + " : "
|
74
|
+
+ event.getRepository().getId());
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
data/lib/doubleshot.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require "java"
|
1
2
|
require "pathname"
|
2
3
|
require "set"
|
4
|
+
require "yaml"
|
3
5
|
|
4
6
|
$:.unshift(Pathname(__FILE__).dirname)
|
5
7
|
|
8
|
+
doubleshot_jar = Pathname(__FILE__).dirname.parent + "target/doubleshot.jar"
|
9
|
+
require doubleshot_jar if doubleshot_jar.exist?
|
10
|
+
|
6
11
|
require "ruby/gem/requirement"
|
7
12
|
require "ruby/string"
|
8
13
|
require "ruby/blank"
|
@@ -12,26 +17,167 @@ require "ruby/time"
|
|
12
17
|
require "doubleshot/readonly_collection"
|
13
18
|
require "doubleshot/configuration"
|
14
19
|
require "doubleshot/compiler"
|
20
|
+
require "doubleshot/lockfile"
|
15
21
|
|
16
22
|
class Doubleshot
|
17
|
-
|
23
|
+
|
24
|
+
attr_accessor :path
|
25
|
+
attr_reader :config
|
26
|
+
attr_reader :lockfile
|
27
|
+
attr_reader :classpath
|
28
|
+
|
29
|
+
def initialize
|
30
|
+
@classpath = Set.new
|
18
31
|
@config = Doubleshot::Configuration.new
|
19
|
-
|
32
|
+
@lockfile = Doubleshot::Lockfile.new
|
33
|
+
yield @config if block_given?
|
20
34
|
end
|
21
35
|
|
22
36
|
def build_gemspec
|
23
37
|
@config.gemspec.to_ruby
|
24
38
|
end
|
25
39
|
|
26
|
-
def config
|
27
|
-
@config
|
28
|
-
end
|
29
|
-
|
30
40
|
def self.current
|
31
41
|
@current ||= load
|
32
42
|
end
|
33
|
-
|
34
|
-
def self.load
|
35
|
-
|
43
|
+
|
44
|
+
def self.load(path = "Doubleshot")
|
45
|
+
path = Pathname(path)
|
46
|
+
doubleshot = eval(path.read)
|
47
|
+
doubleshot.path = path
|
48
|
+
doubleshot
|
49
|
+
end
|
50
|
+
|
51
|
+
# This modifies the current environment.
|
52
|
+
# Do not run this unless you really know what you're
|
53
|
+
# doing (modifying global shared state). The recommended
|
54
|
+
# way to call this, and ensure it's only called once for
|
55
|
+
# your current configuration, is to:
|
56
|
+
# require "doubleshot/setup"
|
57
|
+
def setup!
|
58
|
+
# This will add your compiled sources to $CLASSPATH so
|
59
|
+
# you can reference your Java classes in Ruby.
|
60
|
+
$CLASSPATH << @config.target.to_url if @config.target.exist?
|
61
|
+
|
62
|
+
# BEGIN: Cleanup tasks
|
63
|
+
#
|
64
|
+
# Delete +lockfile+ and +classpath_file+ if the
|
65
|
+
# Doubleshot file has been modified since they were written.
|
66
|
+
#
|
67
|
+
# SCENARIO: You will run into this if you've added a new dependency
|
68
|
+
# (or made any other change) to your Doubleshot configuration file.
|
69
|
+
if path.exist? && lockfile.exist? && path.mtime > lockfile.mtime
|
70
|
+
lockfile.delete
|
71
|
+
classpath_cache.delete if classpath_cache.exist?
|
72
|
+
end
|
73
|
+
|
74
|
+
# If the above is not true, your Doubleshot file hasn't
|
75
|
+
# been modified, but you may have updated the +lockfile+,
|
76
|
+
# in which case we need to check if the classpath_cache is
|
77
|
+
# still current, or needs to be flushed.
|
78
|
+
#
|
79
|
+
# SCENARIO: You will typically run into this if you've cloned
|
80
|
+
# a Doubleshotted project, where the Doubleshot file and Lockfile
|
81
|
+
# have been committed to the repository, but you have not ever
|
82
|
+
# started the project on your local machine.
|
83
|
+
if lockfile.exist? && classpath_cache.exist? && lockfile.mtime > classpath_cache.mtime
|
84
|
+
classpath_cache.delete
|
85
|
+
end
|
86
|
+
# END: Cleanup tasks
|
87
|
+
|
88
|
+
load_jars! unless @config.runtime.jars.empty? && @config.development.jars.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
def load_jars!
|
92
|
+
if classpath_cache.exist?
|
93
|
+
# We survived the cleanup checks, go ahead and just load
|
94
|
+
# the cached version of your JARs.
|
95
|
+
cached_paths = YAML::load(classpath_cache)
|
96
|
+
|
97
|
+
lockfile.jars.each do |jar|
|
98
|
+
jar.path = cached_paths[jar.to_s]
|
99
|
+
begin
|
100
|
+
require jar.path
|
101
|
+
self.classpath << jar.path
|
102
|
+
rescue LoadError
|
103
|
+
warn "Could not load: #{jar.path.inspect}"
|
104
|
+
raise
|
105
|
+
end
|
106
|
+
end
|
107
|
+
else
|
108
|
+
# No classpath_cache exists, we must resolve the paths
|
109
|
+
# to our dependencies, then store the results in
|
110
|
+
# classpath_cache for future processes to use.
|
111
|
+
require "doubleshot/resolver"
|
112
|
+
|
113
|
+
if @config.mvn_repositories.empty?
|
114
|
+
@config.mvn_repository Resolver::JarResolver::DEFAULT_REPOSITORY
|
115
|
+
end
|
116
|
+
|
117
|
+
resolver = Resolver::JarResolver.new(*@config.mvn_repositories)
|
118
|
+
jars = nil
|
119
|
+
|
120
|
+
if lockfile.exist?
|
121
|
+
jars = Dependencies::JarDependencyList.new
|
122
|
+
lockfile.jars.each do |jar|
|
123
|
+
jars.add jar
|
124
|
+
end
|
125
|
+
else
|
126
|
+
jars = @config.runtime.jars + @config.development.jars
|
127
|
+
end
|
128
|
+
|
129
|
+
resolver.resolve! jars
|
130
|
+
|
131
|
+
jars.each { |jar| lockfile.add jar }
|
132
|
+
lockfile.flush!
|
133
|
+
|
134
|
+
cache = {}
|
135
|
+
jars.each do |jar|
|
136
|
+
cache[jar.to_s] = jar.path
|
137
|
+
begin
|
138
|
+
require jar.path
|
139
|
+
self.classpath << jar.path
|
140
|
+
rescue LoadError
|
141
|
+
warn "Could not load: #{jar.path.inspect}"
|
142
|
+
raise
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
classpath_cache.open("w+") do |file|
|
147
|
+
file << cache.to_yaml
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def classpath_cache
|
153
|
+
@classpath_cache ||= Pathname(".classpath.cache")
|
154
|
+
end
|
155
|
+
|
156
|
+
def bootstrap!
|
157
|
+
if !@config.target.exist? || !lockfile.exist? || !classpath_cache.exist? || Pathname("pom.xml").mtime > classpath_cache.mtime
|
158
|
+
# Dependencies classpath:
|
159
|
+
paths = `mvn dependency:build-classpath`.split(/\bDependencies classpath\b/).last.split($/).grep(/\.jar\b/).map { |line| line.split(":") }.flatten
|
160
|
+
coordinates = `mvn dependency:list`.split(/\bfiles have been resolved\b/).last.split($/).grep(/\bcompile$/).map do |line|
|
161
|
+
line.split.last.sub /\:compile$/, ""
|
162
|
+
end
|
163
|
+
|
164
|
+
resolved = Hash[*coordinates.zip(paths).flatten]
|
165
|
+
|
166
|
+
resolved.each_pair do |coordinate, path|
|
167
|
+
require path
|
168
|
+
self.classpath << path
|
169
|
+
jar = Dependencies::JarDependency.new(coordinate)
|
170
|
+
jar.path = path
|
171
|
+
lockfile.add jar
|
172
|
+
end
|
173
|
+
|
174
|
+
lockfile.flush!
|
175
|
+
|
176
|
+
classpath_cache.open("w+") do |file|
|
177
|
+
file << resolved.to_yaml
|
178
|
+
end
|
179
|
+
else
|
180
|
+
setup!
|
181
|
+
end
|
36
182
|
end
|
37
183
|
end
|