doubleshot 0.2.0-java → 0.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
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