teapot 1.2.6 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f65f0293a8919b935c0db96920432e0df489e5e
4
- data.tar.gz: fd153aff98dc3f33c9cab3cb486b2d3b3304bcf6
3
+ metadata.gz: eddf99e30dfd202f8c03b4b075c276eb4eccf6a6
4
+ data.tar.gz: b739803f53360546415b4f6aa91f51677b2b8dd5
5
5
  SHA512:
6
- metadata.gz: abbf8e06783cd1060bf30926cbf96f04854b5992cb7e7da252b97be4e9d89d82b1d89fcf1e4430496755a2ee990926b310d7d5e4a56d42f7b5a2035f96d541e4
7
- data.tar.gz: b2ba99f9e2d1a42f479d1a91d6ec33437373b43d2902a82fc95da186cf282ce8d5576a992e6345ca98f7308854187e643237a59bdea9c2491c3f3d3683d07437
6
+ metadata.gz: a76805afdfba7756138fd61d50d9d8cbc63e05bd5e66857d23d94e45bef06206cd0a187f016cd0c4975f45eaf6c22e9a7226fc6f869e90b268a243d70bbcdaaa
7
+ data.tar.gz: 3df933c8591927c119010d54377a1679a59b40281d5793c9a3e68acafbf8a3c2a3660da7e91172940d1f014b9df8d91a56714e213d1d943247b106b05ede56e8
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --color
2
2
  --format documentation
3
+ --warnings
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ gemspec
6
6
  group :development do
7
7
  gem 'pry'
8
8
  gem 'pry-coolline'
9
+ gem 'pry-byebug'
9
10
  end
10
11
 
11
12
  group :test do
@@ -0,0 +1,20 @@
1
+ # Planning
2
+
3
+ Teapot 2.0 will feature isolated build directories and private dependencies.
4
+
5
+ ## Isolated Build Directories
6
+
7
+ Individual packages will be built into discrete directories:
8
+
9
+ ```
10
+ teapot/#{platform}/libpng/include/png.h
11
+ teapot/#{platform}/libpng/lib/libpng.a
12
+ ```
13
+
14
+ ## Private Dependencies
15
+
16
+ All dependencies by default are public.
17
+
18
+ Given a package, C, that depends on B, and B publicly depends on A, C also depends on A.
19
+
20
+ The problem is that some dependencies of B should not also be dependencies of A, for example internal build tools, etc. It's not necessary for a consumer of A to be aware of C in all cases.
data/README.md CHANGED
@@ -188,7 +188,7 @@ You need to make sure any basic tools, e.g. compilers, system libraries, are ins
188
188
 
189
189
  - Should packages be built into a shared prefix or should they be built into unique prefixes and joined together either via install or `-L` and `-I`?
190
190
  - Relative include paths might fail to work correctly if headers are not installed into same directory.
191
- - Should packages expose the tools required to build themselves as dependencies? e.g. should `build-cmake` as required by, say, `OpenCV`, be exposed to all who depend on `OpenCV`? Should there be a mechanism for non-public dependencies, i.e. dependencies which are not exposed to dependants?
191
+ - Should packages expose the tools required to build themselves as dependencies? e.g. should `build-cmake` as required by, say, `OpenCV`, be exposed to all who depend on `OpenCV`? Should there be a mechanism for non-public dependencies, i.e. dependencies which are not exposed to dependants? *YES - Implemented*.
192
192
  - Should packages have some way to expose system requirements, e.g. installed compiler, libraries, etc. Perhaps some kind of `Package#valid?` which allows custom logic?
193
193
 
194
194
  ## Contributing
@@ -29,6 +29,9 @@ require_relative 'controller/visualize'
29
29
 
30
30
  require_relative 'repository'
31
31
 
32
+ # For IncompatibleTeapotError
33
+ require_relative 'loader'
34
+
32
35
  require 'samovar'
33
36
 
34
37
  module Teapot
@@ -126,6 +129,21 @@ module Teapot
126
129
  end
127
130
  end
128
131
 
132
+ class Visualize < Samovar::Command
133
+ self.description = "Generate a picture of the dependency graph."
134
+
135
+ options do
136
+ option '-o/--output-path <path>', "The output path for the visualization.", default: "dependency.svg"
137
+ option '-d/--dependency-name <name>', "Show the partial chain for the given named dependency."
138
+ end
139
+
140
+ many :targets, "Visualize these targets, or use them to help the dependency resolution process."
141
+
142
+ def invoke(parent)
143
+ parent.controller.visualize(@targets, **@options)
144
+ end
145
+ end
146
+
129
147
  class Clean < Samovar::Command
130
148
  self.description = "Delete everything in the teapot directory."
131
149
 
@@ -151,6 +169,7 @@ module Teapot
151
169
  'fetch' => Fetch,
152
170
  'list' => List,
153
171
  'build' => Build,
172
+ 'visualize' => Visualize,
154
173
  'clean' => Clean
155
174
 
156
175
  def root
@@ -24,7 +24,6 @@ require 'set'
24
24
  require 'yaml/store'
25
25
 
26
26
  require_relative 'identity_set'
27
- require_relative 'context'
28
27
  require_relative 'definition'
29
28
 
30
29
  module Teapot
@@ -104,7 +104,7 @@ module Teapot
104
104
 
105
105
  select(dependency_names)
106
106
 
107
- Dependency::chain(@selection, @dependencies, @targets.values)
107
+ Dependency::Chain.expand(@dependencies, @targets.values, @selection)
108
108
  end
109
109
 
110
110
  def direct_targets(ordered)
@@ -18,6 +18,7 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require_relative 'context'
21
22
  require_relative 'configuration'
22
23
  require_relative 'version'
23
24
 
@@ -71,7 +71,7 @@ module Teapot
71
71
  ordered.each do |resolution|
72
72
  target = resolution.provider
73
73
 
74
- environment = target.environment(context.configuration)
74
+ environment = target.environment(context.configuration, chain)
75
75
 
76
76
  if target.build
77
77
  controller.add_target(target, environment.flatten)
@@ -52,28 +52,18 @@ module Teapot
52
52
  log "\t\t- Author: #{author.name}" + contact_text
53
53
  end
54
54
  when Target
55
- definition.dependencies.each do |name|
56
- log "\t\t- depends on #{name.inspect}".color(:red)
55
+ definition.dependencies.each do |dependency|
56
+ log "\t\t- #{dependency}".color(:red)
57
57
  end
58
58
 
59
- definition.provisions.each do |(name, provision)|
60
- if Dependency::Alias === provision
61
- log "\t\t- provides #{name.inspect} => #{provision.dependencies.inspect}".color(:green)
62
- else
63
- log "\t\t- provides #{name.inspect}".color(:green)
64
- end
59
+ definition.provisions.each do |name, provision|
60
+ log "\t\t- #{provision}".color(:green)
65
61
  end
66
62
  when Configuration
67
63
  definition.materialize
68
64
 
69
65
  definition.packages.each do |package|
70
- if package.local?
71
- log "\t\t- links #{package.name} from #{package.options[:local]}".color(:green)
72
- elsif package.external?
73
- log "\t\t- clones #{package.name} from #{package.external_url(context.root)}".color(:green)
74
- else
75
- log "\t\t- references #{package.name} from #{package.path}".color(:green)
76
- end
66
+ log "\t\t- #{package}".color(:green)
77
67
  end
78
68
 
79
69
  definition.imports.select(&:explicit).each do |import|
@@ -21,88 +21,30 @@
21
21
  require_relative '../controller'
22
22
 
23
23
  require 'graphviz'
24
- require 'yaml'
25
24
 
26
25
  module Teapot
27
26
  class Controller
28
- def visualize(dependency_names = [])
27
+ def visualize(dependency_names = [], output_path: nil, dependency_name: nil)
29
28
  configuration = context.configuration
30
29
 
31
30
  chain = context.dependency_chain(dependency_names, context.configuration)
32
31
 
33
- g = Graphviz::Graph.new
34
- g.attributes[:ratio] = :auto
35
-
36
- base_attributes = {
37
- :shape => 'box',
38
- }
39
-
40
- provision_attributes = base_attributes.dup
41
-
42
- alias_attributes = {
43
- :shape => 'box',
44
- :color => 'grey',
45
- }
46
-
47
- chain.ordered.each do |resolution|
48
- provider = resolution.provider
49
- name = resolution.name
50
-
51
- # Provider is the target that provides the dependency referred to by name.
52
- node = g.add_node(name.to_s, base_attributes.dup)
53
-
54
- if chain.dependencies.include?(name)
55
- node.attributes[:color] = 'blue'
56
- node.attributes[:penwidth] = 2.0
57
- elsif chain.selection.include?(provider.name)
58
- node.attributes[:color] = 'brown'
59
- end
32
+ if dependency_name
33
+ provider = context.dependencies[dependency_name]
60
34
 
61
- # A provision has dependencies...
62
- provider.dependencies.each do |dependency|
63
- dependency_node = g.nodes[dependency.to_s]
64
-
65
- node.connect(dependency_node) if dependency_node
66
- end
67
-
68
- # A provision provides other provisions...
69
- provider.provisions.each do |(provision_name, provision)|
70
- next if name == provision_name
71
-
72
- provides_node = g.nodes[provision_name.to_s] || g.add_node(provision_name.to_s, provision_attributes)
73
-
74
- if Dependency::Alias === provision
75
- provides_node.attributes = alias_attributes
76
- end
77
-
78
- unless provides_node.connected?(node)
79
- edge = provides_node.connect(node)
80
- end
81
- end
35
+ # TODO The visualisation generated isn't quite right. It's introspecting too much from the packages and not reflecting #ordered and #provisions.
36
+ chain = chain.partial(provider)
82
37
  end
83
38
 
84
- # Put all dependencies at the same level so as to not make the graph too confusing.
85
- done = Set.new
86
- chain.ordered.each do |resolution|
87
- provider = resolution.provider
88
- name = resolution.name
89
-
90
- p = g.graphs[provider.name] || g.add_subgraph(provider.name, :rank => :same)
91
-
92
- provider.dependencies.each do |dependency|
93
- next if done.include? dependency
94
-
95
- done << dependency
96
-
97
- dependency_node = g.nodes[dependency.to_s]
98
-
99
- p.add_node(dependency_node.name)
100
- end
101
- end
39
+ visualization = Build::Dependency::Visualization.new
40
+
41
+ graph = visualization.generate(chain)
102
42
 
103
- Graphviz::output(g, :path => "graph.pdf")
43
+ if output
44
+ Graphviz::output(graph, :path => output)
45
+ end
104
46
 
105
- puts g.to_dot
47
+ return graph
106
48
  end
107
49
  end
108
50
  end
@@ -50,7 +50,7 @@ module Teapot
50
50
  attr :name
51
51
 
52
52
  # A textual description of the definition, possibly in markdown format:
53
- attr :description, true
53
+ attr :description
54
54
 
55
55
  def description=(text)
56
56
  if text =~ /^(\t+)/
@@ -1,4 +1,4 @@
1
- # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
1
+ # Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
2
  #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  # of this software and associated documentation files (the "Software"), to deal
@@ -18,224 +18,8 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require 'set'
21
+ require 'build/dependency'
22
22
 
23
23
  module Teapot
24
- module Dependency
25
- class UnresolvedDependencyError < StandardError
26
- def initialize(chain)
27
- super "Unresolved dependency chain!"
28
-
29
- @chain = chain
30
- end
31
-
32
- attr :chain
33
- end
34
-
35
- Provision = Struct.new(:value)
36
- Alias = Struct.new(:dependencies)
37
- Resolution = Struct.new(:provider, :name)
38
-
39
- def priority= value
40
- @priority = value
41
- end
42
-
43
- def priority
44
- @priority || 0
45
- end
46
-
47
- def provides?(name)
48
- provisions.key? name
49
- end
50
-
51
- def provides(name_or_aliases, &block)
52
- if String === name_or_aliases || Symbol === name_or_aliases
53
- name = name_or_aliases
54
-
55
- provisions[name] = Provision.new(block)
56
- else
57
- aliases = name_or_aliases
58
-
59
- aliases.each do |name, dependencies|
60
- provisions[name] = Alias.new(Array(dependencies))
61
- end
62
- end
63
- end
64
-
65
- def provisions
66
- @provisions ||= {}
67
- end
68
-
69
- def depends(name)
70
- dependencies << name
71
- end
72
-
73
- def depends?(name)
74
- dependencies.include? name
75
- end
76
-
77
- def dependencies
78
- @dependencies ||= Set.new
79
- end
80
-
81
- class Chain
82
- def initialize(selection, dependencies, providers, options = {})
83
- # Explicitly selected targets which will be used when resolving ambiguity:
84
- @selection = Set.new(selection)
85
-
86
- # The list of dependencies that needs to be satisfied:
87
- @dependencies = dependencies
88
-
89
- # The available providers which match up to required dependencies:
90
- @providers = providers
91
-
92
- @resolved = Set.new
93
- @ordered = []
94
- @provisions = []
95
- @unresolved = []
96
- @conflicts = {}
97
-
98
- @options = options
99
-
100
- @dependencies.each do |dependency|
101
- expand(dependency, "<top>")
102
- end
103
- end
104
-
105
- attr :selection
106
- attr :dependencies
107
- attr :providers
108
-
109
- attr :resolved
110
- attr :ordered
111
- attr :provisions
112
- attr :unresolved
113
- attr :conflicts
114
-
115
- private
116
-
117
- def ignore_priority?
118
- @options[:ignore_priority]
119
- end
120
-
121
- def filter_by_priority(viable_providers)
122
- # Sort from highest priority to lowest priority:
123
- viable_providers = viable_providers.sort{|a,b| b.priority <=> a.priority}
124
-
125
- # The first item has the highest priority:
126
- highest_priority = viable_providers.first.priority
127
-
128
- # We compute all providers with the same highest priority (may be zero):
129
- return viable_providers.take_while{|provider| provider.priority == highest_priority}
130
- end
131
-
132
- def filter_by_selection(viable_providers)
133
- return viable_providers.select{|provider| @selection.include? provider.name}
134
- end
135
-
136
- def find_provider(dependency, parent)
137
- # Mostly, only one package will satisfy the dependency...
138
- viable_providers = @providers.select{|provider| provider.provides? dependency}
139
-
140
- # puts "** Found #{viable_providers.collect(&:name).join(', ')} viable providers.".color(:magenta)
141
-
142
- if viable_providers.size > 1
143
- # ... however in some cases (typically where aliases are being used) an explicit selection must be made for the build to work correctly.
144
- explicit_providers = filter_by_selection(viable_providers)
145
-
146
- # puts "** Filtering to #{explicit_providers.collect(&:name).join(', ')} explicit providers.".color(:magenta)
147
-
148
- if explicit_providers.size != 1 and !ignore_priority?
149
- # If we were unable to select a single package, we may use the priority to limit the number of possible options:
150
- explicit_providers = viable_providers if explicit_providers.empty?
151
-
152
- explicit_providers = filter_by_priority(explicit_providers)
153
- end
154
-
155
- if explicit_providers.size == 0
156
- # No provider was explicitly specified, thus we require explicit conflict resolution:
157
- @conflicts[dependency] = viable_providers
158
- return nil
159
- elsif explicit_providers.size == 1
160
- # The best outcome, a specific provider was named:
161
- return explicit_providers.first
162
- else
163
- # Multiple providers were explicitly mentioned that satisfy the dependency.
164
- @conflicts[dependency] = explicit_providers
165
- return nil
166
- end
167
- else
168
- return viable_providers.first
169
- end
170
- end
171
-
172
- def expand(dependency, parent)
173
- # puts "** Expanding #{dependency} from #{parent}".color(:magenta)
174
-
175
- if @resolved.include? dependency
176
- # puts "** Already resolved dependency!".color(:magenta)
177
-
178
- return
179
- end
180
-
181
- provider = find_provider(dependency, parent)
182
-
183
- if provider == nil
184
- # puts "** Couldn't find provider -> unresolved".color(:magenta)
185
- @unresolved << [dependency, parent]
186
- return nil
187
- end
188
-
189
- provision = provider.provisions[dependency]
190
-
191
- # We will now satisfy this dependency by satisfying any dependent dependencies, but we no longer need to revisit this one.
192
- @resolved << dependency
193
-
194
- # If the provision was an Alias, make sure to resolve the alias first:
195
- if Alias === provision
196
- # puts "** Resolving alias #{provision}".color(:magenta)
197
-
198
- provision.dependencies.each do |dependency|
199
- expand(dependency, provider)
200
- end
201
- end
202
-
203
- unless @resolved.include?(provider)
204
- # We are now satisfying the provider by expanding all its own dependencies:
205
- @resolved << provider
206
-
207
- # Make sure we satisfy the provider's dependencies first:
208
- provider.dependencies.each do |dependency|
209
- expand(dependency, provider)
210
- end
211
-
212
- # puts "** Appending #{dependency} -> ordered".color(:magenta)
213
-
214
- # Add the provider to the ordered list.
215
- @ordered << Resolution.new(provider, dependency)
216
- end
217
-
218
- # This goes here because we want to ensure 1/ that if
219
- unless provision == nil or Alias === provision
220
- # puts "** Appending #{dependency} -> provisions".color(:magenta)
221
-
222
- # Add the provision to the set of required provisions.
223
- @provisions << provision
224
- end
225
-
226
- # For both @ordered and @provisions, we ensure that for [...xs..., x, ...], x is satisfied by ...xs....
227
- end
228
- end
229
-
230
- # An `UnresolvedDependencyError` will be thrown if there are any unresolved dependencies.
231
- def self.chain(selection, dependencies, providers)
232
- chain = Chain.new(selection, dependencies, providers)
233
-
234
- if chain.unresolved.size > 0
235
- raise UnresolvedDependencyError.new(chain)
236
- end
237
-
238
- return chain
239
- end
240
- end
24
+ Dependency = ::Build::Dependency
241
25
  end
@@ -27,14 +27,12 @@ require 'build/rule'
27
27
  require 'build/name'
28
28
  require 'build/files'
29
29
 
30
- # Required for CPU count, etc.
31
- require 'system'
32
-
33
30
  module Teapot
34
- # Cannot load packages newer than this:
35
- LOADER_VERSION = "1.1"
31
+ # Cannot load packages newer than this.
32
+ # Version 1.3: Added support for build-dependency library which allows options for `#depends`. The primary use case is private dependencies.
33
+ LOADER_VERSION = "1.3"
36
34
 
37
- # Cannot load packages older than this:
35
+ # Cannot load packages older than this.
38
36
  MINIMUM_LOADER_VERSION = "1.0"
39
37
 
40
38
  class IncompatibleTeapotError < StandardError
@@ -53,6 +51,18 @@ module Teapot
53
51
  attr :path
54
52
  end
55
53
 
54
+ # This is a quick hack so that we can avoid using the system gem.. it's used in build-make package.
55
+ # TODO Remove this and also the dependency on facets, or fix facets.
56
+ module System
57
+ module CPU
58
+ def self.count
59
+ require 'etc'
60
+
61
+ Etc.nprocessors rescue 4
62
+ end
63
+ end
64
+ end
65
+
56
66
  class Loader
57
67
  Files = Build::Files
58
68
  Rule = Build::Rule
@@ -19,8 +19,8 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'build/files'
22
+ require 'build/uri'
22
23
 
23
- require_relative 'context'
24
24
  require_relative 'definition'
25
25
 
26
26
  module Teapot
@@ -63,32 +63,37 @@ module Teapot
63
63
  attr :path
64
64
 
65
65
  attr :uri
66
- attr :options, true
66
+ attr_accessor :options
67
+
68
+ def local
69
+ @options[:local].to_s
70
+ end
67
71
 
68
72
  def local?
69
- @options.key? :local
73
+ @options.include?(:local)
70
74
  end
71
75
 
72
76
  def external?
73
- @options.key? :source
77
+ @options.include?(:source)
74
78
  end
75
79
 
76
- def source
77
- @options[:source].to_s + '/'
80
+ # The source uri from which this package would be cloned. Might be relative, in which case it's relative to the root of the context.
81
+ def source_uri
82
+ Build::URI[@options[:source]]
78
83
  end
79
84
 
80
- def external_url(relative_root)
81
- base_uri = URI(source)
82
-
83
- if base_uri.scheme == nil || base_uri.scheme == 'file'
84
- base_uri = URI "file://" + File.expand_path(base_uri.path, relative_root) + "/"
85
- end
86
-
87
- return relative_url(base_uri)
85
+ def external_url(root_path = nil)
86
+ Build::URI[root_path] + source_uri + Build::URI[@uri]
88
87
  end
89
88
 
90
89
  def to_s
91
- "#<#{self.class} #{@name.dump} path=#{path}>"
90
+ if self.local?
91
+ "links #{@name} from #{self.local}"
92
+ elsif self.external?
93
+ "clones #{@name} from #{self.external_url}"
94
+ else
95
+ "references #{@name} from #{@path}"
96
+ end
92
97
  end
93
98
 
94
99
  # Package may be used as hash key / in a set:
@@ -100,22 +105,5 @@ module Teapot
100
105
  def eql?(other)
101
106
  @path.eql?(other.path)
102
107
  end
103
-
104
- private
105
-
106
- def relative_url(base_uri)
107
- source_uri = URI(@uri)
108
-
109
- unless source_uri.absolute?
110
- source_uri = base_uri + source_uri
111
- end
112
-
113
- # Git can't handle the default formatting that Ruby uses for file URIs.
114
- if source_uri.scheme == "file"
115
- source_uri = "file://" + source_uri.path
116
- end
117
-
118
- return source_uri
119
- end
120
108
  end
121
109
  end
@@ -42,10 +42,10 @@ module Teapot
42
42
  super
43
43
  end
44
44
 
45
- attr :summary, true
46
- attr :license, true
47
- attr :website, true
48
- attr :version, true
45
+ attr_accessor :summary
46
+ attr_accessor :license
47
+ attr_accessor :website
48
+ attr_accessor :version
49
49
 
50
50
  attr :authors
51
51
 
@@ -28,7 +28,7 @@ module Teapot
28
28
  def self.run(*args, &block)
29
29
  options = Hash === args.last ? args.pop : {}
30
30
 
31
- args = args.flatten.collect &:to_s
31
+ args = args.flatten.collect(&:to_s)
32
32
 
33
33
  puts args.join(' ').color(:blue) + " in #{options[:chdir] || Dir.getwd}"
34
34
 
@@ -25,6 +25,8 @@ require_relative 'definition'
25
25
  require 'build/environment'
26
26
  require 'build/rulebook'
27
27
 
28
+ require 'pry'
29
+
28
30
  module Teapot
29
31
  class BuildError < StandardError
30
32
  end
@@ -49,22 +51,12 @@ module Teapot
49
51
  super
50
52
  end
51
53
 
52
- # Given a configuration, compute the dependency chain for this target.
53
- def provision_chain(configuration)
54
- # Reduce the number of keystrokes for good health:
55
- context = configuration.context
56
-
57
- chain = Dependency::chain(context.selection, self.dependencies, context.targets.values)
58
- end
59
-
60
54
  # Given a specific configuration, generate the build environment based on this target and it's provision chain.
61
- def environment(configuration)
62
- chain = provision_chain(configuration)
63
-
64
- environments = []
55
+ def environment(configuration, chain)
56
+ chain = chain.partial(self)
65
57
 
66
58
  # Calculate the dependency chain's ordered environments:
67
- environments += chain.provisions.collect do |provision|
59
+ environments = chain.provisions.collect do |provision|
68
60
  Build::Environment.new(&provision.value)
69
61
  end
70
62
 
@@ -79,9 +71,6 @@ module Teapot
79
71
  end
80
72
  end
81
73
 
82
- # Legacy method name.
83
- alias environment_for_configuration environment
84
-
85
74
  def build(&block)
86
75
  if block_given?
87
76
  @build = block
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Teapot
22
- VERSION = "1.2.6"
22
+ VERSION = "1.3.0"
23
23
  end
@@ -40,7 +40,7 @@ module Teapot::TargetSpec
40
40
  expect(chain.ordered[2].name).to be == 'Test/TargetSpec'
41
41
  expect(chain.ordered[2].provider).to be == target
42
42
 
43
- environment = target.environment(context.configuration)
43
+ environment = target.environment(context.configuration, chain)
44
44
  # Environment#to_hash flattens the environment and evaluates all values:
45
45
  hash = environment.to_hash
46
46
 
@@ -39,7 +39,7 @@ module Teapot::WaitSpec
39
39
  ordered.each do |resolution|
40
40
  target = resolution.provider
41
41
 
42
- environment = target.environment(context.configuration)
42
+ environment = target.environment(context.configuration, chain)
43
43
 
44
44
  if target.build
45
45
  controller.add_target(target, environment.flatten)
@@ -48,8 +48,6 @@ module Teapot::WaitSpec
48
48
  end
49
49
 
50
50
  controller.update
51
-
52
- puts $log
53
51
  end
54
52
  end
55
53
  end
@@ -24,15 +24,16 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.has_rdoc = 'yard'
26
26
 
27
- spec.required_ruby_version = '>= 2.1'
27
+ spec.required_ruby_version = '>= 2.1.0'
28
28
 
29
29
  spec.add_dependency "rainbow", "~> 2.0"
30
- spec.add_dependency "system", "~> 0.1.3"
31
30
 
32
- spec.add_dependency "graphviz", "~> 0.3"
31
+ spec.add_dependency "graphviz", "~> 0.4"
33
32
 
34
- spec.add_dependency "build", "~> 1.0.9"
35
- spec.add_dependency "build-files", "~> 1.0.5"
33
+ spec.add_dependency "build", "~> 1.0"
34
+ spec.add_dependency "build-files", "~> 1.0"
35
+ spec.add_dependency "build-dependency", "~> 1.1"
36
+ spec.add_dependency "build-uri", "~> 1.0"
36
37
 
37
38
  spec.add_dependency "facets", "~> 3.1"
38
39
  spec.add_dependency "samovar", "~> 1.2"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teapot
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.6
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-16 00:00:00.000000000 Z
11
+ date: 2017-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
@@ -25,61 +25,75 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: system
28
+ name: graphviz
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.3
33
+ version: '0.4'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.1.3
40
+ version: '0.4'
41
41
  - !ruby/object:Gem::Dependency
42
- name: graphviz
42
+ name: build
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0.3'
47
+ version: '1.0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0.3'
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: build
56
+ name: build-files
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.0.9
61
+ version: '1.0'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.0.9
68
+ version: '1.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: build-files
70
+ name: build-dependency
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: build-uri
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: 1.0.5
89
+ version: '1.0'
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: 1.0.5
96
+ version: '1.0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: facets
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -167,6 +181,7 @@ files:
167
181
  - ".travis.yml"
168
182
  - Gemfile
169
183
  - Gemfile.local
184
+ - PLANNING.md
170
185
  - README.md
171
186
  - Rakefile
172
187
  - bin/teapot
@@ -202,7 +217,6 @@ files:
202
217
  - spec/teapot/command_spec.rb
203
218
  - spec/teapot/context_spec.rb
204
219
  - spec/teapot/context_spec/teapot.rb
205
- - spec/teapot/dependency_spec.rb
206
220
  - spec/teapot/generator_spec.rb
207
221
  - spec/teapot/generator_spec/teapot.rb
208
222
  - spec/teapot/generator_spec/template/$NAME.txt
@@ -227,7 +241,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
227
241
  requirements:
228
242
  - - ">="
229
243
  - !ruby/object:Gem::Version
230
- version: '2.1'
244
+ version: 2.1.0
231
245
  required_rubygems_version: !ruby/object:Gem::Requirement
232
246
  requirements:
233
247
  - - ">="
@@ -235,7 +249,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
249
  version: '0'
236
250
  requirements: []
237
251
  rubyforge_project:
238
- rubygems_version: 2.5.1
252
+ rubygems_version: 2.6.10
239
253
  signing_key:
240
254
  specification_version: 4
241
255
  summary: Teapot is a tool for managing complex cross-platform builds.
@@ -243,7 +257,6 @@ test_files:
243
257
  - spec/teapot/command_spec.rb
244
258
  - spec/teapot/context_spec.rb
245
259
  - spec/teapot/context_spec/teapot.rb
246
- - spec/teapot/dependency_spec.rb
247
260
  - spec/teapot/generator_spec.rb
248
261
  - spec/teapot/generator_spec/teapot.rb
249
262
  - spec/teapot/generator_spec/template/$NAME.txt
@@ -1,166 +0,0 @@
1
- # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'teapot/dependency'
22
-
23
- module Teapot::DependencySpec
24
- class BasicDependency
25
- include Teapot::Dependency
26
-
27
- def initialize(name = nil)
28
- @name = name
29
- end
30
-
31
- attr :name
32
-
33
- def inspect
34
- "<BasicDependency:#{@name}>"
35
- end
36
- end
37
-
38
- describe Teapot::Dependency do
39
- it "Should resolve dependency chain" do
40
- a = BasicDependency.new
41
-
42
- a.provides 'apple' do
43
- fruit ['apple']
44
- end
45
-
46
- b = BasicDependency.new
47
-
48
- b.provides 'orange' do
49
- fruit ['orange']
50
- end
51
-
52
- c = BasicDependency.new
53
-
54
- c.provides 'fruit-juice' do
55
- juice ['ice', 'cold']
56
- end
57
-
58
- c.depends 'apple'
59
- c.depends 'orange'
60
-
61
- chain = Teapot::Dependency::chain([], ['fruit-juice'], [a, b, c])
62
- expect(chain.ordered.collect(&:first)).to be == [a, b, c]
63
-
64
- d = BasicDependency.new
65
-
66
- d.provides 'pie' do
67
- end
68
-
69
- d.depends 'apple'
70
-
71
- chain = Teapot::Dependency::chain([], ['pie'], [a, b, c, d])
72
-
73
- expect(chain.unresolved).to be == []
74
- expect(chain.ordered.collect(&:first)).to be == [a, d]
75
- end
76
-
77
- it "should report conflicts" do
78
- apple = BasicDependency.new('apple')
79
- apple.provides 'apple'
80
- apple.provides 'fruit'
81
-
82
- bananna = BasicDependency.new('bananna')
83
- bananna.provides 'fruit'
84
-
85
- salad = BasicDependency.new('salad')
86
- salad.depends 'fruit'
87
- salad.provides 'salad'
88
-
89
- chain = Teapot::Dependency::Chain.new([], ['salad'], [apple, bananna, salad])
90
- expect(chain.unresolved.first).to be == ["fruit", salad]
91
- expect(chain.conflicts).to be == {"fruit" => [apple, bananna]}
92
-
93
- chain = Teapot::Dependency::Chain.new(['apple'], ['salad'], [apple, bananna, salad])
94
- expect(chain.unresolved).to be == []
95
- expect(chain.conflicts).to be == {}
96
- end
97
-
98
- it "should resolve aliases" do
99
- apple = BasicDependency.new('apple')
100
- apple.provides 'apple'
101
- apple.provides :fruit => 'apple'
102
-
103
- bananna = BasicDependency.new('bananna')
104
- bananna.provides 'bananna'
105
- bananna.provides :fruit => 'bananna'
106
-
107
- salad = BasicDependency.new('salad')
108
- salad.depends :fruit
109
- salad.provides 'salad'
110
-
111
- chain = Teapot::Dependency::chain(['apple'], ['salad'], [apple, bananna, salad])
112
- expect(chain.unresolved).to be == []
113
- expect(chain.conflicts).to be == {}
114
-
115
- expect(chain.ordered.size).to be == 2
116
- expect(chain.ordered[0]).to be == Teapot::Dependency::Resolution.new(apple, "apple")
117
- expect(chain.ordered[1]).to be == Teapot::Dependency::Resolution.new(salad, "salad")
118
- end
119
-
120
- it "should select dependencies with high priority" do
121
- bad_apple = BasicDependency.new('bad_apple')
122
- bad_apple.provides 'apple'
123
- bad_apple.priority = 20
124
-
125
- good_apple = BasicDependency.new('good_apple')
126
- good_apple.provides 'apple'
127
- good_apple.priority = 40
128
-
129
- chain = Teapot::Dependency::chain([], ['apple'], [bad_apple, good_apple])
130
-
131
- expect(chain.unresolved).to be == []
132
- expect(chain.conflicts).to be == {}
133
-
134
- # Should select higher priority package by default:
135
- expect(chain.ordered).to be == [Teapot::Dependency::Resolution.new(good_apple, 'apple')]
136
- end
137
-
138
- it "should expose direct dependencies" do
139
- system = BasicDependency.new('linux')
140
- system.provides 'linux'
141
- system.provides 'clang'
142
- system.provides system: 'linux'
143
- system.provides compiler: 'clang'
144
-
145
- library = BasicDependency.new('library')
146
- library.provides 'library'
147
- library.depends :system
148
- library.depends :compiler
149
-
150
- application = BasicDependency.new('application')
151
- application.provides 'application'
152
- application.depends :compiler
153
- application.depends 'library'
154
-
155
- chain = Teapot::Dependency::chain([], ['application'], [system, library, application])
156
-
157
- expect(chain.unresolved).to be == []
158
- expect(chain.conflicts).to be == {}
159
- expect(chain.ordered).to be == [
160
- Teapot::Dependency::Resolution.new(system, 'clang'),
161
- Teapot::Dependency::Resolution.new(library, 'library'),
162
- Teapot::Dependency::Resolution.new(application, 'application'),
163
- ]
164
- end
165
- end
166
- end