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.
Files changed (56) hide show
  1. data/Doubleshot +21 -10
  2. data/README.textile +13 -5
  3. data/bin/doubleshot +9 -1
  4. data/ext/java/Aether.java +199 -0
  5. data/ext/java/ManualWagonProvider.java +24 -0
  6. data/ext/java/SimpleRepositoryListener.java +77 -0
  7. data/lib/doubleshot.rb +155 -9
  8. data/lib/doubleshot/cli.rb +2 -1
  9. data/lib/doubleshot/cli/options.rb +3 -1
  10. data/lib/doubleshot/commands/build.rb +47 -9
  11. data/lib/doubleshot/commands/gem.rb +30 -9
  12. data/lib/doubleshot/commands/init.rb +41 -10
  13. data/lib/doubleshot/commands/install.rb +4 -4
  14. data/lib/doubleshot/commands/jar.rb +60 -2
  15. data/lib/doubleshot/commands/pom.rb +29 -0
  16. data/lib/doubleshot/commands/test.rb +85 -32
  17. data/lib/doubleshot/compiler.rb +20 -17
  18. data/lib/doubleshot/compiler/classpath.rb +46 -0
  19. data/lib/doubleshot/configuration.rb +158 -8
  20. data/lib/doubleshot/dependencies/dependency.rb +16 -15
  21. data/lib/doubleshot/dependencies/dependency_list.rb +20 -5
  22. data/lib/doubleshot/dependencies/gem_dependency.rb +35 -0
  23. data/lib/doubleshot/dependencies/gem_dependency_list.rb +1 -1
  24. data/lib/doubleshot/dependencies/jar_dependency.rb +64 -1
  25. data/lib/doubleshot/dependencies/jar_dependency_list.rb +1 -1
  26. data/lib/doubleshot/jar.rb +13 -2
  27. data/lib/doubleshot/lockfile.rb +108 -0
  28. data/lib/doubleshot/pom.rb +42 -0
  29. data/lib/doubleshot/readonly_collection.rb +6 -2
  30. data/lib/doubleshot/resolver.rb +22 -0
  31. data/lib/doubleshot/resolver/jar_resolver.rb +36 -0
  32. data/lib/doubleshot/setup.rb +1 -47
  33. data/lib/ruby/blank.rb +3 -3
  34. data/lib/ruby/pathname.rb +8 -4
  35. data/lib/ruby/time.rb +1 -2
  36. data/target/doubleshot.jar +0 -0
  37. data/test/compiler/classpath_spec.rb +74 -0
  38. data/test/compiler_spec.rb +89 -10
  39. data/test/configuration/source_locations_spec.rb +2 -2
  40. data/test/configuration_spec.rb +115 -17
  41. data/test/dependencies/dependency_list_spec.rb +26 -4
  42. data/test/dependencies/dependency_spec.rb +19 -18
  43. data/test/dependencies/gem_dependency_list_spec.rb +0 -0
  44. data/test/dependencies/gem_dependency_spec.rb +54 -0
  45. data/test/dependencies/jar_dependency_list_spec.rb +0 -0
  46. data/test/dependencies/jar_dependency_spec.rb +62 -1
  47. data/test/dependencies_spec.rb +4 -4
  48. data/test/doubleshot_spec.rb +34 -2
  49. data/test/helper.rb +36 -1
  50. data/test/lockfile_spec.rb +236 -0
  51. data/test/pom_spec.rb +66 -0
  52. data/test/readonly_collection_spec.rb +10 -3
  53. data/test/resolver/jar_resolver_spec.rb +34 -0
  54. data/test/resolver_spec.rb +25 -0
  55. metadata +28 -28
  56. data/ext/java/Empty.java +0 -0
data/Doubleshot CHANGED
@@ -1,21 +1,33 @@
1
- # encoding: UTF-8
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
- config.gem "jbundler", ">= 0"
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", "~> 0.9.1"
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 (currently Travis CI's JRuby ~1.7 mode is broken as it runs `bundle install` but doesn't have the Bundler gem installed):
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. Where is @doubleshot install@?
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/setup"
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 @jruby -r "doubleshot/setup"@ in your project's home-directory. Nothing to it.
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
- exit Doubleshot::CLI::start ? 0 : 1
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
- def initialize(&b)
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
- yield @config
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
- eval(Pathname("Doubleshot").read)
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