doubleshot 0.2.0-java → 0.3.0-java

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.
Files changed (47) hide show
  1. data/Doubleshot +16 -6
  2. data/README-OLD.textile +216 -0
  3. data/README.textile +38 -182
  4. data/lib/doubleshot.rb +100 -39
  5. data/lib/doubleshot/commands/gem.rb +15 -12
  6. data/lib/doubleshot/commands/test.rb +38 -5
  7. data/lib/doubleshot/configuration.rb +2 -2
  8. data/lib/doubleshot/dependencies/dependency.rb +1 -1
  9. data/lib/doubleshot/dependencies/gem_dependency.rb +2 -10
  10. data/lib/doubleshot/dependencies/jar_dependency.rb +12 -2
  11. data/lib/doubleshot/lockfile.rb +9 -6
  12. data/lib/doubleshot/pom.rb +15 -2
  13. data/lib/doubleshot/resolver.rb +1 -0
  14. data/lib/doubleshot/resolver/gem_resolver.rb +45 -0
  15. data/lib/doubleshot/resolver/gem_resolver/artifact.rb +146 -0
  16. data/lib/doubleshot/resolver/gem_resolver/demand.rb +57 -0
  17. data/lib/doubleshot/resolver/gem_resolver/dependency.rb +57 -0
  18. data/lib/doubleshot/resolver/gem_resolver/errors.rb +37 -0
  19. data/lib/doubleshot/resolver/gem_resolver/gem_source.rb +58 -0
  20. data/lib/doubleshot/resolver/gem_resolver/graph.rb +200 -0
  21. data/lib/doubleshot/resolver/gem_resolver/solver.rb +279 -0
  22. data/lib/doubleshot/resolver/gem_resolver/solver/constraint_row.rb +29 -0
  23. data/lib/doubleshot/resolver/gem_resolver/solver/constraint_table.rb +35 -0
  24. data/lib/doubleshot/resolver/gem_resolver/solver/variable_row.rb +47 -0
  25. data/lib/doubleshot/resolver/gem_resolver/solver/variable_table.rb +59 -0
  26. data/lib/doubleshot/resolver/gem_resolver/source.rb +36 -0
  27. data/lib/doubleshot/resolver/jar_resolver.rb +1 -3
  28. data/lib/ruby/gem/requirement.rb +9 -0
  29. data/target/doubleshot.jar +0 -0
  30. data/test/compiler_spec.rb +31 -3
  31. data/test/configuration_spec.rb +11 -3
  32. data/test/dependencies/gem_dependency_spec.rb +3 -17
  33. data/test/dependencies/jar_dependency_spec.rb +20 -0
  34. data/test/helper.rb +3 -1
  35. data/test/helpers/stub_source.rb +120 -0
  36. data/test/lockfile_spec.rb +9 -17
  37. data/test/pom_spec.rb +31 -1
  38. data/test/resolver/gem_resolver/artifact_spec.rb +106 -0
  39. data/test/resolver/gem_resolver/demand_spec.rb +70 -0
  40. data/test/resolver/gem_resolver/dependency_spec.rb +33 -0
  41. data/test/resolver/gem_resolver/gem_source_spec.rb +28 -0
  42. data/test/resolver/gem_resolver/graph_spec.rb +239 -0
  43. data/test/resolver/gem_resolver/solver_spec.rb +449 -0
  44. data/test/resolver/gem_resolver/source_spec.rb +18 -0
  45. data/test/resolver/gem_resolver_spec.rb +102 -0
  46. metadata +35 -73
  47. data/lib/doubleshot/jar.rb +0 -62
@@ -19,4 +19,5 @@ class Doubleshot
19
19
  end
20
20
  end
21
21
 
22
+ require "doubleshot/resolver/gem_resolver"
22
23
  require "doubleshot/resolver/jar_resolver"
@@ -0,0 +1,45 @@
1
+ class Doubleshot
2
+ class Resolver
3
+ class GemResolver < Resolver
4
+ DEFAULT_REPOSITORY = "http://rubygems.org"
5
+
6
+ def initialize(*repositories)
7
+ super
8
+ @graph = Graph.new(*repositories)
9
+ end
10
+
11
+ def resolve!(dependencies)
12
+ demands = dependencies.map do |dependency|
13
+ if dependency.requirements.empty?
14
+ dependency.name
15
+ else
16
+ [ dependency.name, *dependency.requirements.map { |requirement| requirement.to_s } ]
17
+ end
18
+ end
19
+
20
+ ui = Class.new do
21
+ def say(*args)
22
+ STDERR.puts *args
23
+ end
24
+ end.new
25
+ ui = nil
26
+ results = Solver.new(@graph, demands, ui).resolve
27
+
28
+ results.each_pair do |name, version|
29
+ dependencies.fetch(name).lock(version)
30
+ end
31
+
32
+ dependencies
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+
39
+ require "doubleshot/resolver/gem_resolver/source"
40
+ require "doubleshot/resolver/gem_resolver/artifact"
41
+ require "doubleshot/resolver/gem_resolver/demand"
42
+ require "doubleshot/resolver/gem_resolver/dependency"
43
+ require "doubleshot/resolver/gem_resolver/errors"
44
+ require "doubleshot/resolver/gem_resolver/graph"
45
+ require "doubleshot/resolver/gem_resolver/solver"
@@ -0,0 +1,146 @@
1
+ class Doubleshot
2
+ class Resolver
3
+ class GemResolver
4
+ class Artifact
5
+ include Comparable
6
+
7
+ # A reference to the graph this artifact belongs to
8
+ #
9
+ # @return [Doubleshot::Resolver::GemResolver::Graph]
10
+ attr_reader :graph
11
+
12
+ # The name of the artifact
13
+ #
14
+ # @return [String]
15
+ attr_reader :name
16
+
17
+ # The version of this artifact
18
+ #
19
+ # @return [Gem::Version]
20
+ attr_reader :version
21
+
22
+ # @param [Doubleshot::Resolver::GemResolver::Graph] graph
23
+ # @param [#to_s] name
24
+ # @param [Gem::Version, #to_s] version
25
+ def initialize(graph, name, version)
26
+ @graph = graph
27
+ @name = name
28
+ @version = Gem::Version.new(version)
29
+ @dependencies = Hash.new
30
+ end
31
+
32
+ # Return the Doubleshot::Resolver::GemResolver::Dependency from the collection of
33
+ # dependencies with the given name and constraint.
34
+ #
35
+ # @param [#to_s] name
36
+ # @param [Gem::Requirement, #to_s] constraint
37
+ #
38
+ # @example adding dependencies
39
+ # artifact.depends("nginx") => <#Dependency: @name="nginx", @constraint=">= 0.0.0">
40
+ # artifact.depends("ntp", "= 1.0.0") => <#Dependency: @name="ntp", @constraint="= 1.0.0">
41
+ #
42
+ # @example chaining dependencies
43
+ # artifact.depends("nginx").depends("ntp")
44
+ #
45
+ # @return [Doubleshot::Resolver::GemResolver::Artifact]
46
+ def depends(name, constraint = ">= 0")
47
+ if name.nil?
48
+ raise ArgumentError, "A name must be specified. You gave: #{args}."
49
+ end
50
+
51
+ dependency = Dependency.new(self, name, constraint)
52
+ add_dependency(dependency)
53
+
54
+ self
55
+ end
56
+
57
+ # Return the collection of dependencies on this instance of artifact
58
+ #
59
+ # @return [Array<Doubleshot::Resolver::GemResolver::Dependency>]
60
+ def dependencies
61
+ @dependencies.collect { |name, dependency| dependency }
62
+ end
63
+
64
+ # Retrieve the dependency from the artifact with the matching name and constraint
65
+ #
66
+ # @param [#to_s] name
67
+ # @param [#to_s] constraint
68
+ #
69
+ # @return [Doubleshot::Resolver::GemResolver::Artifact, nil]
70
+ def get_dependency(name, constraint)
71
+ @dependencies.fetch(Graph.dependency_key(name, constraint), nil)
72
+ end
73
+
74
+ # Remove this artifact from the graph it belongs to
75
+ #
76
+ # @return [Doubleshot::Resolver::GemResolver::Artifact, nil]
77
+ def delete
78
+ unless graph.nil?
79
+ result = graph.remove_artifact(self)
80
+ @graph = nil
81
+ result
82
+ end
83
+ end
84
+
85
+ def to_s
86
+ "#{name}-#{version}"
87
+ end
88
+
89
+ # @param [Object] other
90
+ #
91
+ # @return [Boolean]
92
+ def ==(other)
93
+ other.is_a?(self.class) &&
94
+ self.name == other.name &&
95
+ self.version == other.version
96
+ end
97
+ alias_method :eql?, :==
98
+
99
+ # @param [Gem::Version] other
100
+ #
101
+ # @return [Integer]
102
+ def <=>(other)
103
+ self.version <=> other.version
104
+ end
105
+
106
+ private
107
+
108
+ # Add a Doubleshot::Resolver::GemResolver::Dependency to the collection of dependencies
109
+ # and return the added Doubleshot::Resolver::GemResolver::Dependency. No change will be
110
+ # made if the dependency is already a member of the collection.
111
+ #
112
+ # @param [Doubleshot::Resolver::GemResolver::Dependency] dependency
113
+ #
114
+ # @return [Doubleshot::Resolver::GemResolver::Dependency]
115
+ def add_dependency(dependency)
116
+ unless has_dependency?(dependency.name, dependency.constraint)
117
+ @dependencies[Graph.key_for(dependency)] = dependency
118
+ end
119
+
120
+ get_dependency(dependency.name, dependency.constraint)
121
+ end
122
+
123
+ # Remove the matching dependency from the artifact
124
+ #
125
+ # @param [Doubleshot::Resolver::GemResolver::Dependency] dependency
126
+ #
127
+ # @return [Doubleshot::Resolver::GemResolver::Dependency, nil]
128
+ def remove_dependency(dependency)
129
+ if has_dependency?(dependency)
130
+ @dependencies.delete(Graph.key_for(dependency))
131
+ end
132
+ end
133
+
134
+ # Check if the artifact has a dependency with the matching name and constraint
135
+ #
136
+ # @param [#to_s] name
137
+ # @param [#to_s] constraint
138
+ #
139
+ # @return [Boolean]
140
+ def has_dependency?(name, constraint)
141
+ @dependencies.has_key?(Graph.dependency_key(name, constraint))
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,57 @@
1
+ class Doubleshot
2
+ class Resolver
3
+ class GemResolver
4
+ class Demand
5
+ # A reference to the solver this demand belongs to
6
+ #
7
+ # @return [Doubleshot::Resolver::GemResolver::Solver]
8
+ attr_reader :solver
9
+
10
+ # The name of the artifact this demand is for
11
+ #
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ # The acceptable constraint of the artifact this demand is for
16
+ #
17
+ # @return [Gem::Requirement]
18
+ attr_reader :constraint
19
+
20
+ # @param [Doubleshot::Resolver::GemResolver::Solver] solver
21
+ # @param [#to_s] name
22
+ # @param [Gem::Requirement, #to_s] constraint
23
+ def initialize(solver, name, constraint = ">= 0")
24
+ @solver = solver
25
+ @name = name
26
+ @constraint = if constraint.is_a?(Gem::Requirement)
27
+ constraint
28
+ else
29
+ Gem::Requirement.new(constraint.to_s)
30
+ end
31
+ end
32
+
33
+ # Remove this demand from the solver it belongs to
34
+ #
35
+ # @return [Doubleshot::Resolver::GemResolver::Demand, nil]
36
+ def delete
37
+ unless solver.nil?
38
+ result = solver.remove_demand(self)
39
+ @solver = nil
40
+ result
41
+ end
42
+ end
43
+
44
+ def to_s
45
+ "#{name} (#{constraint})"
46
+ end
47
+
48
+ def ==(other)
49
+ other.is_a?(self.class) &&
50
+ self.name == other.name &&
51
+ self.constraint == other.constraint
52
+ end
53
+ alias_method :eql?, :==
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ class Doubleshot
2
+ class Resolver
3
+ class GemResolver
4
+ class Dependency
5
+ # A reference to the artifact this dependency belongs to
6
+ #
7
+ # @return [Doubleshot::Resolver::GemResolver::Artifact]
8
+ attr_reader :artifact
9
+
10
+ # The name of the artifact this dependency represents
11
+ #
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ # The constraint requirement of this dependency
16
+ #
17
+ # @return [Gem::Requirement]
18
+ attr_reader :constraint
19
+
20
+ # @param [Doubleshot::Resolver::GemResolver::Artifact] artifact
21
+ # @param [#to_s] name
22
+ # @param [Gem::Requirement, #to_s] constraint
23
+ def initialize(artifact, name, constraint = ">= 0")
24
+ @artifact = artifact
25
+ @name = name
26
+ @constraint = case constraint
27
+ when Gem::Requirement
28
+ constraint
29
+ else
30
+ Gem::Requirement.new(constraint)
31
+ end
32
+ end
33
+
34
+ # Remove this dependency from the artifact it belongs to
35
+ #
36
+ # @return [Doubleshot::Resolver::GemResolver::Dependency, nil]
37
+ def delete
38
+ unless artifact.nil?
39
+ result = artifact.remove_dependency(self)
40
+ @artifact = nil
41
+ result
42
+ end
43
+ end
44
+
45
+ # @param [Object] other
46
+ #
47
+ # @return [Boolean]
48
+ def ==(other)
49
+ other.is_a?(self.class) &&
50
+ self.artifact == other.artifact &&
51
+ self.constraint == other.constraint
52
+ end
53
+ alias_method :eql?, :==
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ class Doubleshot
2
+ class Resolver
3
+ class GemResolver
4
+ module Errors
5
+ class Doubleshot::Resolver::GemResolverError < StandardError; end
6
+
7
+ class InvalidVersionFormat < Doubleshot::Resolver::GemResolverError
8
+ attr_reader :version
9
+
10
+ # @param [#to_s] version
11
+ def initialize(version)
12
+ @version = version
13
+ end
14
+
15
+ def message
16
+ "'#{version}' did not contain a valid version string: 'x.y.z' or 'x.y'."
17
+ end
18
+ end
19
+
20
+ class InvalidConstraintFormat < Doubleshot::Resolver::GemResolverError
21
+ attr_reader :constraint
22
+
23
+ # @param [#to_s] constraint
24
+ def initialize(constraint)
25
+ @constraint = constraint
26
+ end
27
+
28
+ def message
29
+ "'#{constraint}' did not contain a valid operator or a valid version string."
30
+ end
31
+ end
32
+
33
+ class NoSolutionError < Doubleshot::Resolver::GemResolverError; end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,58 @@
1
+ require "open-uri"
2
+ require "zlib"
3
+
4
+ class Doubleshot
5
+ class Resolver
6
+ class GemResolver
7
+ class GemSource < Source
8
+
9
+ map :http, :https
10
+
11
+ SUPPORTED_PLATFORMS = [ /\bjava\b/i, /^jruby$/i, /^ruby$/i ]
12
+
13
+ def versions(name)
14
+ __versions__[name]
15
+ end
16
+
17
+ def spec(name, version)
18
+ __specs__[name][version]
19
+ end
20
+
21
+ private
22
+ def __specs__
23
+ @specs ||= begin
24
+ Hash.new do |h,name|
25
+ h[name] = Hash.new do |h2,version|
26
+ begin
27
+ puts "Loading Gem::Specification for #{name}:#{version}..."
28
+ Marshal.load(Gem.inflate(open(
29
+ "#{@uri.to_s.ensure_ends_with("/")}quick/Marshal.4.8/#{name}-#{version}.gemspec.rz"
30
+ ).read))
31
+ rescue
32
+ puts "Gem::Specification for #{name}:#{version} not found!"
33
+ nil
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def __versions__
41
+ @versions ||= Hash.new do |h,k|
42
+ versions = h[k] = []
43
+ dep = Gem::Dependency.new(k, Gem::Requirement::default)
44
+ puts "Fetching list of versions for #{k.inspect}"
45
+ Gem::SpecFetcher::fetcher.find_matching(dep, true, false, false).map do |entry|
46
+ if tuple = entry.first
47
+ if SUPPORTED_PLATFORMS.any? { |platform| tuple.last =~ platform }
48
+ versions << tuple[1]
49
+ end # if SUPPORTED_PLATFORMS
50
+ end # if tuple = entry.first
51
+ end # Gem::SpecFetcher::fetcher.find_matching
52
+ versions
53
+ end # Hash.new
54
+ end # __versions__
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,200 @@
1
+ class Doubleshot
2
+ class Resolver
3
+ class GemResolver
4
+ class Graph
5
+ # Create a key for a graph from an instance of an Artifact or Dependency
6
+ #
7
+ # @param [Doubleshot::Resolver::GemResolver::Artifact, Doubleshot::Resolver::GemResolver::Dependency] object
8
+ #
9
+ # @raise [ArgumentError] if an instance of an object of an unknown type is given
10
+ #
11
+ # @return [Symbol]
12
+ def self.key_for(object)
13
+ case object
14
+ when Doubleshot::Resolver::GemResolver::Artifact
15
+ artifact_key(object.name, object.version)
16
+ when Doubleshot::Resolver::GemResolver::Dependency
17
+ dependency_key(object.name, object.constraint)
18
+ else
19
+ raise ArgumentError, "Could not generate graph key for Class: #{object.class}"
20
+ end
21
+ end
22
+
23
+ # Create a key representing an artifact for an instance of Graph
24
+ #
25
+ # @param [#to_s] name
26
+ # @param [#to_s] version
27
+ #
28
+ # @return [Symbol]
29
+ def self.artifact_key(name, version)
30
+ "#{name}-#{version}".to_sym
31
+ end
32
+
33
+ # Create a key representing an dependency for an instance of Graph
34
+ #
35
+ # @param [#to_s] name
36
+ # @param [#to_s] constraint
37
+ #
38
+ # @return [Symbol]
39
+ def self.dependency_key(name, constraint)
40
+ "#{name}-#{constraint}".to_sym
41
+ end
42
+
43
+ def initialize(*repositories)
44
+ @sources = repositories.map do |repository|
45
+ Source.new(repository)
46
+ end
47
+ @versions = Hash.new
48
+ @artifacts = Hash.new
49
+ end
50
+
51
+ # @overload artifacts(name, version)
52
+ # Return the Doubleshot::Resolver::GemResolver::Artifact from the collection of artifacts
53
+ # with the given name and version.
54
+ #
55
+ # @param [#to_s]
56
+ # @param [Gem::Version, #to_s]
57
+ #
58
+ # @return [Doubleshot::Resolver::GemResolver::Artifact]
59
+ # @overload artifacts
60
+ # Return the collection of artifacts
61
+ #
62
+ # @return [Array<Doubleshot::Resolver::GemResolver::Artifact>]
63
+ def artifacts(*args)
64
+ if args.empty?
65
+ return artifact_collection
66
+ end
67
+ unless args.length == 2
68
+ raise ArgumentError, "Unexpected number of arguments. You gave: #{args.length}. Expected: 0 or 2."
69
+ end
70
+
71
+ name, version = args
72
+
73
+ if name.nil? || version.nil?
74
+ raise ArgumentError, "A name and version must be specified. You gave: #{args}."
75
+ end
76
+
77
+ artifact = Artifact.new(self, name, version)
78
+ add_artifact(artifact)
79
+ end
80
+
81
+ # Return all the artifacts from the collection of artifacts
82
+ # with the given name.
83
+ #
84
+ # @param [String] name
85
+ #
86
+ # @return [Array<Doubleshot::Resolver::GemResolver::Artifact>]
87
+ def versions(name, constraint = ">= 0.0.0")
88
+ constraint = constraint.is_a?(Gem::Requirement) ? constraint : Gem::Requirement.new(constraint)
89
+
90
+ if @sources.empty?
91
+ # ORIGINAL CODE FROM Solve PROJECT. DO NOT TOUCH!
92
+ artifacts.select do |artifact|
93
+ artifact.name == name && constraint.satisfied_by?(artifact.version)
94
+ end
95
+ else
96
+ @sources.map do |source|
97
+ source.versions(name).select do |version|
98
+ constraint.satisfied_by?(version)
99
+ end.map do |version|
100
+ Artifact.new(self, name, version)
101
+ end
102
+ end.flatten
103
+ end
104
+ end
105
+
106
+ # Add a Doubleshot::Resolver::GemResolver::Artifact to the collection of artifacts and
107
+ # return the added Doubleshot::Resolver::GemResolver::Artifact. No change will be made
108
+ # if the artifact is already a member of the collection.
109
+ #
110
+ # @param [Doubleshot::Resolver::GemResolver::Artifact] artifact
111
+ #
112
+ # @return [Doubleshot::Resolver::GemResolver::Artifact]
113
+ def add_artifact(artifact)
114
+ unless has_artifact?(artifact.name, artifact.version)
115
+ @artifacts[self.class.key_for(artifact)] = artifact
116
+ end
117
+
118
+ get_artifact(artifact.name, artifact.version)
119
+ end
120
+
121
+ # Retrieve the artifact from the graph with the matching name and version
122
+ #
123
+ # @param [String] name
124
+ # @param [Gem::Version, #to_s] version
125
+ #
126
+ # @return [Doubleshot::Resolver::GemResolver::Artifact, nil]
127
+ def get_artifact(name, version)
128
+ if @sources.empty?
129
+ @artifacts.fetch(self.class.artifact_key(name, version.to_s), nil)
130
+ else
131
+ artifact = nil
132
+ @sources.any? do |source|
133
+ if spec = source.spec(name, version)
134
+ artifact = Artifact.new(self, name, version)
135
+ spec.runtime_dependencies.each do |dependency|
136
+ dependency.requirements_list.each do |requirement|
137
+ artifact.depends(dependency.name, requirement.to_s)
138
+ end
139
+ end
140
+ true
141
+ end
142
+ end
143
+ artifact
144
+ end
145
+ end
146
+
147
+ # Remove the given instance of artifact from the graph
148
+ #
149
+ # @param [Doubleshot::Resolver::GemResolver::Artifact, nil] artifact
150
+ def remove_artifact(artifact)
151
+ if has_artifact?(artifact.name, artifact.version)
152
+ @artifacts.delete(self.class.key_for(artifact))
153
+ end
154
+ end
155
+
156
+ # Check if an artifact with a matching name and version is a member of this instance
157
+ # of graph
158
+ #
159
+ # @param [String] name
160
+ # @param [Gem::Version, #to_s] version
161
+ #
162
+ # @return [Boolean]
163
+ def has_artifact?(name, version)
164
+ !get_artifact(name, version).nil?
165
+ end
166
+
167
+ # @param [Object] other
168
+ #
169
+ # @return [Boolean]
170
+ def ==(other)
171
+ return false unless other.is_a?(self.class)
172
+
173
+ self_artifacts = self.artifacts
174
+ other_artifacts = other.artifacts
175
+
176
+ self_dependencies = self_artifacts.inject([]) do |list, artifact|
177
+ list << artifact.dependencies
178
+ end.flatten
179
+
180
+ other_dependencies = other_artifacts.inject([]) do |list, artifact|
181
+ list << artifact.dependencies
182
+ end.flatten
183
+
184
+ self_artifacts.size == other_artifacts.size &&
185
+ self_dependencies.size == other_dependencies.size &&
186
+ self_artifacts.all? { |artifact| other_artifacts.include?(artifact) } &&
187
+ self_dependencies.all? { |dependency| other_dependencies.include?(dependency) }
188
+ end
189
+ alias_method :eql?, :==
190
+
191
+ private
192
+
193
+ # @return [Array<Doubleshot::Resolver::GemResolver::Artifact>]
194
+ def artifact_collection
195
+ @artifacts.collect { |name, artifact| artifact }
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end