bee 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -1
- data/egg/application.yml +2 -2
- data/egg/application/build.yml +23 -23
- data/egg/package.yml +2 -2
- data/egg/package/build.erb +21 -21
- data/egg/package/egg.yml +2 -2
- data/egg/package/egg_build.erb +5 -5
- data/egg/script.yml +2 -2
- data/egg/script/build.yml +5 -5
- data/egg/sinatra.yml +2 -2
- data/egg/sinatra/build.yml +8 -8
- data/egg/source.yml +2 -2
- data/egg/xmlrpc.yml +2 -2
- data/egg/xmlrpc/build.yml +6 -6
- data/lib/bee.rb +44 -569
- data/lib/bee_console.rb +25 -28
- data/lib/bee_context.rb +138 -0
- data/lib/bee_properties.rb +145 -0
- data/lib/bee_target.rb +287 -0
- metadata +6 -3
data/README
CHANGED
data/egg/application.yml
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
description: "Generate a sample Ruby application project"
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
6
|
+
name: application
|
7
|
+
description: |
|
8
8
|
This script will create a sample Ruby application project. Build file
|
9
9
|
can run unit tests, generate API documentation, generate GEM archive
|
10
10
|
and build a ZIP distribution file.
|
data/egg/application/build.yml
CHANGED
@@ -5,30 +5,30 @@
|
|
5
5
|
|
6
6
|
# Build properties
|
7
7
|
- properties:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
name: "<%= name %>"
|
9
|
+
version: ~
|
10
|
+
author: ~
|
11
|
+
years: ~
|
12
|
+
platform: "Gem::Platform::RUBY"
|
13
|
+
summary: ~
|
14
|
+
email: ~
|
15
|
+
homepage: ~
|
16
|
+
rubyforge: ~
|
17
|
+
dependencies:
|
18
18
|
bee: [">= 0.7.0"]
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
19
|
+
lib_dir: "lib"
|
20
|
+
test_dir: "test"
|
21
|
+
build_dir: "build"
|
22
|
+
api_dir: "#{build_dir}/api"
|
23
|
+
gem_spec: "gem.spec"
|
24
|
+
gem_spec_erb: "gem.spec.erb"
|
25
|
+
gem_package: "#{name}-#{version}.gem"
|
26
|
+
rdoc_files: ["#{lib_dir}/*.rb"]
|
27
|
+
zip_excludes: ["**/CVS", "**/.DS_Store", "**/*~"]
|
28
|
+
zip_prefix: "#{name}-#{version}"
|
29
|
+
zip_archive: "#{build_dir}/#{name}-#{version}.zip"
|
30
|
+
clean_dirs: [:build_dir]
|
31
|
+
clean_files: ["**/*~", "**/.#*", "**/.DS_Store", :gem_spec]
|
32
32
|
|
33
33
|
# Build targets
|
34
34
|
- target: test
|
data/egg/package.yml
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
description: "Generate a bee package project"
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
6
|
+
project_name: bee_hello
|
7
|
+
description: |
|
8
8
|
This script will create a project for a bee package with sample task (in
|
9
9
|
'lib' directory) and template (in 'egg' directory). A unit test for the
|
10
10
|
task is generated in 'test' directory. Generated build file has a target
|
data/egg/package/build.erb
CHANGED
@@ -6,28 +6,28 @@
|
|
6
6
|
|
7
7
|
# Build properties
|
8
8
|
- properties:
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
name: <%= project_name %>
|
10
|
+
version: 0.0.1
|
11
|
+
author: ~
|
12
|
+
years: ~
|
13
|
+
platform: "Gem::Platform::RUBY"
|
14
|
+
summary: ~
|
15
|
+
email: ~
|
16
|
+
homepage: "http://<%= project_name %>.rubyforge.org"
|
17
|
+
rubyforge: ~
|
18
|
+
dependencies:
|
19
19
|
"bee": [">= 0.5.0"]
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
20
|
+
lib_dir: "lib"
|
21
|
+
test_dir: "test"
|
22
|
+
build_dir: "build"
|
23
|
+
readme_erb: "readme.erb"
|
24
|
+
readme_file: "#{build_dir}/README"
|
25
|
+
license_file: "LICENSE"
|
26
|
+
gem_spec_erb: "gem.spec.erb"
|
27
|
+
gem_spec: "#{build_dir}/gem.spec"
|
28
|
+
gem_package: "#{name}-#{version}.gem"
|
29
|
+
clean_dirs: :build_dir
|
30
|
+
clean_files: ""
|
31
31
|
|
32
32
|
# Build targets
|
33
33
|
- target: test
|
data/egg/package/egg.yml
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
description: "Generate a project for a Ruby script"
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
6
|
+
project_name: hello
|
7
|
+
description: |
|
8
8
|
This script will create a project for a Ruby script that might be
|
9
9
|
distributed as a gem. Generated build file has a single target gem
|
10
10
|
to generate the distribution gem.
|
data/egg/package/egg_build.erb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
default: all
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
name: <%= project_name %>
|
7
|
+
version: 0.0.1
|
8
|
+
build: build
|
9
|
+
gem_spec: "#{build}/gem_spec"
|
10
|
+
gem_erb: |
|
11
11
|
require 'rubygems'
|
12
12
|
SPEC = Gem::Specification.new do |spec|
|
13
13
|
spec.name = '<%= name %>'
|
data/egg/script.yml
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
description: "Generate a sample Ruby script project"
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
6
|
+
name: script
|
7
|
+
description: This script will generate a sample Ruby script project.
|
8
8
|
|
9
9
|
- target: welcome
|
10
10
|
description: "Print information message"
|
data/egg/script/build.yml
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
# Build properties
|
7
7
|
- properties:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
name: "<%= name %>"
|
9
|
+
version: "0.0.0"
|
10
|
+
build: "build"
|
11
|
+
clean_dirs: [:build]
|
12
|
+
clean_files: ["**/*~", "**/.#*", "**/.DS_Store"]
|
13
13
|
|
14
14
|
# Build targets
|
15
15
|
- target: zip
|
data/egg/sinatra.yml
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
description: "Generate a Sinatra project"
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
6
|
+
name: sinatra
|
7
|
+
description: |
|
8
8
|
This script will create a Sinatra project. Generated build file has a
|
9
9
|
target 'run' to run the server, 'zip' to generate a distribution archive
|
10
10
|
and 'clean' to delete generated files.
|
data/egg/sinatra/build.yml
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
default: all
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
name: "<%= name %>"
|
7
|
+
version: "0.0.0"
|
8
|
+
build: "build"
|
9
|
+
zip_prefix: "#{name}-#{version}"
|
10
|
+
zip_file: "#{build}/#{zip_prefix}.zip"
|
11
|
+
url: "http://localhost:4567/hello"
|
12
|
+
clean_dirs: [:build]
|
13
|
+
clean_files: ["**/*~", "**/.#*", "**/.DS_Store"]
|
14
14
|
|
15
15
|
- target: run
|
16
16
|
description: Run server
|
data/egg/source.yml
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
description: Generate a sample Ruby source file
|
4
4
|
|
5
5
|
- properties:
|
6
|
-
|
7
|
-
|
6
|
+
name: source.rb
|
7
|
+
description: This script will generate a sample Ruby source file.
|
8
8
|
|
9
9
|
- target: welcome
|
10
10
|
description: Print information message
|
data/egg/xmlrpc.yml
CHANGED
data/egg/xmlrpc/build.yml
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
# Build properties
|
7
7
|
- properties:
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
name: <%= project_name %>
|
9
|
+
version: "0.0.0"
|
10
|
+
build: "build"
|
11
|
+
zip: "#{build}/#{name}-#{version}.zip"
|
12
|
+
clean_dirs: [:build]
|
13
|
+
clean_files: ["**/*~", "**/.#*", "**/.DS_Store"]
|
14
14
|
|
15
15
|
# Build targets
|
16
16
|
- target: server
|
data/lib/bee.rb
CHANGED
@@ -15,7 +15,10 @@
|
|
15
15
|
require 'rubygems'
|
16
16
|
require 'yaml'
|
17
17
|
require 'bee_task'
|
18
|
+
require 'bee_target'
|
18
19
|
require 'bee_util'
|
20
|
+
require 'bee_context'
|
21
|
+
require 'bee_properties'
|
19
22
|
|
20
23
|
# Module for Bee core classes.
|
21
24
|
module Bee
|
@@ -36,7 +39,6 @@ module Bee
|
|
36
39
|
'description' => :optional,
|
37
40
|
'context' => :optional,
|
38
41
|
'extends' => :optional,
|
39
|
-
'includes' => :optional,
|
40
42
|
'abstract' => :optional
|
41
43
|
}
|
42
44
|
|
@@ -50,8 +52,6 @@ module Bee
|
|
50
52
|
attr_reader :name
|
51
53
|
# Parent build.
|
52
54
|
attr_reader :extends
|
53
|
-
# Included builds
|
54
|
-
attr_reader :includes
|
55
55
|
# Abstractness.
|
56
56
|
attr_reader :abstract
|
57
57
|
# Default target, specified with default entry or fist target in build file.
|
@@ -108,8 +108,8 @@ module Bee
|
|
108
108
|
@file = file
|
109
109
|
@base = get_base(@file)
|
110
110
|
@here = here
|
111
|
-
@context = Context.new
|
112
111
|
@properties = Properties.new(self)
|
112
|
+
@context = Context.new(@properties)
|
113
113
|
@properties.evaluate(@context)
|
114
114
|
@targets = Targets.new(self)
|
115
115
|
parse(object)
|
@@ -172,16 +172,11 @@ module Bee
|
|
172
172
|
error "Unknown entry:\n#{YAML::dump(entry)}"
|
173
173
|
end
|
174
174
|
end
|
175
|
-
# manage
|
176
|
-
if @
|
177
|
-
@
|
178
|
-
|
179
|
-
|
180
|
-
# manage included builds
|
181
|
-
if @included
|
182
|
-
for include in @included.reverse
|
183
|
-
@properties.include(include.properties)
|
184
|
-
@targets.include(include.targets)
|
175
|
+
# manage extended builds
|
176
|
+
if @extends
|
177
|
+
for parent in @extends
|
178
|
+
@properties.extend(parent.properties)
|
179
|
+
@targets.extend(parent.targets)
|
185
180
|
end
|
186
181
|
end
|
187
182
|
end
|
@@ -199,33 +194,46 @@ module Bee
|
|
199
194
|
@default = entry['default']
|
200
195
|
@targets.default = @default
|
201
196
|
@description = entry['description']
|
202
|
-
@extends = entry['extends']
|
203
|
-
@includes = Array(entry['includes'])
|
204
197
|
@abstract = entry['abstract']
|
205
|
-
# load
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
error "Error loading parent build file '#{@extends}': #{$!}"
|
212
|
-
end
|
213
|
-
@default = @default || @parent.default
|
214
|
-
@targets.default = @default
|
215
|
-
@description = @description || @parent.description
|
216
|
-
end
|
217
|
-
# load included build files if any
|
218
|
-
if @includes
|
219
|
-
@included = []
|
220
|
-
for include in @includes
|
221
|
-
absolute_path = Bee::Util::absolute_path(include, @base)
|
198
|
+
# load parents build if any
|
199
|
+
parents = Array(entry['extends'])
|
200
|
+
if parents.length > 0
|
201
|
+
@extends = []
|
202
|
+
for extended in parents
|
203
|
+
absolute_path = Bee::Util::absolute_path(extended, @base)
|
222
204
|
begin
|
223
|
-
@
|
205
|
+
@extends << Bee::Build::load(absolute_path)
|
224
206
|
rescue Exception
|
225
|
-
error "Error loading
|
207
|
+
error "Error loading parent build file '#{extended}': #{$!}"
|
226
208
|
end
|
227
209
|
end
|
228
210
|
end
|
211
|
+
# check that there are no property and target collisions in parents
|
212
|
+
if @extends
|
213
|
+
properties = []
|
214
|
+
collisions = []
|
215
|
+
for parent in @extends
|
216
|
+
parent_properties = parent.properties.expressions.keys
|
217
|
+
collisions += properties & parent_properties
|
218
|
+
properties += parent_properties
|
219
|
+
end
|
220
|
+
collisions = collisions - Properties::SYSTEM_PROPERTIES
|
221
|
+
collisions = collisions.uniq.map { |e| e.to_s }.sort
|
222
|
+
if collisions.length > 0
|
223
|
+
error "Properties in parents are colliding: #{collisions.join(', ')}"
|
224
|
+
end
|
225
|
+
targets = []
|
226
|
+
collisions = []
|
227
|
+
for parent in @extends
|
228
|
+
parent_targets = parent.targets.hash.keys
|
229
|
+
collisions += targets & parent_targets
|
230
|
+
targets += parent_targets
|
231
|
+
end
|
232
|
+
collisions = collisions.uniq.map { |e| e.to_s }.sort
|
233
|
+
if collisions.length > 0
|
234
|
+
error "Targets in parents are colliding: #{collisions.join(', ')}"
|
235
|
+
end
|
236
|
+
end
|
229
237
|
# load context files if any
|
230
238
|
context = entry['context']
|
231
239
|
if context
|
@@ -258,146 +266,6 @@ module Bee
|
|
258
266
|
|
259
267
|
end
|
260
268
|
|
261
|
-
# Class to manage properties.
|
262
|
-
class Properties
|
263
|
-
|
264
|
-
include Bee::Util::BuildErrorMixin
|
265
|
-
|
266
|
-
# Key for properties entry.
|
267
|
-
KEY = 'properties'
|
268
|
-
|
269
|
-
# List of system properties
|
270
|
-
SYSTEM_PROPERTIES = [:base, :here]
|
271
|
-
|
272
|
-
# List of properties in order of evaluation.
|
273
|
-
attr_reader :list
|
274
|
-
# Hash of properties by name.
|
275
|
-
attr_reader :hash
|
276
|
-
|
277
|
-
# Constructor.
|
278
|
-
# - build: build object.
|
279
|
-
def initialize(build)
|
280
|
-
@list = []
|
281
|
-
@hash = {}
|
282
|
-
@build = build
|
283
|
-
defaults
|
284
|
-
end
|
285
|
-
|
286
|
-
# Write properties. Will raise an error on duplicate definitions.
|
287
|
-
# - object: object tree resulting from YAML build file parsing or string
|
288
|
-
# for a properties file to load.
|
289
|
-
def write(object)
|
290
|
-
properties = object[Properties::KEY]
|
291
|
-
if properties.kind_of?(String)
|
292
|
-
begin
|
293
|
-
source = Bee::Util::get_file(properties, @build.base)
|
294
|
-
list = YAML::load(source)
|
295
|
-
set_properties(list, false)
|
296
|
-
rescue Exception
|
297
|
-
error "Error loading properties file '#{properties}': #{$!}"
|
298
|
-
end
|
299
|
-
else
|
300
|
-
set_properties(properties, false)
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
# Overwrite properties. Will raise an error if properties don't already
|
305
|
-
# exist.
|
306
|
-
# - object: object tree resulting from YAML build file parsing.
|
307
|
-
def overwrite(object)
|
308
|
-
set_properties(object, true)
|
309
|
-
end
|
310
|
-
|
311
|
-
# Extend with properties of parent build.
|
312
|
-
# - properties: properties of parent build.
|
313
|
-
def extend(properties)
|
314
|
-
current_list = @list
|
315
|
-
current_hash = @hash
|
316
|
-
@list = properties.list
|
317
|
-
@hash = properties.hash
|
318
|
-
index = 0
|
319
|
-
0.upto(current_list.length - 1) do |current|
|
320
|
-
name = current_list[current]
|
321
|
-
pos = @list.index(name)
|
322
|
-
if pos
|
323
|
-
sub = current_list[index .. current]
|
324
|
-
@list[pos .. pos] = sub
|
325
|
-
for name in sub
|
326
|
-
@hash[name] = current_hash[name]
|
327
|
-
end
|
328
|
-
index = current + 1
|
329
|
-
end
|
330
|
-
end
|
331
|
-
tail = current_list[index .. current_list.length() - 1]
|
332
|
-
@list += tail
|
333
|
-
for name in tail
|
334
|
-
@hash[name] = current_hash[name]
|
335
|
-
end
|
336
|
-
end
|
337
|
-
|
338
|
-
# Include properties of included build.
|
339
|
-
# - properties: properties of parent build.
|
340
|
-
def include(properties)
|
341
|
-
extend(properties)
|
342
|
-
end
|
343
|
-
|
344
|
-
# Evaluate properties in context.
|
345
|
-
# - context: build context where properties must be evaluated.
|
346
|
-
def evaluate(context)
|
347
|
-
for name in @list
|
348
|
-
begin
|
349
|
-
value = context.evaluate_object(@hash[name])
|
350
|
-
rescue Bee::Util::BuildError
|
351
|
-
error "Error evaluating property '#{name}': #{$!}"
|
352
|
-
end
|
353
|
-
context.set_property(name, value, true)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
private
|
358
|
-
|
359
|
-
# Set default properties.
|
360
|
-
def defaults
|
361
|
-
set(:base, @build.base, false)
|
362
|
-
set(:here, @build.here, false)
|
363
|
-
end
|
364
|
-
|
365
|
-
# Set properties.
|
366
|
-
# - properties: properties as a list of hash if overwrite = false
|
367
|
-
# or a hash if overwrite = true.
|
368
|
-
# - overwrite: tells if we can overwrite existing properties.
|
369
|
-
def set_properties(properties, overwrite)
|
370
|
-
if overwrite
|
371
|
-
raise "Properties must be a hash" if not properties.kind_of?(Hash)
|
372
|
-
for name in properties.keys
|
373
|
-
expression = properties[name]
|
374
|
-
set(name, expression, overwrite)
|
375
|
-
end
|
376
|
-
else
|
377
|
-
raise "Properties must be a list" if not properties.kind_of?(Array)
|
378
|
-
for property in properties
|
379
|
-
name = property.keys[0]
|
380
|
-
expression = property[name]
|
381
|
-
set(name, expression, overwrite)
|
382
|
-
end
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
# Set a property.
|
387
|
-
# - name: property name (as a string or symbol).
|
388
|
-
# - expression: property expression (as a string) to be evaluated in
|
389
|
-
# context to get value.
|
390
|
-
# - overwrite: tells if we can overwrite existing properties.
|
391
|
-
def set(name, expression, overwrite)
|
392
|
-
name = name.to_sym
|
393
|
-
error "Duplicate property definition: '#{name}'" if
|
394
|
-
not overwrite and @hash.has_key?(name)
|
395
|
-
@list << name
|
396
|
-
@hash[name] = expression
|
397
|
-
end
|
398
|
-
|
399
|
-
end
|
400
|
-
|
401
269
|
# Class to manage targets in a build.
|
402
270
|
class Targets
|
403
271
|
|
@@ -470,25 +338,6 @@ module Bee
|
|
470
338
|
@default = @default || parent.default
|
471
339
|
end
|
472
340
|
|
473
|
-
# Include included build file targets.
|
474
|
-
# - included: included build file targets.
|
475
|
-
def include(included)
|
476
|
-
# set appropriate targets for targets of parent
|
477
|
-
for targets in included.hash.values
|
478
|
-
for target in targets
|
479
|
-
target.targets = self
|
480
|
-
end
|
481
|
-
end
|
482
|
-
# look for targets already defined
|
483
|
-
duplicates = @hash.keys & included.hash.keys
|
484
|
-
error "Included target(s) '#{duplicates.join('\', \'')}' already defined" if
|
485
|
-
duplicates.length > 0
|
486
|
-
# insert included targets
|
487
|
-
for name in included.hash.keys
|
488
|
-
@hash[name] = included.hash[name]
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
341
|
# Run targets.
|
493
342
|
# - targets: list of target names to run.
|
494
343
|
def run(targets, dry)
|
@@ -543,380 +392,6 @@ module Bee
|
|
543
392
|
return description
|
544
393
|
end
|
545
394
|
|
546
|
-
end
|
547
|
-
|
548
|
-
# Class for a target. It is built from the YAML build file and manages a
|
549
|
-
# target, in particular, tasks execution.
|
550
|
-
class Target
|
551
|
-
|
552
|
-
include Bee::Util::BuildErrorMixin
|
553
|
-
include Bee::Util::HashCheckerMixin
|
554
|
-
|
555
|
-
# Target key.
|
556
|
-
KEY = 'target'
|
557
|
-
# Target entry description.
|
558
|
-
DESCRIPTION = {
|
559
|
-
'target' => :mandatory,
|
560
|
-
'depends' => :optional,
|
561
|
-
'description' => :optional,
|
562
|
-
'script' => :optional}
|
563
|
-
|
564
|
-
# Targets for build.
|
565
|
-
attr_accessor :targets
|
566
|
-
# Name of the target.
|
567
|
-
attr_reader :name
|
568
|
-
# Target dependencies.
|
569
|
-
attr_accessor :depends
|
570
|
-
# Target description.
|
571
|
-
attr_accessor :description
|
572
|
-
# Script that run in the target.
|
573
|
-
attr_reader :script
|
574
|
-
|
575
|
-
# Constructor.
|
576
|
-
# - object: object for target, resulting from YAML parsing.
|
577
|
-
# - targets: build targets.
|
578
|
-
def initialize(object, targets)
|
579
|
-
check_hash(object, Target::DESCRIPTION)
|
580
|
-
@targets = targets
|
581
|
-
@name = object[Target::KEY]
|
582
|
-
error "Target name cannot be 'null'" if @name == nil
|
583
|
-
@depends = object['depends']||[]
|
584
|
-
@depends = Array(@depends)
|
585
|
-
@description = object['description']
|
586
|
-
@script = object['script']
|
587
|
-
@script = [@script] if @script.kind_of?(String)
|
588
|
-
@script = [] if not @script
|
589
|
-
end
|
590
|
-
|
591
|
-
# Run target.
|
592
|
-
# - dry: tells if we run in dry mode. Defaults to false.
|
593
|
-
def run(dry=false)
|
594
|
-
current_dir = Dir.pwd
|
595
|
-
begin
|
596
|
-
for depend in @depends
|
597
|
-
@targets.run_target(depend, dry)
|
598
|
-
end
|
599
|
-
@targets.build.listener.target(self) if
|
600
|
-
@targets.build.listener and @targets.is_last(self)
|
601
|
-
run_block(@script, dry)
|
602
|
-
ensure
|
603
|
-
Dir.chdir(current_dir)
|
604
|
-
end
|
605
|
-
end
|
606
|
-
|
607
|
-
private
|
608
|
-
|
609
|
-
# Run a task.
|
610
|
-
# - task: the task to run.
|
611
|
-
# - dry: whether to just print.
|
612
|
-
def run_task(task, dry=false)
|
613
|
-
@targets.build.listener.task(task) if @targets.build.listener
|
614
|
-
case task
|
615
|
-
when String
|
616
|
-
# shell script
|
617
|
-
run_shell(task, dry)
|
618
|
-
when Hash
|
619
|
-
if task.keys.length > 1
|
620
|
-
# construct
|
621
|
-
run_construct(task, dry)
|
622
|
-
else
|
623
|
-
if task.key?('rb')
|
624
|
-
# ruby script
|
625
|
-
script = task['rb']
|
626
|
-
run_ruby(script, dry)
|
627
|
-
elsif task.key?('sh')
|
628
|
-
# shell script
|
629
|
-
script = task['sh']
|
630
|
-
run_shell(script, dry)
|
631
|
-
elsif task.key?('super')
|
632
|
-
# call super target
|
633
|
-
targets.call_super(self, dry)
|
634
|
-
else
|
635
|
-
# must be a task
|
636
|
-
run_bee_task(task, dry)
|
637
|
-
end
|
638
|
-
end
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
# Run a given shell script.
|
643
|
-
# - script: the scrip to run.
|
644
|
-
def run_shell(script, dry=false)
|
645
|
-
@listener.task(script) if @listener
|
646
|
-
return if dry
|
647
|
-
evaluated_script = @targets.build.context.evaluate_object(script)
|
648
|
-
if evaluated_script != ''
|
649
|
-
system(evaluated_script)
|
650
|
-
error "Script exited with value #{$?}" if $? != 0
|
651
|
-
end
|
652
|
-
end
|
653
|
-
|
654
|
-
# Run a given shell script.
|
655
|
-
# - script: the scrip to run.
|
656
|
-
# - dry: tells if we run in dry mode.
|
657
|
-
def run_ruby(script, dry=false)
|
658
|
-
@listener.task(script) if @listener
|
659
|
-
return if dry
|
660
|
-
begin
|
661
|
-
@targets.build.context.evaluate_script(script)
|
662
|
-
rescue Exception
|
663
|
-
error "Error running Ruby script: #{$!}"
|
664
|
-
end
|
665
|
-
end
|
666
|
-
|
667
|
-
# Run a given bee task.
|
668
|
-
# - task: task to run as a Hash.
|
669
|
-
def run_bee_task(task, dry=false)
|
670
|
-
@listener.task(task) if @listener
|
671
|
-
return if dry
|
672
|
-
@targets.build.package_manager.run_task(task)
|
673
|
-
end
|
674
|
-
|
675
|
-
# Run a given construct.
|
676
|
-
# - construct: construct to run as a Hash.
|
677
|
-
def run_construct(construct, dry=false)
|
678
|
-
@listener.task(construct) if @listener
|
679
|
-
return if dry
|
680
|
-
# if construct
|
681
|
-
if construct.keys.include?('if')
|
682
|
-
construct_if(construct, dry)
|
683
|
-
# while construct
|
684
|
-
elsif construct.keys.include?('while')
|
685
|
-
construct_while(construct, dry)
|
686
|
-
# for construct
|
687
|
-
elsif construct.keys.include?('for')
|
688
|
-
construct_for(construct, dry)
|
689
|
-
# try construct
|
690
|
-
elsif construct.keys.include?('try')
|
691
|
-
construct_try(construct, dry)
|
692
|
-
else
|
693
|
-
error "Unknown construct '#{construct.keys.join('-')}'"
|
694
|
-
end
|
695
|
-
end
|
696
|
-
|
697
|
-
# Run if construct.
|
698
|
-
# - task: the construct as a hash.
|
699
|
-
# - dry: tells if we run in dry mode.
|
700
|
-
def construct_if(task, dry)
|
701
|
-
# test entries
|
702
|
-
error "If-then-else construct must include 'then' entry" if
|
703
|
-
not task.keys.include?('then')
|
704
|
-
unknown_keys = task.keys - ['if', 'then', 'else']
|
705
|
-
error "If-then-else construct may only include 'if', 'then' and 'else' entries" if
|
706
|
-
unknown_keys.length > 0
|
707
|
-
error "If entry in if-then-else construct must be a string" if
|
708
|
-
not task['if'].kind_of?(String)
|
709
|
-
error "Then entry in if-then-else construct must be a list" if
|
710
|
-
not task['then'].kind_of?(Array)
|
711
|
-
error "Else entry in if-then-else construct must be a list" if
|
712
|
-
task['else'] and not task['else'].kind_of?(Array)
|
713
|
-
# evaluate condition in the build context
|
714
|
-
if evaluate(task['if'])
|
715
|
-
run_block(task['then'], dry)
|
716
|
-
else
|
717
|
-
run_block(task['else'], dry) if task['else']
|
718
|
-
end
|
719
|
-
end
|
720
|
-
|
721
|
-
# Run while construct.
|
722
|
-
# - task: the construct as a hash.
|
723
|
-
# - dry: tells if we run in dry mode.
|
724
|
-
def construct_while(task, dry)
|
725
|
-
# test entries
|
726
|
-
error "While-do construct must include 'do' entry" if
|
727
|
-
not task.keys.include?('do')
|
728
|
-
unknown_keys = task.keys - ['while', 'do']
|
729
|
-
error "While-do construct may only include 'while' and 'do' entries" if
|
730
|
-
unknown_keys.length > 0
|
731
|
-
error "While entry in while-do construct must be a string" if
|
732
|
-
not task['while'].kind_of?(String)
|
733
|
-
error "Do entry in while-do construct must be a list" if
|
734
|
-
not task['do'].kind_of?(Array)
|
735
|
-
# evaluate condition in the build context
|
736
|
-
while evaluate(task['while'])
|
737
|
-
run_block(task['do'], dry)
|
738
|
-
end
|
739
|
-
end
|
740
|
-
|
741
|
-
# Run for construct.
|
742
|
-
# - task: the construct as a hash.
|
743
|
-
# - dry: tells if we run in dry mode.
|
744
|
-
def construct_for(task, dry)
|
745
|
-
# test entries
|
746
|
-
error "For-in-do construct must include 'in' and 'do' entries" if
|
747
|
-
not task.keys.include?('in') or not task.keys.include?('do')
|
748
|
-
unknown_keys = task.keys - ['for', 'in', 'do']
|
749
|
-
error "For-in-do construct may only include 'for', 'in' and 'do' entries" if
|
750
|
-
unknown_keys.length > 0
|
751
|
-
error "For entry in for-in-do construct must be a string" if
|
752
|
-
not task['for'].kind_of?(String)
|
753
|
-
error "In entry in for-in-do construct must be a list or a string" if
|
754
|
-
not task['in'].kind_of?(Enumerable) and not task['in'].kind_of?(String)
|
755
|
-
error "Do entry in for-in-do construct must be a list" if
|
756
|
-
not task['do'].kind_of?(Array)
|
757
|
-
# iterate over list
|
758
|
-
if task['in'].kind_of?(String)
|
759
|
-
enumerable = evaluate(@targets.build.context.
|
760
|
-
evaluate_object(task['in']))
|
761
|
-
else
|
762
|
-
enumerable = task['in']
|
763
|
-
end
|
764
|
-
for element in enumerable
|
765
|
-
begin
|
766
|
-
@targets.build.context.set_property(task['for'], element)
|
767
|
-
rescue
|
768
|
-
error "Error setting property '#{task['for']}'"
|
769
|
-
end
|
770
|
-
run_block(task['do'], dry)
|
771
|
-
end
|
772
|
-
end
|
773
|
-
|
774
|
-
# Run try-catch construct.
|
775
|
-
# - task: the construct as a hash.
|
776
|
-
# - dry: tells if we run in dry mode.
|
777
|
-
def construct_try(task, dry)
|
778
|
-
# test entries
|
779
|
-
error "Try-catch construct must include 'catch' entry" if
|
780
|
-
not task.keys.include?('catch')
|
781
|
-
unknown_keys = task.keys - ['try', 'catch']
|
782
|
-
error "Try-catch construct may only include 'try' and 'catch' entries" if
|
783
|
-
unknown_keys.length > 0
|
784
|
-
error "Try entry in try-catch construct must be a list" if
|
785
|
-
not task['try'].kind_of?(Array)
|
786
|
-
error "Catch entry in try-catch construct must be a list" if
|
787
|
-
not task['catch'].kind_of?(Array)
|
788
|
-
# try and catch errors
|
789
|
-
begin
|
790
|
-
run_block(task['try'], dry)
|
791
|
-
rescue
|
792
|
-
@targets.build.listener.recover if @targets.build.listener
|
793
|
-
run_block(task['catch'], dry)
|
794
|
-
end
|
795
|
-
end
|
796
|
-
|
797
|
-
# Run a block, that is a list of tasks.
|
798
|
-
# - block: the block to run as a list of tasks.
|
799
|
-
# - dry: tells if we run in dry mode.
|
800
|
-
def run_block(block, dry)
|
801
|
-
for task in block
|
802
|
-
run_task(task, dry)
|
803
|
-
end
|
804
|
-
end
|
805
|
-
|
806
|
-
# Evaluate a given expression and raise a BuildError if an error happens.
|
807
|
-
def evaluate(expression)
|
808
|
-
begin
|
809
|
-
return @targets.build.context.evaluate_script(expression)
|
810
|
-
rescue
|
811
|
-
error "Error evaluating expression: #{$!}"
|
812
|
-
end
|
813
|
-
end
|
814
|
-
|
815
|
-
end
|
816
|
-
|
817
|
-
# Class for Ruby scripts context. All embedded Ruby scripts run in this
|
818
|
-
# context where build properties are defined as Ruby variables.
|
819
|
-
class Context
|
820
|
-
|
821
|
-
include Bee::Util::BuildErrorMixin
|
822
|
-
|
823
|
-
# The binding of this context.
|
824
|
-
attr_reader :context_binding
|
825
|
-
|
826
|
-
# Constructor.
|
827
|
-
def initialize
|
828
|
-
@context_binding = get_binding
|
829
|
-
end
|
830
|
-
|
831
|
-
# Set a given property in context.
|
832
|
-
# - name: the property name.
|
833
|
-
# - value: the property value.
|
834
|
-
# - override: tells if we can overwrite an existing value.
|
835
|
-
def set_property(name, value, overwrite=true)
|
836
|
-
error "Property '#{name}' was already defined" if
|
837
|
-
!overwrite and properties.include?(name.to_s)
|
838
|
-
begin
|
839
|
-
eval("#{name} = #{value.inspect}", @context_binding)
|
840
|
-
rescue Exception
|
841
|
-
error "Error setting property '#{name} = #{value.inspect}': #{$!}"
|
842
|
-
end
|
843
|
-
end
|
844
|
-
|
845
|
-
# Get a given property in context.
|
846
|
-
# - name: the property name.
|
847
|
-
# - strict: raise an error if given property was not set.
|
848
|
-
def get_property(name, strict=false)
|
849
|
-
error "Property '#{name}' was not set" if
|
850
|
-
strict and !properties.include?(name.to_s)
|
851
|
-
begin
|
852
|
-
eval("#{name}", @context_binding)
|
853
|
-
rescue NameError
|
854
|
-
error "Property '#{name}' was not set"
|
855
|
-
rescue Exception
|
856
|
-
error "Error getting property '#{name}': #{$!}"
|
857
|
-
end
|
858
|
-
end
|
859
|
-
|
860
|
-
# Return list of properties (as local variables of binding).
|
861
|
-
def properties
|
862
|
-
return eval('local_variables', @context_binding).map{ |var| var.to_s }
|
863
|
-
end
|
864
|
-
|
865
|
-
# Evaluate a script in context.
|
866
|
-
# - script: source of the script to evaluate.
|
867
|
-
def evaluate_script(script)
|
868
|
-
eval(script, @context_binding)
|
869
|
-
end
|
870
|
-
|
871
|
-
# Process a given object, replacing properties references with their
|
872
|
-
# string value, symbol with their raw value. Property references have
|
873
|
-
# same form than variable references in ruby strings: '#{variable}'
|
874
|
-
# will be replaced with variable string value.
|
875
|
-
# - object: object to process.
|
876
|
-
def evaluate_object(object)
|
877
|
-
case object
|
878
|
-
when NilClass
|
879
|
-
# nil: return nil
|
880
|
-
return nil
|
881
|
-
when String
|
882
|
-
# string: replace embedded Ruby expressions
|
883
|
-
object = object.gsub(/#\{.+?\}/) do |match|
|
884
|
-
expression = match[2..-2]
|
885
|
-
begin
|
886
|
-
value = evaluate_script(expression)
|
887
|
-
rescue
|
888
|
-
error "Error evaluating expression '#{expression}': #{$!}"
|
889
|
-
end
|
890
|
-
value
|
891
|
-
end
|
892
|
-
return object
|
893
|
-
when Symbol
|
894
|
-
# symbol: return property object
|
895
|
-
property = object.to_s
|
896
|
-
value = get_property(property, true)
|
897
|
-
return evaluate_object(value)
|
898
|
-
when Array
|
899
|
-
# array: evaluate each element
|
900
|
-
return object.collect { |element| evaluate_object(element) }
|
901
|
-
when Hash
|
902
|
-
# hash: evaluate all keys and values
|
903
|
-
evaluated = {}
|
904
|
-
object.each_pair do |key, value|
|
905
|
-
evaluated[evaluate_object(key)] = evaluate_object(value)
|
906
|
-
end
|
907
|
-
return evaluated
|
908
|
-
else
|
909
|
-
return object
|
910
|
-
end
|
911
|
-
end
|
912
|
-
|
913
|
-
private
|
914
|
-
|
915
|
-
# Get a binding as script context.
|
916
|
-
def get_binding
|
917
|
-
return binding
|
918
|
-
end
|
919
|
-
|
920
|
-
end
|
395
|
+
end
|
921
396
|
|
922
397
|
end
|