bee 0.3.1 → 0.4.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 +16 -0
- data/bin/bee.bat +32 -0
- data/lib/bee.rb +165 -170
- data/lib/bee_console.rb +90 -87
- data/lib/bee_task.rb +149 -0
- data/lib/bee_task_default.rb +525 -0
- data/lib/bee_util.rb +230 -0
- data/test/tc_bee_build.rb +216 -0
- data/test/tc_bee_console.rb +106 -0
- data/test/tc_bee_console_formatter.rb +38 -3
- data/test/tc_bee_context.rb +84 -0
- data/test/tc_bee_task_default.rb +467 -0
- data/test/tc_bee_util.rb +85 -0
- data/test/test_build.rb +26 -0
- data/test/test_build_listener.rb +60 -0
- data/test/tmp_test_case.rb +58 -0
- data/test/ts_bee.rb +1 -1
- metadata +35 -8
- data/lib/bee_default_context.rb +0 -475
- data/test/tc_bee_default_tasks.rb +0 -298
data/README
CHANGED
data/bin/bee
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
+
# Copyright 2006-2007 Michel Casabianca <michel.casabianca@gmail.com>
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
# Launching script for bee.
|
18
|
+
|
3
19
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
20
|
require 'bee_console'
|
5
21
|
|
data/bin/bee.bat
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
@echo off
|
2
|
+
if not "%~f0" == "~f0" goto WinNT
|
3
|
+
ruby -Sx "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
|
4
|
+
goto endofruby
|
5
|
+
:WinNT
|
6
|
+
"%~d0%~p0ruby" -x "%~f0" %*
|
7
|
+
goto endofruby
|
8
|
+
#!/usr/bin/env ruby
|
9
|
+
|
10
|
+
# Copyright 2006-2007 Michel Casabianca <michel.casabianca@gmail.com>
|
11
|
+
#
|
12
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
13
|
+
# you may not use this file except in compliance with the License.
|
14
|
+
# You may obtain a copy of the License at
|
15
|
+
#
|
16
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
#
|
18
|
+
# Unless required by applicable law or agreed to in writing, software
|
19
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
20
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
21
|
+
# See the License for the specific language governing permissions and
|
22
|
+
# limitations under the License.
|
23
|
+
|
24
|
+
# Launching script for bee.
|
25
|
+
|
26
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
27
|
+
require 'bee_console'
|
28
|
+
|
29
|
+
Bee::Console.start_command_line
|
30
|
+
|
31
|
+
__END__
|
32
|
+
:endofruby
|
data/lib/bee.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2006 Michel Casabianca <
|
1
|
+
# Copyright 2006-2007 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.
|
@@ -12,125 +12,139 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
require 'yaml'
|
19
|
-
|
20
|
-
#########################################################################
|
21
|
-
# BUILD ERROR #
|
22
|
-
#########################################################################
|
23
|
-
|
24
|
-
class BuildError < RuntimeError; end
|
25
|
-
|
26
|
-
module BuildErrorMixin
|
27
|
-
|
28
|
-
# Convenient method to raise a BuildError.
|
29
|
-
# - message: error message.
|
30
|
-
def error(message)
|
31
|
-
raise BuildError.new(message)
|
32
|
-
end
|
15
|
+
require 'yaml'
|
16
|
+
require 'bee_util'
|
33
17
|
|
34
|
-
|
35
|
-
|
36
|
-
#########################################################################
|
37
|
-
# BUILD CLASS #
|
38
|
-
#########################################################################
|
18
|
+
# Module for Bee core classes.
|
19
|
+
module Bee
|
39
20
|
|
40
|
-
# Class for a
|
21
|
+
# Class for a build. This class is built from an object resulting from YAML
|
22
|
+
# build file parsing.
|
41
23
|
class Build
|
42
24
|
|
43
|
-
include BuildErrorMixin
|
25
|
+
include Bee::Util::BuildErrorMixin
|
26
|
+
include Bee::Util::HashCheckerMixin
|
44
27
|
|
45
28
|
# Build file.
|
46
29
|
attr_reader :file
|
47
|
-
# Base directory.
|
30
|
+
# Base directory (directory where lives the build file). All file paths
|
31
|
+
# are relative to this directory.
|
48
32
|
attr_reader :base
|
49
33
|
# Build name.
|
50
34
|
attr_reader :name
|
51
|
-
# Default target
|
35
|
+
# Default target (bee runs target passed on the command line, default
|
36
|
+
# target or first one in build file).
|
52
37
|
attr_reader :default
|
53
38
|
# Build description.
|
54
39
|
attr_reader :description
|
55
|
-
# Properties hash (used for project help).
|
56
|
-
attr_reader :properties
|
57
40
|
# Hash for targets, indexed by target name.
|
58
41
|
attr_reader :targets
|
59
42
|
# Context for Ruby scripts and properties.
|
60
43
|
attr_reader :context
|
61
|
-
#
|
62
|
-
attr_reader :
|
63
|
-
# Build listener.
|
44
|
+
# Package manager (for task invocation).
|
45
|
+
attr_reader :package_manager
|
46
|
+
# Build listener (responsible for displaying build status).
|
64
47
|
attr_reader :listener
|
48
|
+
|
49
|
+
# Load a build from a YAML build file.
|
50
|
+
# - file: YAML build file.
|
51
|
+
# - recursive: tells if we look for build file recursively (defaults to
|
52
|
+
# nil).
|
53
|
+
def self.load(file, recursive=nil)
|
54
|
+
if recursive
|
55
|
+
begin
|
56
|
+
file = Bee::Util::find(file)
|
57
|
+
rescue
|
58
|
+
raise Bee::Util::BuildError.new("Build file '#{file}' " +
|
59
|
+
"not found recursively")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
raise Bee::Util::BuildError.new("Build file '#{file}' not found") if
|
63
|
+
not File.exists?(file)
|
64
|
+
raise Bee::Util::BuildError.new("Build file '#{file}' is not a file") if
|
65
|
+
not File.file?(file)
|
66
|
+
raise Bee::Util::BuildError.new("Build file '#{file}' is not readable") if
|
67
|
+
not File.readable?(file)
|
68
|
+
yaml = File.read(file)
|
69
|
+
begin
|
70
|
+
object = YAML::load(yaml)
|
71
|
+
rescue
|
72
|
+
raise Bee::Util::BuildError.
|
73
|
+
new("YAML syntax error in build file: #{$!}")
|
74
|
+
end
|
75
|
+
return Build.new(object, file)
|
76
|
+
end
|
65
77
|
|
66
78
|
# Constructor:
|
67
|
-
# -
|
68
|
-
|
79
|
+
# - object: build description as an object (resulting from YAML loading).
|
80
|
+
# - file: build file (nil if none).
|
81
|
+
def initialize(object, file)
|
82
|
+
require 'bee_task'
|
69
83
|
@file = file
|
84
|
+
if file
|
85
|
+
@base = File.expand_path(File.dirname(file))
|
86
|
+
else
|
87
|
+
@base = File.expand_path(Dir.pwd)
|
88
|
+
end
|
89
|
+
error "Build must be a list" unless object.kind_of?(Array)
|
70
90
|
@properties = {}
|
71
91
|
@targets = {}
|
72
|
-
@tasks = {}
|
73
92
|
@context = Context.new
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
based_script = File.join(@base, script)
|
98
|
-
evaluated_script = @context.evaluate_object(based_script)
|
99
|
-
source = File.read(evaluated_script)
|
100
|
-
load_context(source)
|
101
|
-
rescue
|
102
|
-
error "Error loading context '#{script}': #{$!}"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
elsif entry.key?('properties')
|
107
|
-
# properties entry
|
108
|
-
for property in entry['properties']
|
93
|
+
@context.set_property(:base, @base)
|
94
|
+
@properties[:base] = @base
|
95
|
+
@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']
|
109
116
|
begin
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
rescue
|
117
|
-
error "Error evaluating property '#{name}': #{$!}"
|
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}': #{$!}"
|
118
123
|
end
|
119
124
|
end
|
120
|
-
|
121
|
-
|
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
|
122
136
|
target = Target.new(entry, self)
|
123
|
-
|
124
|
-
error "
|
125
|
-
@targets[target.name]
|
126
|
-
@targets[target.name] = target
|
127
|
-
else
|
128
|
-
# unknown entry
|
129
|
-
error "Unknown entry:\n#{YAML::dump(entry)}"
|
137
|
+
rescue
|
138
|
+
error "Error parsing target '#{entry['target']}': #{$!}"
|
130
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)}"
|
131
147
|
end
|
132
|
-
rescue
|
133
|
-
error "Error loading build file '#{@file}': #{$!}"
|
134
148
|
end
|
135
149
|
end
|
136
150
|
|
@@ -148,8 +162,8 @@ module Bee
|
|
148
162
|
for target in targets
|
149
163
|
run_target(target)
|
150
164
|
end
|
151
|
-
@listener.build_finished(self)
|
152
|
-
rescue BuildError => e
|
165
|
+
@listener.build_finished(self) if @listener
|
166
|
+
rescue Bee::Util::BuildError => e
|
153
167
|
if listener
|
154
168
|
@listener.error(e)
|
155
169
|
else
|
@@ -168,31 +182,14 @@ module Bee
|
|
168
182
|
@targets[target].run
|
169
183
|
end
|
170
184
|
|
171
|
-
private
|
172
|
-
|
173
|
-
# Load a given context and add last expression evaluated in context to
|
174
|
-
# extension tasks mapping.
|
175
|
-
# - source: the context source.
|
176
|
-
def load_context(source)
|
177
|
-
new_tasks = @context.evaluate_script(source)
|
178
|
-
if new_tasks.kind_of?(Hash)
|
179
|
-
for task in new_tasks.keys
|
180
|
-
error "Duplicate definition for task '#{task}'" if @tasks[task]
|
181
|
-
end
|
182
|
-
@tasks.merge!(new_tasks)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
185
|
end
|
187
186
|
|
188
|
-
|
189
|
-
#
|
190
|
-
#########################################################################
|
191
|
-
|
192
|
-
# Class for a given target.
|
187
|
+
# Class for a target. It is built from the YAML build file and manages a
|
188
|
+
# target, in particular, tasks execution.
|
193
189
|
class Target
|
194
190
|
|
195
|
-
include BuildErrorMixin
|
191
|
+
include Bee::Util::BuildErrorMixin
|
192
|
+
include Bee::Util::HashCheckerMixin
|
196
193
|
|
197
194
|
# Build that encapsulates target.
|
198
195
|
attr_reader :build
|
@@ -206,14 +203,19 @@ module Bee
|
|
206
203
|
attr_reader :script
|
207
204
|
|
208
205
|
# Constructor.
|
209
|
-
# -
|
206
|
+
# - object: object for target, resulting from YAML parsing.
|
210
207
|
# - build: build that encapsulate this target.
|
211
|
-
def initialize(
|
208
|
+
def initialize(object, build)
|
209
|
+
check_hash(object,
|
210
|
+
{'target' => :mandatory,
|
211
|
+
'depends' => :optional,
|
212
|
+
'description' => :optional,
|
213
|
+
'script' => :optional})
|
212
214
|
@build = build
|
213
|
-
@name =
|
214
|
-
@depends =
|
215
|
-
@description =
|
216
|
-
@script =
|
215
|
+
@name = object['target']
|
216
|
+
@depends = object['depends']||[]
|
217
|
+
@description = object['description']
|
218
|
+
@script = object['script']
|
217
219
|
end
|
218
220
|
|
219
221
|
# Run target.
|
@@ -260,7 +262,7 @@ module Bee
|
|
260
262
|
run_ruby(script)
|
261
263
|
else
|
262
264
|
# must be a task
|
263
|
-
|
265
|
+
run_bee_task(task)
|
264
266
|
end
|
265
267
|
end
|
266
268
|
end
|
@@ -280,37 +282,26 @@ module Bee
|
|
280
282
|
@listener.task(script) if @listener
|
281
283
|
begin
|
282
284
|
@build.context.evaluate_script(script)
|
283
|
-
rescue
|
285
|
+
rescue Exception
|
284
286
|
error "Error running Ruby script: #{$!}"
|
285
287
|
end
|
286
288
|
end
|
287
289
|
|
288
|
-
# Run a given task.
|
290
|
+
# Run a given bee task.
|
289
291
|
# - task: task to run as a Hash.
|
290
|
-
def
|
292
|
+
def run_bee_task(task)
|
293
|
+
require 'bee_task'
|
291
294
|
@listener.task(task) if @listener
|
292
|
-
|
293
|
-
error "Unknown task '#{name}'" if
|
294
|
-
not @build.tasks.key?(name)
|
295
|
-
parameters = task[name]
|
296
|
-
script = "#{name}(#{parameters.inspect})"
|
297
|
-
begin
|
298
|
-
@build.context.evaluate_script(script)
|
299
|
-
rescue BuildError
|
300
|
-
error "Error running task #{name}: #{$!}"
|
301
|
-
end
|
295
|
+
@build.package_manager.run_task(task)
|
302
296
|
end
|
303
|
-
|
297
|
+
|
304
298
|
end
|
305
299
|
|
306
|
-
|
307
|
-
#
|
308
|
-
#########################################################################
|
309
|
-
|
310
|
-
# Class for Ruby scripts context.
|
300
|
+
# Class for Ruby scripts context. All embedded Ruby scripts run in this
|
301
|
+
# context where build properties are defined as Ruby variables.
|
311
302
|
class Context
|
312
303
|
|
313
|
-
include BuildErrorMixin
|
304
|
+
include Bee::Util::BuildErrorMixin
|
314
305
|
|
315
306
|
# The binding of this context.
|
316
307
|
attr_reader :context_binding
|
@@ -320,26 +311,37 @@ module Bee
|
|
320
311
|
@context_binding = get_binding
|
321
312
|
end
|
322
313
|
|
323
|
-
# Set a given
|
324
|
-
# - name: the
|
325
|
-
# - value: the
|
326
|
-
|
314
|
+
# Set a given property in context.
|
315
|
+
# - name: the property name.
|
316
|
+
# - value: the property value.
|
317
|
+
# - override: tells if we can overwrite an existing value.
|
318
|
+
def set_property(name, value, overwrite=true)
|
319
|
+
error "Property '#{name}' was already defined" if
|
320
|
+
!overwrite and properties.include?(name.to_s)
|
327
321
|
begin
|
328
322
|
eval("#{name} = #{value.inspect}", @context_binding)
|
329
|
-
rescue
|
323
|
+
rescue Exception
|
330
324
|
error "Error setting property '#{name} = #{value.inspect}': #{$!}"
|
331
325
|
end
|
332
326
|
end
|
333
327
|
|
334
|
-
# Get a given
|
335
|
-
# - name: the
|
336
|
-
|
328
|
+
# Get a given property in context.
|
329
|
+
# - name: the property name.
|
330
|
+
# - strict: raise an error if given property was not set.
|
331
|
+
def get_property(name, strict=false)
|
332
|
+
error "Property '#{name}' was not set" if
|
333
|
+
strict and !properties.include?(name.to_s)
|
337
334
|
begin
|
338
335
|
eval("#{name}", @context_binding)
|
339
|
-
rescue
|
336
|
+
rescue Exception
|
340
337
|
error "Error getting property '#{name}': #{$!}"
|
341
338
|
end
|
342
339
|
end
|
340
|
+
|
341
|
+
# Return list of properties (as local variables of binding).
|
342
|
+
def properties
|
343
|
+
return eval('local_variables', @context_binding)
|
344
|
+
end
|
343
345
|
|
344
346
|
# Evaluate a script in context.
|
345
347
|
# - script: script to evaluate.
|
@@ -361,38 +363,31 @@ module Bee
|
|
361
363
|
# string: replace property references
|
362
364
|
object = object.gsub(/#\{.+?\}/) do |match|
|
363
365
|
property = match[2..-2]
|
364
|
-
value =
|
365
|
-
error
|
366
|
+
value = get_property(property)
|
367
|
+
error "Property '#{property}' was not defined" unless value
|
366
368
|
value
|
367
369
|
end
|
368
370
|
return object
|
369
371
|
when Symbol
|
370
372
|
# symbol: return property object
|
371
373
|
property = object.to_s
|
372
|
-
value =
|
373
|
-
|
374
|
-
|
374
|
+
value = get_property(property, true)
|
375
|
+
return evaluate_object(value)
|
376
|
+
when Array
|
377
|
+
# array: evaluate each element
|
378
|
+
return object.collect { |element| evaluate_object(element) }
|
379
|
+
when Hash
|
380
|
+
# hash: evaluate all keys and values
|
381
|
+
evaluated = {}
|
382
|
+
object.each_pair do |key, value|
|
383
|
+
evaluated[evaluate_object(key)] = evaluate_object(value)
|
384
|
+
end
|
385
|
+
return evaluated
|
375
386
|
else
|
376
387
|
return object
|
377
388
|
end
|
378
389
|
end
|
379
390
|
|
380
|
-
# Check a task parameters. Raise a RuntimeError with explanation message if
|
381
|
-
# a mandatory parameter is missing or an unknown parameter was found.
|
382
|
-
# - params: task parameters as a Hash.
|
383
|
-
# - description: parameters description as a Hash associating a parameter
|
384
|
-
# name with symbol :mandatory or :optional.
|
385
|
-
def check_task_parameters(params, description)
|
386
|
-
error "Parameters must be a Hash" unless params.kind_of?(Hash)
|
387
|
-
for param in description.keys
|
388
|
-
error "Missing mandatory parameter '#{param}'" unless
|
389
|
-
params[param] or description[param] == :optional
|
390
|
-
end
|
391
|
-
for param in params.keys
|
392
|
-
error "Unknown parameter '#{param}'" if not description.key?(param)
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
391
|
private
|
397
392
|
|
398
393
|
# Get a binding as script context.
|