bee 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/bin/bee +1 -1
- data/bin/bee.bat +1 -1
- data/egg/package.yml +100 -0
- data/egg/package/bee_task.erb +25 -0
- data/egg/package/build.erb +70 -0
- data/egg/package/egg.yml +58 -0
- data/egg/package/egg_build.erb +57 -0
- data/egg/package/egg_launcher.erb +6 -0
- data/egg/package/egg_script.rb +31 -0
- data/egg/package/gem_spec.erb +23 -0
- data/egg/package/license +202 -0
- data/egg/package/readme.erb +23 -0
- data/egg/package/test.erb +28 -0
- data/egg/package/test_build.erb +16 -0
- data/{test → egg/package}/test_build.rb +1 -1
- data/{test → egg/package}/test_build_listener.rb +3 -1
- data/{test/ts_bee.rb → egg/package/test_suite.rb} +1 -1
- data/lib/bee.rb +468 -167
- data/lib/bee_console.rb +174 -94
- data/lib/bee_task.rb +121 -19
- data/lib/bee_task_default.rb +1016 -229
- data/lib/bee_util.rb +217 -64
- metadata +73 -58
- data/test/tc_bee_build.rb +0 -216
- data/test/tc_bee_console.rb +0 -106
- data/test/tc_bee_console_formatter.rb +0 -81
- data/test/tc_bee_context.rb +0 -84
- data/test/tc_bee_task_default.rb +0 -467
- data/test/tc_bee_util.rb +0 -85
- data/test/tmp_test_case.rb +0 -58
@@ -0,0 +1,23 @@
|
|
1
|
+
= <%= name.capitalize %>
|
2
|
+
|
3
|
+
<%= summary %>
|
4
|
+
|
5
|
+
= Home Page
|
6
|
+
|
7
|
+
This software is hosted on RubyForge (thanks to them for their great job!)
|
8
|
+
at <%= homepage %>.
|
9
|
+
|
10
|
+
= Documentation
|
11
|
+
|
12
|
+
For more information about this software, please read the documentation
|
13
|
+
in "<%= name %>" section on Gem server (type "gem_server" and go at URL
|
14
|
+
http://localhost:8808) if you installed it using Gem.
|
15
|
+
|
16
|
+
= License
|
17
|
+
|
18
|
+
bee is Open Source and released under the Apache License (see LICENE file
|
19
|
+
or go to URL http://www.apache.org/licenses/LICENSE-2.0).
|
20
|
+
|
21
|
+
= Copyright
|
22
|
+
|
23
|
+
<%= name.capitalize %> version <%= version %> (C) <%= author %> - <%= years %>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bee'
|
4
|
+
require 'test/unit'
|
5
|
+
$:.unshift(File.join(File.expand_path(File.dirname(__FILE__))))
|
6
|
+
require 'test_build'
|
7
|
+
require 'test_build_listener'
|
8
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
9
|
+
require 'bee_task_<%= project_short_name %>'
|
10
|
+
|
11
|
+
# Test case for bee task.
|
12
|
+
class TestBeeTask<%= project_short_name.capitalize %> < Test::Unit::TestCase
|
13
|
+
|
14
|
+
# Create a context object and load tasks in it.
|
15
|
+
def setup
|
16
|
+
super
|
17
|
+
@context = Bee::Context.new
|
18
|
+
@listener = TestBuildListener.new
|
19
|
+
@build = TestBuild.new(@context, @listener)
|
20
|
+
@package = Bee::Task::<%= project_short_name.capitalize %>.new(@build)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_hello
|
24
|
+
@package.hello('TEST')
|
25
|
+
assert_equal("Hello TEST!\n", @listener.output)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
- build: package_test
|
2
|
+
default: all
|
3
|
+
description: Build file to test generated and installed package
|
4
|
+
|
5
|
+
- target: task
|
6
|
+
description: Test task for generated package
|
7
|
+
script:
|
8
|
+
- <%= project_short_name %>.hello: "World"
|
9
|
+
|
10
|
+
- target: egg
|
11
|
+
description: Test egg for generated package
|
12
|
+
script:
|
13
|
+
- "bee -t '<%= project_short_name %>.hello'"
|
14
|
+
|
15
|
+
- target: all
|
16
|
+
depends: [task, egg]
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2006-
|
1
|
+
# Copyright 2006-2008 Michel Casabianca <michel.casabianca@gmail.com>
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2006-
|
1
|
+
# Copyright 2006-2008 Michel Casabianca <michel.casabianca@gmail.com>
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -22,11 +22,13 @@ class TestBuildListener
|
|
22
22
|
attr_reader :success
|
23
23
|
attr_reader :errors
|
24
24
|
attr_accessor :output
|
25
|
+
attr_reader :verbose
|
25
26
|
|
26
27
|
def initialize
|
27
28
|
@targets = []
|
28
29
|
@tasks = []
|
29
30
|
@output = ''
|
31
|
+
@verbose = false
|
30
32
|
end
|
31
33
|
|
32
34
|
def build_started(build)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# Copyright 2006-
|
3
|
+
# Copyright 2006-2008 Michel Casabianca <michel.casabianca@gmail.com>
|
4
4
|
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
data/lib/bee.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2006-
|
1
|
+
# Copyright 2006-2008 Michel Casabianca <michel.casabianca@gmail.com>
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -13,44 +13,61 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
require 'yaml'
|
16
|
+
require 'bee_task'
|
16
17
|
require 'bee_util'
|
17
18
|
|
18
19
|
# Module for Bee core classes.
|
19
20
|
module Bee
|
20
|
-
|
21
|
+
|
21
22
|
# Class for a build. This class is built from an object resulting from YAML
|
22
23
|
# build file parsing.
|
23
24
|
class Build
|
24
|
-
|
25
|
+
|
25
26
|
include Bee::Util::BuildErrorMixin
|
26
27
|
include Bee::Util::HashCheckerMixin
|
27
28
|
|
29
|
+
# Build key.
|
30
|
+
KEY = 'build'
|
31
|
+
# Build entry description.
|
32
|
+
DESCRIPTION = {
|
33
|
+
'build' => :mandatory,
|
34
|
+
'default' => :optional,
|
35
|
+
'description' => :optional,
|
36
|
+
'context' => :optional,
|
37
|
+
'extends' => :optional}
|
38
|
+
|
28
39
|
# Build file.
|
29
40
|
attr_reader :file
|
30
|
-
# Base directory
|
31
|
-
# are relative to this directory.
|
41
|
+
# Base directory, that is directory where lives the build file.
|
32
42
|
attr_reader :base
|
43
|
+
# Current directory, where was started the script.
|
44
|
+
attr_reader :here
|
33
45
|
# Build name.
|
34
46
|
attr_reader :name
|
35
|
-
#
|
36
|
-
|
37
|
-
|
47
|
+
# Parent build.
|
48
|
+
attr_reader :extends
|
49
|
+
# Default target, specified with default entry or fist target in build file.
|
50
|
+
attr_accessor :default
|
38
51
|
# Build description.
|
39
52
|
attr_reader :description
|
53
|
+
# Build properties.
|
54
|
+
attr_reader :properties
|
40
55
|
# Hash for targets, indexed by target name.
|
41
56
|
attr_reader :targets
|
42
57
|
# Context for Ruby scripts and properties.
|
43
58
|
attr_reader :context
|
44
|
-
# Package manager
|
59
|
+
# Package manager, for task invocation.
|
45
60
|
attr_reader :package_manager
|
46
|
-
# Build listener
|
61
|
+
# Build listener, responsible for displaying build status.
|
47
62
|
attr_reader :listener
|
48
63
|
|
49
64
|
# Load a build from a YAML build file.
|
50
|
-
# - file: YAML build file.
|
65
|
+
# - file: YAML build file or URL.
|
51
66
|
# - recursive: tells if we look for build file recursively (defaults to
|
52
67
|
# nil).
|
53
|
-
|
68
|
+
# - properties: a hash of additional properties passed on command line.
|
69
|
+
def self.load(file, recursive=nil, properties={})
|
70
|
+
raise "Can't use recursive URL" if recursive and Bee::Util::url?(file)
|
54
71
|
if recursive
|
55
72
|
begin
|
56
73
|
file = Bee::Util::find(file)
|
@@ -59,140 +76,420 @@ module Bee
|
|
59
76
|
"not found recursively")
|
60
77
|
end
|
61
78
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
yaml = File.read(file)
|
79
|
+
begin
|
80
|
+
yaml = Bee::Util::get_file(file)
|
81
|
+
rescue
|
82
|
+
raise Bee::Util::BuildError.
|
83
|
+
new("Error loading build file '#{file}': #{$!}")
|
84
|
+
end
|
69
85
|
begin
|
70
86
|
object = YAML::load(yaml)
|
71
87
|
rescue
|
72
88
|
raise Bee::Util::BuildError.
|
73
|
-
new("YAML syntax error in build file: #{$!}")
|
89
|
+
new("YAML syntax error in build file '#{file}': #{$!}")
|
74
90
|
end
|
75
|
-
return Build.new(object, file)
|
91
|
+
return Build.new(object, file, properties)
|
76
92
|
end
|
77
|
-
|
93
|
+
|
78
94
|
# Constructor:
|
79
|
-
# - object:
|
95
|
+
# - object: object tree resulting from YAML build file parsing.
|
80
96
|
# - file: build file (nil if none).
|
81
|
-
|
82
|
-
|
97
|
+
# - properties: a hash of additional properties passed on command line.
|
98
|
+
# - here: current directory.
|
99
|
+
def initialize(object, file, properties={}, here=Dir.pwd)
|
83
100
|
@file = file
|
84
|
-
|
85
|
-
|
86
|
-
else
|
87
|
-
@base = File.expand_path(Dir.pwd)
|
88
|
-
end
|
89
|
-
error "Build must be a list" unless object.kind_of?(Array)
|
90
|
-
@properties = {}
|
91
|
-
@targets = {}
|
101
|
+
@base = get_base(@file)
|
102
|
+
@here = here
|
92
103
|
@context = Context.new
|
93
|
-
@
|
94
|
-
@properties
|
104
|
+
@properties = Properties.new(self)
|
105
|
+
@properties.evaluate(@context)
|
106
|
+
@targets = Targets.new(self)
|
107
|
+
parse(object)
|
108
|
+
@properties.overwrite(properties)
|
95
109
|
@package_manager = Bee::Task::PackageManager.new(self)
|
96
|
-
# parse object entries
|
97
|
-
for entry in object
|
98
|
-
if entry.key?('build')
|
99
|
-
# build info entry
|
100
|
-
begin
|
101
|
-
check_hash(entry,
|
102
|
-
{'build' => :mandatory,
|
103
|
-
'default' => :optional,
|
104
|
-
'description' => :optional,
|
105
|
-
'context' => :optional})
|
106
|
-
rescue
|
107
|
-
error "Error parsing build entry: #{$!}"
|
108
|
-
end
|
109
|
-
error "Duplicate build info" if @name
|
110
|
-
@name = entry['build']
|
111
|
-
@default = entry['default']
|
112
|
-
@description = entry['description']
|
113
|
-
# load context files if any
|
114
|
-
if entry['context']
|
115
|
-
for script in entry['context']
|
116
|
-
begin
|
117
|
-
based_script = File.join(@base, script)
|
118
|
-
evaluated_script = @context.evaluate_object(based_script)
|
119
|
-
source = File.read(evaluated_script)
|
120
|
-
@context.evaluate_script(source)
|
121
|
-
rescue Exception
|
122
|
-
error "Error loading context '#{script}': #{$!}"
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
elsif entry.key?('properties')
|
127
|
-
# properties entry
|
128
|
-
for property in entry['properties']
|
129
|
-
name = property.keys[0]
|
130
|
-
value = @context.evaluate_object(property[name])
|
131
|
-
@context.set_property(name, value, false)
|
132
|
-
end
|
133
|
-
elsif entry.key?('target')
|
134
|
-
# target entry
|
135
|
-
begin
|
136
|
-
target = Target.new(entry, self)
|
137
|
-
rescue
|
138
|
-
error "Error parsing target '#{entry['target']}': #{$!}"
|
139
|
-
end
|
140
|
-
@default = target.name if !@default and @targets.keys.empty?
|
141
|
-
error "Duplicate target definition: '#{target.name}'" if
|
142
|
-
@targets[target.name]
|
143
|
-
@targets[target.name] = target
|
144
|
-
else
|
145
|
-
# unknown entry
|
146
|
-
error "Unknown entry:\n#{YAML::dump(entry)}"
|
147
|
-
end
|
148
|
-
end
|
149
110
|
end
|
150
111
|
|
112
|
+
# Evaluate properties.
|
113
|
+
def evaluate_properties
|
114
|
+
@properties.evaluate(@context)
|
115
|
+
end
|
116
|
+
|
151
117
|
# Run build:
|
152
118
|
# - targets: list of targets to run.
|
153
119
|
# - listener: listener for the build.
|
154
|
-
def run(targets, listener=nil)
|
120
|
+
def run(targets, listener=nil, dry=false)
|
155
121
|
@listener = listener
|
156
122
|
working_directory = Dir.getwd
|
123
|
+
@listener.build_started(self, dry) if @listener
|
157
124
|
begin
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
targets = [@default] if targets.length == 0
|
162
|
-
for target in targets
|
163
|
-
run_target(target)
|
125
|
+
evaluate_properties
|
126
|
+
if not Bee::Util::url?(@base)
|
127
|
+
Dir.chdir(@base)
|
164
128
|
end
|
165
|
-
@
|
129
|
+
@targets.run(targets, dry)
|
130
|
+
@listener.build_finished(self, dry) if @listener
|
166
131
|
rescue Bee::Util::BuildError => e
|
167
|
-
if listener
|
132
|
+
if @listener
|
168
133
|
@listener.error(e)
|
169
134
|
else
|
170
135
|
raise e
|
171
136
|
end
|
172
137
|
ensure
|
173
|
-
@listener = nil
|
174
138
|
Dir.chdir(working_directory)
|
139
|
+
remove_instance_variable(:@listener)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# Parse entries in build object.
|
146
|
+
# - object: object tree resulting from YAML build file parsing.
|
147
|
+
def parse(object)
|
148
|
+
error "Build must be a list" unless object.kind_of?(Array)
|
149
|
+
first = true
|
150
|
+
for entry in object
|
151
|
+
if entry.key?(Build::KEY)
|
152
|
+
parse_build(entry)
|
153
|
+
error "Build info entry must be first one in build file" if
|
154
|
+
not first
|
155
|
+
first = false
|
156
|
+
elsif entry.key?(Properties::KEY)
|
157
|
+
@properties.write(entry)
|
158
|
+
first = false
|
159
|
+
elsif entry.key?(Target::KEY)
|
160
|
+
@targets.add(entry)
|
161
|
+
first = false
|
162
|
+
else
|
163
|
+
error "Unknown entry:\n#{YAML::dump(entry)}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
# manage parent build
|
167
|
+
if @parent
|
168
|
+
@properties.extend(@parent.properties)
|
169
|
+
@targets.extend(@parent.targets)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Parse a build entry.
|
174
|
+
# - entry: the build entry to parse.
|
175
|
+
def parse_build(entry)
|
176
|
+
begin
|
177
|
+
check_hash(entry, Build::DESCRIPTION)
|
178
|
+
rescue
|
179
|
+
error "Error parsing build info entry: #{$!}"
|
180
|
+
end
|
181
|
+
error "Duplicate build info" if @name
|
182
|
+
@name = entry['build']
|
183
|
+
@default = entry['default']
|
184
|
+
@targets.default = @default
|
185
|
+
@description = entry['description']
|
186
|
+
@extends = entry['extends']
|
187
|
+
# load parent build if any
|
188
|
+
if @extends
|
189
|
+
absolute_path = Bee::Util::absolute_path(@extends, @base)
|
190
|
+
begin
|
191
|
+
@parent = Bee::Build::load(absolute_path)
|
192
|
+
rescue Exception
|
193
|
+
error "Error loading parent build file '#{@extends}': #{$!}"
|
194
|
+
end
|
195
|
+
@default = @default || @parent.default
|
196
|
+
@targets.default = @default
|
197
|
+
@description = @description || @parent.description
|
198
|
+
end
|
199
|
+
# load context files if any
|
200
|
+
context = entry['context']
|
201
|
+
if context
|
202
|
+
context = Array(context)
|
203
|
+
for script in context
|
204
|
+
begin
|
205
|
+
evaluated = @context.evaluate_object(script)
|
206
|
+
source = Bee::Util::get_file(evaluated, @base)
|
207
|
+
@context.evaluate_script(source)
|
208
|
+
rescue Exception
|
209
|
+
error "Error loading context '#{script}': #{$!}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Get base for a given file.
|
216
|
+
# - file: build file.
|
217
|
+
def get_base(file)
|
218
|
+
if file
|
219
|
+
if Bee::Util::url?(file)
|
220
|
+
return File.dirname(file)
|
221
|
+
else
|
222
|
+
return File.expand_path(File.dirname(Bee::Util::absolute_path(file, Dir.pwd)))
|
223
|
+
end
|
224
|
+
else
|
225
|
+
return File.expand_path(Dir.pwd)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
# Class to manage properties.
|
232
|
+
class Properties
|
233
|
+
|
234
|
+
include Bee::Util::BuildErrorMixin
|
235
|
+
|
236
|
+
# Key for properties entry.
|
237
|
+
KEY = 'properties'
|
238
|
+
|
239
|
+
# List of properties in order of evaluation.
|
240
|
+
attr_reader :list
|
241
|
+
# Hash of properties by name.
|
242
|
+
attr_reader :hash
|
243
|
+
|
244
|
+
# Constructor.
|
245
|
+
# - build: build object.
|
246
|
+
def initialize(build)
|
247
|
+
@list = []
|
248
|
+
@hash = {}
|
249
|
+
@build = build
|
250
|
+
defaults
|
251
|
+
end
|
252
|
+
|
253
|
+
# Write properties. Will raise an error on duplicate definitions.
|
254
|
+
# - object: object tree resulting from YAML build file parsing or string
|
255
|
+
# for a properties file to load.
|
256
|
+
def write(object)
|
257
|
+
properties = object[Properties::KEY]
|
258
|
+
if properties.kind_of?(String)
|
259
|
+
begin
|
260
|
+
source = Bee::Util::get_file(properties, @build.base)
|
261
|
+
list = YAML::load(source)
|
262
|
+
set_properties(list, false)
|
263
|
+
rescue Exception
|
264
|
+
error "Error loading properties file '#{properties}': #{$!}"
|
265
|
+
end
|
266
|
+
else
|
267
|
+
set_properties(properties, false)
|
175
268
|
end
|
176
269
|
end
|
177
270
|
|
271
|
+
# Overwrite properties. Will raise an error if properties don't already
|
272
|
+
# exist.
|
273
|
+
# - object: object tree resulting from YAML build file parsing.
|
274
|
+
def overwrite(object)
|
275
|
+
set_properties(object, true)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Extend with properties of parent build.
|
279
|
+
# - properties: properties of parent build.
|
280
|
+
def extend(properties)
|
281
|
+
current_list = @list
|
282
|
+
current_hash = @hash
|
283
|
+
@list = properties.list
|
284
|
+
@hash = properties.hash
|
285
|
+
index = 0
|
286
|
+
0.upto(current_list.length - 1) do |current|
|
287
|
+
name = current_list[current]
|
288
|
+
pos = @list.index(name)
|
289
|
+
if pos
|
290
|
+
sub = current_list[index .. current]
|
291
|
+
@list[pos .. pos] = sub
|
292
|
+
for name in sub
|
293
|
+
@hash[name] = current_hash[name]
|
294
|
+
end
|
295
|
+
index = current + 1
|
296
|
+
end
|
297
|
+
end
|
298
|
+
tail = current_list[index .. current_list.length() - 1]
|
299
|
+
@list += tail
|
300
|
+
for name in tail
|
301
|
+
@hash[name] = current_hash[name]
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# Evaluate properties in context.
|
306
|
+
# - context: build context where properties must be evaluated.
|
307
|
+
def evaluate(context)
|
308
|
+
for name in @list
|
309
|
+
begin
|
310
|
+
value = context.evaluate_object(@hash[name])
|
311
|
+
rescue Bee::Util::BuildError
|
312
|
+
error "Error evaluating property '#{name}': #{$!}"
|
313
|
+
end
|
314
|
+
context.set_property(name, value, true)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
private
|
319
|
+
|
320
|
+
# Set default properties.
|
321
|
+
def defaults
|
322
|
+
set(:base, @build.base, false)
|
323
|
+
set(:here, @build.here, false)
|
324
|
+
end
|
325
|
+
|
326
|
+
# Set properties.
|
327
|
+
# - properties: properties as a list of hash if overwrite = false
|
328
|
+
# or a hash if overwrite = true.
|
329
|
+
# - overwrite: tells if we can overwrite existing properties.
|
330
|
+
def set_properties(properties, overwrite)
|
331
|
+
if overwrite
|
332
|
+
raise "Properties must be a hash" if not properties.kind_of?(Hash)
|
333
|
+
for name in properties.keys
|
334
|
+
expression = properties[name]
|
335
|
+
set(name, expression, overwrite)
|
336
|
+
end
|
337
|
+
else
|
338
|
+
raise "Properties must be a list" if not properties.kind_of?(Array)
|
339
|
+
for property in properties
|
340
|
+
name = property.keys[0]
|
341
|
+
expression = property[name]
|
342
|
+
set(name, expression, overwrite)
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# Set a property.
|
348
|
+
# - name: property name (as a string or symbol).
|
349
|
+
# - expression: property expression (as a string) to be evaluated in
|
350
|
+
# context to get value.
|
351
|
+
# - overwrite: tells if we can overwrite existing properties.
|
352
|
+
def set(name, expression, overwrite)
|
353
|
+
name = name.to_sym
|
354
|
+
error "Duplicate property definition: '#{name}'" if
|
355
|
+
not overwrite and @hash.has_key?(name)
|
356
|
+
@list << name
|
357
|
+
@hash[name] = expression
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
# Class to manage targets in a build.
|
363
|
+
class Targets
|
364
|
+
|
365
|
+
include Bee::Util::BuildErrorMixin
|
366
|
+
|
367
|
+
# Parent build.
|
368
|
+
attr_reader :build
|
369
|
+
# Targets hash by name.
|
370
|
+
attr_reader :hash
|
371
|
+
# Targets already run.
|
372
|
+
attr_reader :already_run
|
373
|
+
# Default target.
|
374
|
+
attr_accessor :default
|
375
|
+
|
376
|
+
# Constructor.
|
377
|
+
# - build: build object.
|
378
|
+
def initialize(build)
|
379
|
+
@build = build
|
380
|
+
@hash = {}
|
381
|
+
@already_run = []
|
382
|
+
end
|
383
|
+
|
384
|
+
# Add a new target.
|
385
|
+
# - object: object tree resulting from YAML build file parsing.
|
386
|
+
def add(object)
|
387
|
+
begin
|
388
|
+
target = Target.new(object, self)
|
389
|
+
rescue
|
390
|
+
error "Error parsing target '#{object[Target::KEY]}': #{$!}"
|
391
|
+
end
|
392
|
+
error "Duplicate target definition: '#{target.name}'" if
|
393
|
+
@hash.has_key?(target.name)
|
394
|
+
@hash[target.name] = [target]
|
395
|
+
if !@default
|
396
|
+
@default = target.name
|
397
|
+
@build.default = target.name
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
# Extend parent targets.
|
402
|
+
# - parent: parent targets.
|
403
|
+
def extend(parent)
|
404
|
+
# set appropriate targets
|
405
|
+
for targets in parent.hash.values
|
406
|
+
for target in targets
|
407
|
+
target.targets = self
|
408
|
+
end
|
409
|
+
end
|
410
|
+
# insert parent targets before current ones
|
411
|
+
for name in parent.hash.keys
|
412
|
+
if @hash[name]
|
413
|
+
@hash[name] = parent.hash[name] + @hash[name]
|
414
|
+
else
|
415
|
+
@hash[name] = parent.hash[name]
|
416
|
+
end
|
417
|
+
end
|
418
|
+
# set default default target to parent one if none was set
|
419
|
+
@default = @default || parent.default
|
420
|
+
end
|
421
|
+
|
422
|
+
# Run targets.
|
423
|
+
# - targets: list of target names to run.
|
424
|
+
def run(targets, dry)
|
425
|
+
error "No default target given" if (!@default and targets.length == 0)
|
426
|
+
targets = [@default] if targets.length == 0
|
427
|
+
for target in targets
|
428
|
+
run_target(target, dry)
|
429
|
+
@already_run.clear
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
# Call super target.
|
434
|
+
# - target: target that calls super.
|
435
|
+
def call_super(target, dry=false)
|
436
|
+
index = @hash[target.name].index(target)
|
437
|
+
error "No super target to call for '#{target.name}'" if index == 0
|
438
|
+
index -= 1
|
439
|
+
@hash[target.name][index].run(dry)
|
440
|
+
end
|
441
|
+
|
442
|
+
# Tells if a given target is last in hierarchy.
|
443
|
+
# - target: given target.
|
444
|
+
def is_last(target)
|
445
|
+
index = @hash[target.name].index(target)
|
446
|
+
last = @hash[target.name].size - 1
|
447
|
+
return index == last
|
448
|
+
end
|
449
|
+
|
178
450
|
# Run a given target.
|
179
451
|
# - target: the target to run.
|
180
|
-
def run_target(target)
|
181
|
-
error "Target '#{target}' not found" if not @
|
182
|
-
@
|
452
|
+
def run_target(target, dry=false)
|
453
|
+
error "Target '#{target}' not found" if not @hash[target]
|
454
|
+
if not @already_run.include?(target)
|
455
|
+
@already_run << target
|
456
|
+
@hash[target].last.run(dry)
|
457
|
+
end
|
183
458
|
end
|
184
459
|
|
460
|
+
# Return targets description as a hash of descriptions indexed by
|
461
|
+
# target name. Dependencies are added after target description.
|
462
|
+
def description
|
463
|
+
description = {}
|
464
|
+
for name in @hash.keys
|
465
|
+
text = @hash[name].last.description
|
466
|
+
depends = ' [' + @hash[name].last.depends.join(', ') + ']' if
|
467
|
+
@hash[name].last.depends and @hash[name].last.depends.length > 0
|
468
|
+
description[name] = (text ? text : '') + (depends ? depends : '')
|
469
|
+
end
|
470
|
+
return description
|
471
|
+
end
|
472
|
+
|
185
473
|
end
|
186
|
-
|
474
|
+
|
187
475
|
# Class for a target. It is built from the YAML build file and manages a
|
188
476
|
# target, in particular, tasks execution.
|
189
477
|
class Target
|
190
|
-
|
478
|
+
|
191
479
|
include Bee::Util::BuildErrorMixin
|
192
480
|
include Bee::Util::HashCheckerMixin
|
193
481
|
|
194
|
-
#
|
195
|
-
|
482
|
+
# Target key.
|
483
|
+
KEY = 'target'
|
484
|
+
# Target entry description.
|
485
|
+
DESCRIPTION = {
|
486
|
+
'target' => :mandatory,
|
487
|
+
'depends' => :optional,
|
488
|
+
'description' => :optional,
|
489
|
+
'script' => :optional}
|
490
|
+
|
491
|
+
# Targets for build.
|
492
|
+
attr_accessor :targets
|
196
493
|
# Name of the target.
|
197
494
|
attr_reader :name
|
198
495
|
# Target dependencies.
|
@@ -201,116 +498,118 @@ module Bee
|
|
201
498
|
attr_reader :description
|
202
499
|
# Script that run in the target.
|
203
500
|
attr_reader :script
|
204
|
-
|
501
|
+
|
205
502
|
# Constructor.
|
206
503
|
# - object: object for target, resulting from YAML parsing.
|
207
|
-
# -
|
208
|
-
def initialize(object,
|
209
|
-
check_hash(object,
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
'script' => :optional})
|
214
|
-
@build = build
|
215
|
-
@name = object['target']
|
504
|
+
# - targets: build targets.
|
505
|
+
def initialize(object, targets)
|
506
|
+
check_hash(object, Target::DESCRIPTION)
|
507
|
+
@targets = targets
|
508
|
+
@name = object[Target::KEY]
|
509
|
+
error "Target name cannot be 'null'" if @name == nil
|
216
510
|
@depends = object['depends']||[]
|
511
|
+
@depends = Array(@depends)
|
217
512
|
@description = object['description']
|
218
513
|
@script = object['script']
|
514
|
+
@script = [@script] if @script.kind_of?(String)
|
515
|
+
@script = [] if not @script
|
219
516
|
end
|
220
|
-
|
517
|
+
|
221
518
|
# Run target.
|
222
|
-
|
519
|
+
# - dry: tells if we run in dry mode. Defaults to false.
|
520
|
+
def run(dry=false)
|
521
|
+
current_dir = Dir.pwd
|
223
522
|
begin
|
224
|
-
|
225
|
-
@
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
case @script
|
232
|
-
when String
|
233
|
-
run_task(@script)
|
234
|
-
when Array
|
235
|
-
for task in @script
|
236
|
-
run_task(task)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
523
|
+
for depend in @depends
|
524
|
+
@targets.run_target(depend, dry)
|
525
|
+
end
|
526
|
+
@targets.build.listener.target(self) if
|
527
|
+
@targets.build.listener and @targets.is_last(self)
|
528
|
+
for task in @script
|
529
|
+
run_task(task, dry)
|
240
530
|
end
|
241
531
|
ensure
|
242
|
-
Dir.chdir(
|
532
|
+
Dir.chdir(current_dir)
|
243
533
|
end
|
244
534
|
end
|
245
|
-
|
535
|
+
|
246
536
|
private
|
247
|
-
|
537
|
+
|
248
538
|
# Run a task.
|
249
539
|
# - task: the task to run.
|
250
|
-
|
251
|
-
|
540
|
+
# - dry: whether to just print.
|
541
|
+
def run_task(task, dry=false)
|
542
|
+
@targets.build.listener.task(task) if @targets.build.listener
|
252
543
|
case task
|
253
544
|
when String
|
254
545
|
# shell script
|
255
|
-
run_shell(task)
|
546
|
+
run_shell(task, dry)
|
256
547
|
when Hash
|
257
548
|
error "A task entry must be a Hash with a single key" if
|
258
549
|
task.keys.length != 1
|
259
550
|
if task.key?('rb')
|
260
551
|
# ruby script
|
261
552
|
script = task['rb']
|
262
|
-
run_ruby(script)
|
553
|
+
run_ruby(script, dry)
|
554
|
+
elsif task.key?('super')
|
555
|
+
# call super target
|
556
|
+
targets.call_super(self, dry)
|
263
557
|
else
|
264
558
|
# must be a task
|
265
|
-
run_bee_task(task)
|
559
|
+
run_bee_task(task, dry)
|
266
560
|
end
|
267
561
|
end
|
268
562
|
end
|
269
|
-
|
563
|
+
|
270
564
|
# Run a given shell script.
|
271
565
|
# - script: the scrip to run.
|
272
|
-
def run_shell(script)
|
566
|
+
def run_shell(script, dry=false)
|
273
567
|
@listener.task(script) if @listener
|
274
|
-
|
275
|
-
|
276
|
-
|
568
|
+
return if dry
|
569
|
+
evaluated_script = @targets.build.context.evaluate_object(script)
|
570
|
+
if evaluated_script != ''
|
571
|
+
system(evaluated_script)
|
572
|
+
error "Script exited with value #{$?}" if $? != 0
|
573
|
+
end
|
277
574
|
end
|
278
|
-
|
575
|
+
|
279
576
|
# Run a given shell script.
|
280
577
|
# - script: the scrip to run.
|
281
|
-
|
578
|
+
# - dry: tells if we run in dry mode.
|
579
|
+
def run_ruby(script, dry=false)
|
282
580
|
@listener.task(script) if @listener
|
581
|
+
return if dry
|
283
582
|
begin
|
284
|
-
@build.context.evaluate_script(script)
|
583
|
+
@targets.build.context.evaluate_script(script)
|
285
584
|
rescue Exception
|
286
585
|
error "Error running Ruby script: #{$!}"
|
287
586
|
end
|
288
587
|
end
|
289
|
-
|
588
|
+
|
290
589
|
# Run a given bee task.
|
291
590
|
# - task: task to run as a Hash.
|
292
|
-
def run_bee_task(task)
|
293
|
-
require 'bee_task'
|
591
|
+
def run_bee_task(task, dry=false)
|
294
592
|
@listener.task(task) if @listener
|
295
|
-
|
593
|
+
return if dry
|
594
|
+
@targets.build.package_manager.run_task(task)
|
296
595
|
end
|
297
|
-
|
298
|
-
end
|
299
596
|
|
597
|
+
end
|
598
|
+
|
300
599
|
# Class for Ruby scripts context. All embedded Ruby scripts run in this
|
301
600
|
# context where build properties are defined as Ruby variables.
|
302
601
|
class Context
|
303
|
-
|
602
|
+
|
304
603
|
include Bee::Util::BuildErrorMixin
|
305
|
-
|
604
|
+
|
306
605
|
# The binding of this context.
|
307
606
|
attr_reader :context_binding
|
308
|
-
|
607
|
+
|
309
608
|
# Constructor.
|
310
609
|
def initialize
|
311
610
|
@context_binding = get_binding
|
312
611
|
end
|
313
|
-
|
612
|
+
|
314
613
|
# Set a given property in context.
|
315
614
|
# - name: the property name.
|
316
615
|
# - value: the property value.
|
@@ -324,7 +623,7 @@ module Bee
|
|
324
623
|
error "Error setting property '#{name} = #{value.inspect}': #{$!}"
|
325
624
|
end
|
326
625
|
end
|
327
|
-
|
626
|
+
|
328
627
|
# Get a given property in context.
|
329
628
|
# - name: the property name.
|
330
629
|
# - strict: raise an error if given property was not set.
|
@@ -333,6 +632,8 @@ module Bee
|
|
333
632
|
strict and !properties.include?(name.to_s)
|
334
633
|
begin
|
335
634
|
eval("#{name}", @context_binding)
|
635
|
+
rescue NameError
|
636
|
+
error "Property '#{name}' was not set"
|
336
637
|
rescue Exception
|
337
638
|
error "Error getting property '#{name}': #{$!}"
|
338
639
|
end
|
@@ -342,13 +643,13 @@ module Bee
|
|
342
643
|
def properties
|
343
644
|
return eval('local_variables', @context_binding)
|
344
645
|
end
|
345
|
-
|
646
|
+
|
346
647
|
# Evaluate a script in context.
|
347
|
-
# - script: script to evaluate.
|
648
|
+
# - script: source of the script to evaluate.
|
348
649
|
def evaluate_script(script)
|
349
650
|
eval(script, @context_binding)
|
350
651
|
end
|
351
|
-
|
652
|
+
|
352
653
|
# Process a given object, replacing properties references with their
|
353
654
|
# string value, symbol with their raw value. Property references have
|
354
655
|
# same form than variable references in ruby strings: '#{variable}'
|
@@ -387,14 +688,14 @@ module Bee
|
|
387
688
|
return object
|
388
689
|
end
|
389
690
|
end
|
390
|
-
|
691
|
+
|
391
692
|
private
|
392
|
-
|
693
|
+
|
393
694
|
# Get a binding as script context.
|
394
695
|
def get_binding
|
395
696
|
return binding
|
396
697
|
end
|
397
|
-
|
698
|
+
|
398
699
|
end
|
399
|
-
|
700
|
+
|
400
701
|
end
|