teapot 1.2.6 → 1.3.0

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.
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