teapot 0.0.1 → 0.0.3

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.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - rbx-19mode
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in teapot.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem "rake"
8
+ end
data/README.md CHANGED
@@ -4,6 +4,8 @@ Teapot is a tool for managing complex cross-platform builds. It provides
4
4
  advanced dependency management via the Teapot file and is supported by
5
5
  the infusions ecosystem of packages and platform tooling.
6
6
 
7
+ [![Build Status](https://secure.travis-ci.org/ioquatix/teapot.png)](http://travis-ci.org/ioquatix/teapot)
8
+
7
9
  ## Installation
8
10
 
9
11
  Add this line to your application's Gemfile:
@@ -20,7 +22,50 @@ Or install it yourself as:
20
22
 
21
23
  ## Usage
22
24
 
23
- TODO: Write usage instructions here
25
+ Create a Teapot file in the root directory of your project:
26
+
27
+ source "https://github.com/infusions"
28
+
29
+ host /linux/ do
30
+ platform "linux"
31
+ end
32
+
33
+ host /darwin/ do
34
+ platform "darwin-osx"
35
+ end
36
+
37
+ package "png"
38
+ package "freetype"
39
+ package "vorbis"
40
+ package "ogg"
41
+ package "jpeg"
42
+
43
+ Then run
44
+
45
+ $ teapot install
46
+
47
+ This will download and compile all the selected packages into the `build` directory.
48
+
49
+ ### CMake ###
50
+
51
+ To use these packages in a CMake project, update your `CMakeLists.txt`:
52
+
53
+ list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/build/${TEAPOT_PLATFORM}/")
54
+
55
+ Then configure like so:
56
+
57
+ cmake path/to/src -DTEAPOT_PLATFORM=linux
58
+
59
+ ### Xcode ###
60
+
61
+ To use these packages in an Xcode project, creating a custom `teapot.xcconfig` is recommended:
62
+
63
+ TEAPOT_PLATFORM=darwin-osx
64
+ TEAPOT_PREFIX_PATH=$(SRCROOT)/build/$(TEAPOT_PLATFORM)
65
+
66
+ // Search paths:
67
+ HEADER_SEARCH_PATHS=$(inherited) "$(TEAPOT_PREFIX_PATH)/include"
68
+ LIBRARY_SEARCH_PATHS=$(inherited) "$(TEAPOT_PREFIX_PATH)/lib"
24
69
 
25
70
  ## Contributing
26
71
 
data/Rakefile CHANGED
@@ -1 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
data/bin/teapot CHANGED
@@ -30,7 +30,7 @@ $app = Rake.application = Rake::Application.new
30
30
  $app.init('teapot')
31
31
 
32
32
  task :fetch do
33
- config = Teapot::Config.load
33
+ config = Teapot::Config.load_default
34
34
  context = Teapot::Context.new(config)
35
35
 
36
36
  base_uri = URI(config.options[:source].to_s + '/')
@@ -38,10 +38,10 @@ task :fetch do
38
38
  config.records.each do |record|
39
39
  destination_path = record.destination_path
40
40
 
41
- $stderr.puts "Fetching #{record}...".color(:blue)
41
+ puts "Fetching #{record}...".color(:blue)
42
42
 
43
43
  unless File.exist? destination_path
44
- $stderr.puts "Cloning package at path #{destination_path} ...".color(:green)
44
+ puts "Cloning package at path #{destination_path} ...".color(:green)
45
45
 
46
46
  source_uri = URI(record.uri)
47
47
 
@@ -53,59 +53,127 @@ task :fetch do
53
53
  source_uri = source_uri.path
54
54
  end
55
55
 
56
- sh("git", "clone", source_uri.to_s, destination_path.to_s)
56
+ Teapot::Commands.run("git", "clone", "--recursive", source_uri.to_s, destination_path.to_s)
57
57
  else
58
- $stderr.puts "Updating package at path #{destination_path} ...".color(:green)
58
+ puts "Updating package at path #{destination_path} ...".color(:green)
59
59
 
60
60
  Dir.chdir(destination_path) do
61
- sh("git", "pull")
61
+ Teapot::Commands.run("git", "pull")
62
+ Teapot::Commands.run("git", "submodule", "update", "--init")
62
63
  end
63
64
  end
64
65
  end
65
66
  end
66
67
 
67
- task :install => :fetch do
68
- config = Teapot::Config.load
68
+ task :build do
69
+ config = Teapot::Config.load_default
69
70
  context = Teapot::Context.new(config)
70
71
 
71
72
  config.records.each do |record|
72
- $stderr.puts "Installing #{record.name}...".color(:blue)
73
-
74
- record.load(context).each do |bundle|
75
- if bundle.respond_to? :fetch_location
76
- location = bundle.fetch_location
77
-
78
- if !location
79
- puts "Could not determine fetch location for #{name}!".color(:red)
80
- elsif File.exist? bundle.source_path
81
- puts "Source path #{bundle.source_path} already exists!".color(:red)
82
- else
83
- url = location[:url]
84
- local_path = bundle.path + (location[:filename] || File.basename(url))
73
+ destination_path = record.destination_path
74
+
75
+ bundles = record.load(context)
76
+
77
+ bundles.each do |bundle|
85
78
 
86
- puts "Local path: #{local_path}"
79
+ end
80
+ end
81
+ end
82
+
83
+ task :build do |task, arguments|
84
+ config = Teapot::Config.load_default
85
+ context = Teapot::Context.new(config)
86
+
87
+ config.records.each do |record|
88
+ destination_path = record.destination_path
89
+
90
+ record.load(context)
91
+ end
92
+
93
+ build_package = ENV['PACKAGE']
94
+ build_platform = ENV['PLATFORM']
95
+
96
+ if build_package
97
+ package = context.packages[build_package]
98
+
99
+ unless package
100
+ puts "Could not find package #{build_package}".color(:red)
87
101
 
88
- unless bundle.source_path.exist?
89
- unless local_path.exist?
90
- puts "Downloading #{bundle.name} to #{local_path}..."
91
- sh("curl", "-L", url, "-o", local_path.to_s)
92
- end
102
+ next
103
+ end
104
+
105
+ packages = [package]
106
+ else
107
+ packages = context.packages.values
108
+ end
109
+
110
+ if build_platform
111
+ platform = context.platforms[build_platform.to_sym]
112
+
113
+ unless platform
114
+ puts "Could not find platform #{build_platform}".color(:red)
93
115
 
94
- puts "Extracting #{bundle.name}..."
95
- sh("mkdir", bundle.source_path.to_s)
96
- sh("tar", "-C", bundle.source_path.to_s, "--strip-components", "1", "-xvf", local_path.to_s)
97
- end
98
- end
99
- end
116
+ next
100
117
  end
118
+
119
+ platforms = [platform]
120
+ end
121
+
122
+ unless ENV['ONLY']
123
+ ordered = Teapot::Package.build_order(context.packages, packages)
124
+ else
125
+ ordered = packages
126
+ end
127
+
128
+ puts "Building #{ordered.join(', ')} for variant #{config.variant}".color(:blue)
129
+
130
+ context.platforms.each do |name, platform|
131
+ next unless platform.available?
132
+
133
+ puts "Building for #{platform}...".color(:blue)
134
+
135
+ platform.prepare!
136
+
137
+ ordered.each do |package|
138
+ package.build!(platform, :variant => config.variant)
139
+ end
140
+ end
141
+
142
+ puts "Completed build successfully.".color(:green)
143
+ end
144
+
145
+ task :list do
146
+ config = Teapot::Config.load_default
147
+ context = Teapot::Context.new(config)
148
+
149
+ config.records.each do |record|
150
+ destination_path = record.destination_path
151
+
152
+ record.load(context)
153
+ end
154
+
155
+ ordered = Teapot::Package::build_order(context.packages, context.packages.values)
156
+
157
+ ordered.each do |package|
158
+ puts "Package: #{package.name}"
159
+
160
+ if package.depends.size > 0
161
+ puts " (depends on #{package.depends.join(', ')})"
162
+ end
163
+ end
164
+
165
+ context.platforms.each do |platform|
166
+ puts "Platform: #{platform.name}"
101
167
  end
102
168
  end
103
169
 
104
170
  task :help do
105
- $stderr.puts "To create a new teapot, use the setup task:"
106
- $stderr.puts "$ #{File.basename($0)} setup project-path"
171
+ puts "To create a new teapot, use the setup task:"
172
+ puts "$ #{File.basename($0)} setup project-path"
107
173
  end
108
174
 
175
+ task :install => [:fetch, :build]
176
+
109
177
  task :default => :help
110
178
 
111
179
  $app.top_level
@@ -0,0 +1,32 @@
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 'rainbow'
22
+
23
+ module Teapot
24
+ module Commands
25
+ def self.run(*args)
26
+ args.collect!(&:to_s)
27
+
28
+ puts args.join(' ').color(:blue)
29
+ system(*args)
30
+ end
31
+ end
32
+ end
data/lib/teapot/config.rb CHANGED
@@ -21,6 +21,8 @@
21
21
  require 'pathname'
22
22
 
23
23
  require 'teapot/context'
24
+ require 'teapot/environment'
25
+ require 'teapot/commands'
24
26
 
25
27
  module Teapot
26
28
  class Config
@@ -42,12 +44,14 @@ module Teapot
42
44
  end
43
45
 
44
46
  @options = options
47
+ @global = Environment.new
45
48
  end
46
49
 
47
50
  attr :klass
48
51
  attr :name
49
52
  attr :uri
50
53
  attr :options
54
+ attr :global
51
55
 
52
56
  def load(context)
53
57
  context.load(self)
@@ -84,6 +88,8 @@ module Teapot
84
88
 
85
89
  @packages = []
86
90
  @platforms = []
91
+
92
+ @environment = Environment.new
87
93
  end
88
94
 
89
95
  def packages_path
@@ -98,9 +104,34 @@ module Teapot
98
104
  @root + (@options[:build_path] || "build")
99
105
  end
100
106
 
107
+ def variant(*args, &block)
108
+ name = @options[:variant] || 'debug'
109
+
110
+ if block_given?
111
+ if args.find{|arg| arg === name}
112
+ yield
113
+ end
114
+ else
115
+ name
116
+ end
117
+ end
118
+
119
+ def host(*args, &block)
120
+ name = @options[:host_platform] || RUBY_PLATFORM
121
+
122
+ if block_given?
123
+ if args.find{|arg| arg === name}
124
+ yield
125
+ end
126
+ else
127
+ name
128
+ end
129
+ end
130
+
101
131
  attr :options
102
132
  attr :packages
103
133
  attr :platforms
134
+ attr :environment
104
135
 
105
136
  def source(path)
106
137
  @options[:source] = path
@@ -115,10 +146,11 @@ module Teapot
115
146
  end
116
147
 
117
148
  def platform(name, options = {})
149
+ options = {:environment => @environment}.merge(options)
118
150
  @platforms << Record.new(self, Platform, name, options)
119
151
  end
120
152
 
121
- def self.load(root = Dir.getwd, options = {})
153
+ def self.load(root, options = {})
122
154
  config = new(root, options)
123
155
 
124
156
  teapot_path = File.join(root, "Teapot")
@@ -129,5 +161,11 @@ module Teapot
129
161
 
130
162
  return config
131
163
  end
164
+
165
+ def self.load_default(root = Dir.getwd, options = {})
166
+ options.merge!(:variant => ENV['TEAPOT_VARIANT'])
167
+
168
+ load(root, options)
169
+ end
132
170
  end
133
171
  end
@@ -19,13 +19,12 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'pathname'
22
+ require 'rainbow'
22
23
 
23
24
  require 'teapot/package'
24
25
  require 'teapot/platform'
25
26
 
26
27
  module Teapot
27
- PACKAGE_FILE = "package.rb"
28
-
29
28
  class Context
30
29
  def initialize(config)
31
30
  @config = config
@@ -41,6 +40,7 @@ module Teapot
41
40
  attr :platforms
42
41
 
43
42
  def load(record)
43
+ @record = record
44
44
  @defined = []
45
45
 
46
46
  path = (record.destination_path + record.loader_path).to_s
@@ -49,8 +49,8 @@ module Teapot
49
49
  @defined
50
50
  end
51
51
 
52
- def define_package(name, &block)
53
- package = Package.new(self, name)
52
+ def define_package(*args, &block)
53
+ package = Package.new(self, @record, *args)
54
54
 
55
55
  yield(package)
56
56
 
@@ -59,8 +59,8 @@ module Teapot
59
59
  @defined << package
60
60
  end
61
61
 
62
- def define_platform(name, &block)
63
- platform = Platform.new(self, name)
62
+ def define_platform(*args, &block)
63
+ platform = Platform.new(self, @record, *args)
64
64
 
65
65
  yield(platform)
66
66
 
@@ -70,5 +70,9 @@ module Teapot
70
70
 
71
71
  @defined << platform
72
72
  end
73
+
74
+ def global name
75
+ @config.environment[name]
76
+ end
73
77
  end
74
78
  end
@@ -0,0 +1,232 @@
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 'pathname'
22
+ require 'rainbow'
23
+
24
+ require 'rexec'
25
+ require 'yaml'
26
+
27
+ require 'teapot/package'
28
+ require 'teapot/platform'
29
+ require 'teapot/commands'
30
+
31
+ module Teapot
32
+ class Environment
33
+ Default = Struct.new(:value)
34
+
35
+ class Constructor
36
+ def initialize(environment)
37
+ @environment = environment
38
+ end
39
+
40
+ def method_missing(name, value = nil, &block)
41
+ if block_given?
42
+ @environment[name] = block
43
+ else
44
+ @environment[name] = value
45
+ end
46
+
47
+ name
48
+ end
49
+
50
+ def [] key
51
+ @environment[key]
52
+ end
53
+
54
+ def default(name)
55
+ @environment[name] = Default.new(@environment[name])
56
+ end
57
+ end
58
+
59
+ class Evaluator
60
+ def initialize(environment)
61
+ @environment = environment
62
+ end
63
+
64
+ def method_missing(name)
65
+ object_value(@environment[name])
66
+ end
67
+
68
+ private
69
+
70
+ # Compute the literal object value for a given key:
71
+ def object_value(value)
72
+ case value
73
+ when Array
74
+ value.collect{|item| object_value(item)}
75
+ when Symbol
76
+ object_value(@values[value])
77
+ when Proc
78
+ object_value(instance_eval(&value))
79
+ when Default
80
+ object_value(value.value)
81
+ else
82
+ value
83
+ end
84
+ end
85
+ end
86
+
87
+ def self.combine(*environments)
88
+ # Flatten the list of environments:
89
+ environments = environments.collect do |environment|
90
+ if Environment === environment
91
+ environment.to_a
92
+ else
93
+ environment
94
+ end
95
+ end.flatten
96
+
97
+ # Resequence based on order:
98
+ first = Environment.new(nil, environments.shift)
99
+ top = first
100
+
101
+ environments.each do |tail|
102
+ top = Environment.new(top, tail)
103
+ end
104
+
105
+ return top
106
+ end
107
+
108
+ def initialize(parent = nil, values = nil, &block)
109
+ @values = (values || {}).to_hash
110
+ @parent = parent
111
+
112
+ @evaluator = Evaluator.new(self)
113
+
114
+ if block_given?
115
+ construct(&block)
116
+ end
117
+ end
118
+
119
+ def construct(&block)
120
+ Constructor.new(self).instance_eval(&block)
121
+ end
122
+
123
+ def dup
124
+ self.class.new(@values)
125
+ end
126
+
127
+ attr :values
128
+ attr :parent
129
+
130
+ def [] (key)
131
+ environment = lookup(key)
132
+
133
+ environment ? environment.values[key] : nil
134
+ end
135
+
136
+ def []= (key, value)
137
+ @values[key] = value
138
+ end
139
+
140
+ def to_hash
141
+ @values
142
+ end
143
+
144
+ def flatten
145
+ hash = {}
146
+
147
+ flatten_to_hash(hash)
148
+
149
+ Environment.new(nil, hash)
150
+ end
151
+
152
+ def to_string_hash
153
+ Hash[@values.map{|key, value| [key.to_s.upcase, string_value(value)]}]
154
+ end
155
+
156
+ def use(options = {}, &block)
157
+ system_environment = flatten.to_string_hash
158
+
159
+ puts YAML::dump(system_environment).color(:magenta)
160
+
161
+ Dir.chdir(options[:in] || ".") do
162
+ RExec.env(system_environment) do
163
+ @evaluator.instance_eval(&block)
164
+ end
165
+ end
166
+ end
167
+
168
+ def to_s
169
+ "<#{self.class} #{self.values}>"
170
+ end
171
+
172
+ def to_a
173
+ flat = []
174
+
175
+ flatten_to_array(flat)
176
+
177
+ return flat
178
+ end
179
+
180
+ protected
181
+
182
+ def flatten_to_array(array)
183
+ if @parent
184
+ @parent.flatten_to_array(array)
185
+ end
186
+
187
+ array << self
188
+ end
189
+
190
+ def flatten_to_hash(hash)
191
+ if @parent
192
+ @parent.flatten_to_hash(hash)
193
+ end
194
+
195
+ @values.each do |key, value|
196
+ previous = hash[key]
197
+
198
+ if Array === previous
199
+ hash[key] = previous + Array(value)
200
+ elsif Default == previous
201
+ hash[key] ||= previous
202
+ else
203
+ hash[key] = value
204
+ end
205
+ end
206
+ end
207
+
208
+ # Compute the literal string value for a given key:
209
+ def string_value(value)
210
+ case value
211
+ when Array
212
+ value.collect{|item| string_value(item)}.join(' ')
213
+ when Symbol
214
+ string_value(@values[value])
215
+ when Proc
216
+ string_value(@evaluator.instance_eval(&value))
217
+ when Default
218
+ string_value(value.value)
219
+ else
220
+ value.to_s
221
+ end
222
+ end
223
+
224
+ def lookup(name)
225
+ if @values.include? name
226
+ self
227
+ elsif @parent
228
+ @parent.lookup(name)
229
+ end
230
+ end
231
+ end
232
+ end
@@ -1,82 +1,71 @@
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.
1
20
 
2
21
  require 'pathname'
3
22
 
4
23
  module Teapot
5
- class Package
6
- class BuildError < StandardError
24
+ class BuildError < StandardError
25
+ end
26
+
27
+ class Task
28
+ def initialize
29
+ @callbacks = {}
7
30
  end
8
-
9
- class Task
10
- def initialize
11
- @callbacks = {}
12
- end
13
31
 
14
- def define(name, &callback)
15
- @callbacks[name] = callback
16
- end
17
-
18
- def [](name)
19
- @callbacks[name] || @callbacks[:all]
20
- end
32
+ def define(name, &callback)
33
+ @callbacks[name] = callback
21
34
  end
22
-
23
- def self.build_order(available, packages)
24
- ordered = []
25
-
26
- expand = lambda do |name|
27
- package = available[name]
28
-
29
- unless package
30
- puts "Couldn't resolve #{name}"
31
- else
32
- package.depends.each do |dependency|
33
- expand.call(dependency)
34
- end
35
-
36
- unless ordered.include? package
37
- ordered << package
38
- end
39
- end
40
- end
41
-
42
- packages.each do |package|
43
- expand.call(package.name)
44
- end
45
-
46
- return ordered
35
+
36
+ def [](name)
37
+ @callbacks[name] || @callbacks[:all]
47
38
  end
48
-
49
- def initialize(context, name, path = nil)
39
+ end
40
+
41
+ class Package
42
+ def initialize(context, record, name)
50
43
  @context = context
51
-
44
+ @record = record
45
+
52
46
  parts = name.split('-')
53
47
  @name = parts[0..-2].join('-')
54
48
  @version = parts[-1]
55
49
 
56
- @path = path || (context.config.packages_path + @name)
57
-
58
50
  @build = Task.new
59
51
 
60
52
  @depends = []
61
53
 
54
+ @path = @record.destination_path
62
55
  @source_path = @path + name
63
- @fetch_location = nil
64
56
  end
65
57
 
58
+ attr :context
59
+ attr :record
60
+
66
61
  attr :name
67
62
  attr :version
63
+
68
64
  attr :path
69
- attr :variants
70
- attr :fetch_location
71
65
 
72
66
  attr :depends, true
73
67
  attr :source_path, true
74
68
 
75
- def install!
76
- if @fetch_location
77
- end
78
- end
79
-
80
69
  def build(platform, &block)
81
70
  @build.define(platform, &block)
82
71
  end
@@ -84,23 +73,49 @@ module Teapot
84
73
  def build!(platform = :all, config = {})
85
74
  task = @build[platform.name]
86
75
 
87
- puts "Building #{@name} for #{platform.name}"
88
76
  if task
77
+ environment = Environment.combine(
78
+ @record.options[:environment],
79
+ platform.environment,
80
+ config,
81
+ )
82
+
89
83
  Dir.chdir(@path) do
90
- puts "Entering #{@path}..."
91
- task.call(platform, platform.config.merge(config))
84
+ task.call(platform, environment)
92
85
  end
93
86
  else
94
- raise BuildError.new("Could not find task #{task_name} for #{platform.name}!")
87
+ raise BuildError.new("Could not find build task for #{platform.name}!")
95
88
  end
96
89
  end
97
90
 
98
- def fetch_from(location)
99
- @fetch_location = location
100
- end
101
-
102
91
  def to_s
103
92
  "<Package: #{@name}>"
104
93
  end
94
+
95
+ def self.build_order(available, packages)
96
+ ordered = []
97
+
98
+ expand = lambda do |name|
99
+ package = available[name]
100
+
101
+ unless package
102
+ puts "Couldn't resolve #{name}"
103
+ else
104
+ package.depends.each do |dependency|
105
+ expand.call(dependency)
106
+ end
107
+
108
+ unless ordered.include? package
109
+ ordered << package
110
+ end
111
+ end
112
+ end
113
+
114
+ packages.each do |package|
115
+ expand.call(package.name)
116
+ end
117
+
118
+ return ordered
119
+ end
105
120
  end
106
121
  end
@@ -1,32 +1,43 @@
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.
1
20
 
2
21
  require 'fileutils'
22
+ require 'rexec/environment'
3
23
 
4
24
  module Teapot
25
+ class UnavailableError < StandardError
26
+ end
27
+
5
28
  class Platform
6
- class Config
7
- def initialize(values = {})
8
- @values = values
9
- end
29
+ def initialize(context, record, name)
30
+ @context = context
31
+ @record = record
32
+
33
+ @name = name
34
+ @configure = nil
35
+
36
+ @available = false
37
+ end
10
38
 
11
- attr :values
39
+ attr :name
12
40
 
13
- def method_missing(name, *args)
14
- if name.to_s.match(/^(.*?)(\=)?$/)
15
- if $2
16
- return @values[$1.to_sym] = args[0]
17
- else
18
- return @values[$1.to_sym]
19
- end
20
- else
21
- super(name, *args)
22
- end
23
- end
24
-
25
- def merge(config)
26
- Config.new(@values.merge(config))
27
- end
28
- end
29
-
30
41
  def prefix
31
42
  @context.config.build_path + @name.to_s
32
43
  end
@@ -34,30 +45,19 @@ module Teapot
34
45
  def cmake_modules_path
35
46
  prefix + "share/cmake/modules"
36
47
  end
37
-
38
- def initialize(context, name)
39
- @context = context
40
-
41
- @name = name
42
- @config = nil
43
- @available = false
44
- end
45
-
46
- attr :name
47
48
 
48
49
  def configure(&block)
49
- @configuration = Proc.new &block
50
+ @configure = Proc.new &block
50
51
  end
51
52
 
52
- def config
53
- if available?
54
- config = Config.new
55
-
56
- @configuration.call(config)
57
-
58
- return config
53
+ def environment
54
+ if @available
55
+ return Environment.combine(
56
+ @record.options[:environment],
57
+ Environment.new(&@configure),
58
+ )
59
59
  else
60
- return nil
60
+ raise UnavailableError.new("Platform is not available for configuration!")
61
61
  end
62
62
  end
63
63
 
@@ -70,7 +70,7 @@ module Teapot
70
70
  end
71
71
 
72
72
  def to_s
73
- "<Platform #{@name}: #{@availble ? 'available' : 'inactive'}>"
73
+ "<Platform #{@name}: #{@available ? 'available' : 'inactive'}>"
74
74
  end
75
75
 
76
76
  def prepare!
@@ -1,3 +1,23 @@
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
+
1
21
  module Teapot
2
- VERSION = "0.0.1"
22
+ VERSION = "0.0.3"
3
23
  end
data/lib/teapot.rb CHANGED
@@ -1,5 +1,24 @@
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
+
1
21
  require "teapot/version"
2
22
 
3
23
  module Teapot
4
- # Your code goes here...
5
24
  end
data/teapot.gemspec CHANGED
@@ -23,4 +23,5 @@ Gem::Specification.new do |gem|
23
23
 
24
24
  gem.add_dependency "rake"
25
25
  gem.add_dependency "rainbow"
26
+ gem.add_dependency "rexec"
26
27
  end
@@ -0,0 +1,69 @@
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 'pathname'
22
+ require 'test/unit'
23
+ require 'stringio'
24
+
25
+ require 'teapot/environment'
26
+
27
+ class TestEnvironment < Test::Unit::TestCase
28
+ def test_environment_chaining
29
+ a = Teapot::Environment.new
30
+ a[:cflags] = ["-std=c++11"]
31
+
32
+ b = Teapot::Environment.new(a)
33
+ b[:cflags] = ["-stdlib=libc++"]
34
+
35
+ expected = {:cflags => ["-std=c++11", "-stdlib=libc++"]}
36
+
37
+ assert_equal expected, b.flatten.to_hash
38
+ end
39
+
40
+ def test_environment_lambda
41
+ a = Teapot::Environment.new do
42
+ sdk "bob-2.6"
43
+ cflags {"-sdk=#{sdk}"}
44
+ end
45
+
46
+ b = Teapot::Environment.new(a) do
47
+ sdk "bob-2.8"
48
+ end
49
+
50
+ expected = {'SDK' => "bob-2.8", 'CFLAGS' => "-sdk=bob-2.8"}
51
+
52
+ assert_equal [:cflags, :sdk], b.flatten.to_hash.keys.sort
53
+ assert_equal expected, b.flatten.to_string_hash
54
+ end
55
+
56
+ def test_combine
57
+ a = Teapot::Environment.new(nil, {:name => 'a'})
58
+ b = Teapot::Environment.new(a, {:name => 'b'})
59
+ c = Teapot::Environment.new(nil, {:name => 'c'})
60
+ d = Teapot::Environment.new(c, {:name => 'd'})
61
+
62
+ top = Teapot::Environment.combine(b, d)
63
+
64
+ assert_equal d.values, top.values
65
+ assert_equal c.values, top.parent.values
66
+ assert_equal b.values, top.parent.parent.values
67
+ assert_equal a.values, top.parent.parent.parent.values
68
+ end
69
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teapot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-07 00:00:00.000000000 Z
12
+ date: 2012-11-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rexec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  description: ! "\tTeapot is a tool for managing complex cross-platform builds. It
47
63
  provides\n\tadvanced dependency management via the Teapot file and is supported
48
64
  by\n\tthe infusions ecosystem of packages and platform tooling.\n"
@@ -54,17 +70,21 @@ extensions: []
54
70
  extra_rdoc_files: []
55
71
  files:
56
72
  - .gitignore
73
+ - .travis.yml
57
74
  - Gemfile
58
75
  - README.md
59
76
  - Rakefile
60
77
  - bin/teapot
61
78
  - lib/teapot.rb
79
+ - lib/teapot/commands.rb
62
80
  - lib/teapot/config.rb
63
81
  - lib/teapot/context.rb
82
+ - lib/teapot/environment.rb
64
83
  - lib/teapot/package.rb
65
84
  - lib/teapot/platform.rb
66
85
  - lib/teapot/version.rb
67
86
  - teapot.gemspec
87
+ - test/test_environment.rb
68
88
  homepage: ''
69
89
  licenses: []
70
90
  post_install_message:
@@ -79,7 +99,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
99
  version: '0'
80
100
  segments:
81
101
  - 0
82
- hash: -3245373006178987296
102
+ hash: -2599303512074911541
83
103
  required_rubygems_version: !ruby/object:Gem::Requirement
84
104
  none: false
85
105
  requirements:
@@ -88,11 +108,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
108
  version: '0'
89
109
  segments:
90
110
  - 0
91
- hash: -3245373006178987296
111
+ hash: -2599303512074911541
92
112
  requirements: []
93
113
  rubyforge_project:
94
114
  rubygems_version: 1.8.24
95
115
  signing_key:
96
116
  specification_version: 3
97
117
  summary: Teapot is a tool for managing complex cross-platform builds.
98
- test_files: []
118
+ test_files:
119
+ - test/test_environment.rb