teapot 1.0.0.pre.rc7 → 1.0.0.pre.rc9

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: 89ec99bb9d6d04670ccda7c53e838c9ac266372e
4
- data.tar.gz: b6ee7d9d431b290ec697a19a76674a5a9e82bd98
3
+ metadata.gz: c85e14574b10f98c7393860c30732ba0ce291322
4
+ data.tar.gz: 7800be07e0609957751fcdd79bdd3f454b2e9042
5
5
  SHA512:
6
- metadata.gz: fce6cf29a849f8fc5047dc580b69a46b8153c611a0a89f1374e01407175f30f521e47d4aceb0060a78296586df60ee687f7118869207277b56234a4b64bc20d5
7
- data.tar.gz: 5e499452699b8f1ed0f5b92409cbc78e862dbf108971dca638254a00fa4d9779a8f653ac17debc1f89512ea89d4091329fe9b9c22191e6e1e74146a50463ae3e
6
+ metadata.gz: dc81b95ae0929cc0a7f6c1b387e8b71276b1db78b3f9e8948b7ec72053be173f9279a56c2bb9a6ef6b1f9a6a7de3fa300edd44400e14e64146b828333bcac9a6
7
+ data.tar.gz: d097232b756dc542314069a3f464da5ed8ad7d456db959a6fe5c6c93b9bb8dc25056b0d0a8b3903ced6e33fcd308e480336735e5f6f898f25c13b0b8e738cad0
@@ -1,8 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "1.9"
4
3
  - "2.0"
5
4
  - "2.1"
6
- matrix:
7
- allow_failures:
8
- - rvm: "1.9"
data/README.md CHANGED
@@ -14,7 +14,7 @@ Teapot is a decentralised build tool for managing complex cross-platform project
14
14
 
15
15
  Ensure that you already have a working install of Ruby 1.9.3+
16
16
 
17
- $ gem install teapot
17
+ $ gem install teapot
18
18
 
19
19
  ## Usage
20
20
 
@@ -58,9 +58,10 @@ For Mac OS X (requires Xcode Command Line Tools):
58
58
 
59
59
  You need to make sure any basic tools, e.g. compilers, system libraries, are installed correctly before building. Consult the platform and library documentation for any dependencies.
60
60
 
61
- ## Dependency Graph
61
+ ## Open Issues
62
62
 
63
63
  - 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`?
64
+ - Relative include paths might fail to work correctly if headers are not installed into same directory.
64
65
  - 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?
65
66
 
66
67
  ## Contributing
@@ -1,15 +1,15 @@
1
1
  # Copyright, 2012, 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
5
5
  # in the Software without restriction, including without limitation the rights
6
6
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
7
  # copies of the Software, and to permit persons to whom the Software is
8
8
  # furnished to do so, subject to the following conditions:
9
- #
9
+ #
10
10
  # The above copyright notice and this permission notice shall be included in
11
11
  # all copies or substantial portions of the Software.
12
- #
12
+ #
13
13
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
14
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
15
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -26,6 +26,7 @@ require 'build/makefile'
26
26
 
27
27
  require 'teapot/name'
28
28
 
29
+ require 'graphviz'
29
30
  require 'process/group'
30
31
  require 'system'
31
32
 
@@ -67,6 +68,10 @@ module Teapot
67
68
  scope.instance_exec(@arguments, &@callback)
68
69
  end
69
70
  end
71
+
72
+ def inspect
73
+ @rule.name.inspect
74
+ end
70
75
  end
71
76
 
72
77
  class Top < Graph::Node
@@ -87,6 +92,10 @@ module Teapot
87
92
  def requires_update?
88
93
  true
89
94
  end
95
+
96
+ def inspect
97
+ @task_class.name.inspect
98
+ end
90
99
  end
91
100
 
92
101
  class Task < Graph::Task
@@ -139,7 +148,9 @@ module Teapot
139
148
 
140
149
  def visit
141
150
  super do
151
+ @controller.enter(self, @node)
142
152
  @node.apply!(self)
153
+ @controller.exit(self, @node)
143
154
  end
144
155
  end
145
156
  end
@@ -161,6 +172,8 @@ module Teapot
161
172
 
162
173
  attr :top
163
174
 
175
+ attr :visualisation
176
+
164
177
  # Because we do a depth first traversal, we can capture global state per branch, such as `@task_class`.
165
178
  def traverse!(walker)
166
179
  @top.each do |node|
@@ -186,15 +199,54 @@ module Teapot
186
199
  end
187
200
  end
188
201
 
202
+ def enter(task, node)
203
+ return unless @g
204
+
205
+ parent_node = @hierarchy.last
206
+
207
+ task_node = @g.nodes[node] || @g.add_node(node, shape: 'box')
208
+
209
+ if parent_node
210
+ parent_node.connect(task_node)
211
+ end
212
+
213
+ node.inputs.map{|path| path.shortest_path(Dir.pwd)}.each do |path|
214
+ input_node = @g.nodes[path.to_s] || @g.add_node(path.to_s, shape: 'box')
215
+ input_node.connect(task_node)
216
+ end
217
+
218
+ @hierarchy << task_node
219
+ end
220
+
221
+ def exit(task, node)
222
+ return unless @g
223
+
224
+ @hierarchy.pop
225
+
226
+ task_node = @g.nodes[node] || @g.add_node(node, shape: 'box')
227
+
228
+ node.outputs.map{|path| path.shortest_path(Dir.pwd)}.each do |path|
229
+ output_node = @g.nodes[path.to_s] || @g.add_node(path.to_s, shape: 'box')
230
+ output_node.connect(task_node)
231
+ end
232
+ end
233
+
189
234
  def update!
190
235
  group = Process::Group.new
191
236
 
237
+ @g = Graphviz::Graph.new('G', rankdir: "LR")
238
+ @hierarchy = []
239
+
192
240
  walker = super do |walker, node|
193
241
  @task_class.new(self, walker, node, group)
194
242
  end
195
243
 
196
244
  group.wait
197
245
 
246
+ if ENV['BUILD_GRAPH_PDF']
247
+ Graphviz::output(@g, path: ENV['BUILD_GRAPH_PDF']) rescue nil
248
+ end
249
+
198
250
  return walker
199
251
  end
200
252
  end
@@ -1,15 +1,15 @@
1
1
  # Copyright, 2012, 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
5
5
  # in the Software without restriction, including without limitation the rights
6
6
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
7
  # copies of the Software, and to permit persons to whom the Software is
8
8
  # furnished to do so, subject to the following conditions:
9
- #
9
+ #
10
10
  # The above copyright notice and this permission notice shall be included in
11
11
  # all copies or substantial portions of the Software.
12
- #
12
+ #
13
13
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
14
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
15
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -35,7 +35,7 @@ module Teapot
35
35
  def self.check(definition, definitions)
36
36
  previous = definitions[definition.name]
37
37
 
38
- raise new(definition, previous) if previous
38
+ raise self.new(definition, previous) if previous
39
39
  end
40
40
  end
41
41
 
@@ -21,6 +21,8 @@
21
21
  require 'teapot/controller'
22
22
  require 'teapot/build'
23
23
 
24
+ $TEAPOT_DEBUG_GRAPH = false
25
+
24
26
  module Teapot
25
27
  class Controller
26
28
  class BuildFailedError < StandardError
@@ -45,24 +47,33 @@ module Teapot
45
47
  end
46
48
  end
47
49
 
48
- controller.run do
49
- # The graph has been dirtied because files have changed, traverse and update it:
50
- walker = controller.update_with_log
51
-
52
- # Only run once is asked:
53
- unless @options[:continuous]
54
- if walker.failed?
55
- raise BuildFailedError.new("Failed to build all nodes successfully!")
50
+ walker = nil
51
+
52
+ # We need to catch interrupt here, and exit with the correct exit code:
53
+ begin
54
+ controller.run do
55
+ # The graph has been dirtied because files have changed, traverse and update it:
56
+ walker = controller.update_with_log
57
+
58
+ if $TEAPOT_DEBUG_GRAPH
59
+ controller.nodes.each do |key, node|
60
+ puts "#{node.status} #{node.inspect}" unless node.clean?
61
+ end
56
62
  end
57
63
 
58
- break
59
- end
60
-
61
- if $TEAPOT_DEBUG_GRAPH
62
- controller.nodes.each do |key, node|
63
- puts "#{node.status} #{node.inspect}"# unless node.clean?
64
+ # Only run once is asked:
65
+ unless @options[:continuous]
66
+ if walker.failed?
67
+ raise BuildFailedError.new("Failed to build all nodes successfully!")
68
+ end
69
+
70
+ break
64
71
  end
65
72
  end
73
+ rescue Interrupt
74
+ if walker && walker.failed?
75
+ raise BuildFailedError.new("Failed to build all nodes successfully!")
76
+ end
66
77
  end
67
78
 
68
79
  return chain, ordered
@@ -37,6 +37,14 @@ module Teapot
37
37
  Provision = Struct.new(:value)
38
38
  Alias = Struct.new(:dependencies)
39
39
 
40
+ def priority= value
41
+ @priority = value
42
+ end
43
+
44
+ def priority
45
+ @priority || 0
46
+ end
47
+
40
48
  def provides?(name)
41
49
  provisions.key? name
42
50
  end
@@ -72,7 +80,7 @@ module Teapot
72
80
  end
73
81
 
74
82
  class Chain
75
- def initialize(selection, dependencies, providers)
83
+ def initialize(selection, dependencies, providers, options = {})
76
84
  # Explicitly selected targets which will be used when resolving ambiguity:
77
85
  @selection = Set.new(selection)
78
86
 
@@ -88,6 +96,8 @@ module Teapot
88
96
  @unresolved = []
89
97
  @conflicts = {}
90
98
 
99
+ @options = options
100
+
91
101
  @dependencies.each do |dependency|
92
102
  expand(dependency, "<top>")
93
103
  end
@@ -105,6 +115,25 @@ module Teapot
105
115
 
106
116
  private
107
117
 
118
+ def ignore_priority?
119
+ @options[:ignore_priority]
120
+ end
121
+
122
+ def filter_by_priority(viable_providers)
123
+ # Sort from highest priority to lowest priority:
124
+ viable_providers = viable_providers.sort{|a,b| b.priority <=> a.priority}
125
+
126
+ # The first item has the highest priority:
127
+ highest_priority = viable_providers.first.priority
128
+
129
+ # We compute all providers with the same highest priority (may be zero):
130
+ return viable_providers.take_while{|provider| provider.priority == highest_priority}
131
+ end
132
+
133
+ def filter_by_selection(viable_providers)
134
+ return viable_providers.select{|provider| @selection.include? provider.name}
135
+ end
136
+
108
137
  def find_provider(dependency, parent)
109
138
  # Mostly, only one package will satisfy the dependency...
110
139
  viable_providers = @providers.select{|provider| provider.provides? dependency}
@@ -113,9 +142,17 @@ module Teapot
113
142
 
114
143
  if viable_providers.size > 1
115
144
  # ... however in some cases (typically where aliases are being used) an explicit selection must be made for the build to work correctly.
116
- explicit_providers = viable_providers.select{|provider| @selection.include? provider.name}
117
-
145
+ explicit_providers = filter_by_selection(viable_providers)
146
+
118
147
  # puts "** Filtering to #{explicit_providers.collect(&:name).join(', ')} explicit providers.".color(:magenta)
148
+
149
+ if explicit_providers.size != 1 and !ignore_priority?
150
+ # If we were unable to select a single package, we may use the priority to limit the number of possible options:
151
+ explicit_providers = viable_providers if explicit_providers.empty?
152
+
153
+ explicit_providers = filter_by_priority(explicit_providers)
154
+ end
155
+
119
156
 
120
157
  if explicit_providers.size == 0
121
158
  # No provider was explicitly specified, thus we require explicit conflict resolution:
@@ -1,15 +1,15 @@
1
1
  # Copyright, 2012, 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
5
5
  # in the Software without restriction, including without limitation the rights
6
6
  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
7
  # copies of the Software, and to permit persons to whom the Software is
8
8
  # furnished to do so, subject to the following conditions:
9
- #
9
+ #
10
10
  # The above copyright notice and this permission notice shall be included in
11
11
  # all copies or substantial portions of the Software.
12
- #
12
+ #
13
13
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
14
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
15
  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -18,8 +18,6 @@
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 'rexec/environment'
22
-
23
21
  require 'rainbow'
24
22
  require 'rainbow/ext/string'
25
23
 
@@ -44,26 +44,15 @@ module Teapot
44
44
  dynamic? and @options[:implicit]
45
45
  end
46
46
 
47
- def typed?
48
- @options[:typed]
47
+ # Optional parameters are those that are either defined as optional or implicit.
48
+ def optional?
49
+ @options[:optional] || implicit?
49
50
  end
50
51
 
51
52
  def applicable? arguments
52
- # The parameter is either optional, or is included in the argument list, otherwise we fail.
53
- unless @options[:optional] or arguments.include?(@name)
54
- return false
55
- end
56
-
57
- value = arguments[@name]
58
-
59
- # If the parameter is optional, and wasn't provided, we are okay.
60
- if @options[:optional]
61
- return true if value == nil
62
- end
63
-
64
- # If the parameter is typed, and we don't match the expected type, we fail.
65
- if type = @options[:typed]
66
- return false unless type === value
53
+ value = arguments.fetch(@name) do
54
+ # Value couldn't be found, if it wasn't optional, this parameter didn't apply:
55
+ return optional?
67
56
  end
68
57
 
69
58
  # If a pattern is provided, we must match it.
@@ -76,8 +65,10 @@ module Teapot
76
65
 
77
66
  def compute(arguments, scope)
78
67
  if implicit?
79
- scope.instance_exec(arguments, &@dynamic)
68
+ # Can be replaced if supplied:
69
+ arguments[@name] || scope.instance_exec(arguments, &@dynamic)
80
70
  elsif dynamic?
71
+ # Argument is optional:
81
72
  scope.instance_exec(arguments[@name], arguments, &@dynamic)
82
73
  else
83
74
  arguments[@name]
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Teapot
22
- VERSION = "1.0.0-rc7"
22
+ VERSION = "1.0.0-rc9"
23
23
  end
@@ -29,6 +29,10 @@ module Teapot::DependencySpec
29
29
  end
30
30
 
31
31
  attr :name
32
+
33
+ def inspect
34
+ "<BasicDependency:#{@name}>"
35
+ end
32
36
  end
33
37
 
34
38
  describe Teapot::Dependency do
@@ -109,5 +113,51 @@ module Teapot::DependencySpec
109
113
  expect(chain.conflicts).to be == {}
110
114
  expect(chain.ordered).to be == [[apple, "apple"], [salad, "salad"]]
111
115
  end
116
+
117
+ it "should select dependencies with high priority" do
118
+ bad_apple = BasicDependency.new('bad_apple')
119
+ bad_apple.provides 'apple'
120
+ bad_apple.priority = 20
121
+
122
+ good_apple = BasicDependency.new('good_apple')
123
+ good_apple.provides 'apple'
124
+ good_apple.priority = 40
125
+
126
+ chain = Teapot::Dependency::chain([], ['apple'], [bad_apple, good_apple])
127
+
128
+ expect(chain.unresolved).to be == []
129
+ expect(chain.conflicts).to be == {}
130
+
131
+ # Should select higher priority package by default:
132
+ expect(chain.ordered).to be == [[good_apple, 'apple']]
133
+ end
134
+
135
+ it "should expose direct dependencies" do
136
+ system = BasicDependency.new('linux')
137
+ system.provides 'linux'
138
+ system.provides 'clang'
139
+ system.provides system: 'linux'
140
+ system.provides compiler: 'clang'
141
+
142
+ library = BasicDependency.new('library')
143
+ library.provides 'library'
144
+ library.depends :system
145
+ library.depends :compiler
146
+
147
+ application = BasicDependency.new('application')
148
+ application.provides 'application'
149
+ application.depends :compiler
150
+ application.depends 'library'
151
+
152
+ chain = Teapot::Dependency::chain([], ['application'], [system, library, application])
153
+
154
+ expect(chain.unresolved).to be == []
155
+ expect(chain.conflicts).to be == {}
156
+ expect(chain.ordered).to be == [
157
+ [system, 'clang'],
158
+ [library, 'library'],
159
+ [application, 'application']
160
+ ]
161
+ end
112
162
  end
113
163
  end
@@ -24,6 +24,8 @@ Gem::Specification.new do |spec|
24
24
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
25
25
  spec.require_paths = ["lib"]
26
26
 
27
+ spec.has_rdoc = 'yard'
28
+
27
29
  spec.required_ruby_version = '>= 2.0'
28
30
 
29
31
  spec.add_dependency "rainbow", "~> 2.0.0"
@@ -31,9 +33,9 @@ Gem::Specification.new do |spec|
31
33
 
32
34
  spec.add_dependency "system", "~> 0.1.3"
33
35
 
34
- spec.add_dependency "graphviz", "~> 0.0.2"
36
+ spec.add_dependency "graphviz", "~> 0.1.0"
35
37
 
36
- spec.add_dependency "build-files", "~> 0.2.8"
38
+ spec.add_dependency "build-files", "~> 0.2.9"
37
39
  spec.add_dependency "build-graph", "~> 0.3.5"
38
40
  spec.add_dependency "build-makefile", "~> 0.2.0"
39
41
 
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.0.0.pre.rc7
4
+ version: 1.0.0.pre.rc9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-19 00:00:00.000000000 Z
11
+ date: 2014-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rainbow
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.0.2
61
+ version: 0.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: 0.0.2
68
+ version: 0.1.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: build-files
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 0.2.8
75
+ version: 0.2.9
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 0.2.8
82
+ version: 0.2.9
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: build-graph
85
85
  requirement: !ruby/object:Gem::Requirement