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/lib/bee_console.rb
CHANGED
@@ -62,7 +62,7 @@ targets Targets to run (default target if omitted).'
|
|
62
62
|
| |__ ___ ___
|
63
63
|
____ | '_ \ / _ \/ _ \ _____ _____ _____ _____ _____ _____ _____ _____ _____
|
64
64
|
|____| | |_) | __/ __/ |_____|_____|_____|_____|_____|_____|_____|_____|_____|
|
65
|
-
|_.__/ \___|\___| 0.
|
65
|
+
|_.__/ \___|\___| 0.10.0 http://bee.rubyforge.org
|
66
66
|
|
67
67
|
EOF
|
68
68
|
|
@@ -180,7 +180,12 @@ EOF
|
|
180
180
|
puts "ERROR: parsing command line (type 'bee -h' for help)"
|
181
181
|
exit(EXIT_PARSING_CMDLINE)
|
182
182
|
end
|
183
|
-
|
183
|
+
begin
|
184
|
+
formatter = Formatter.new(style, color)
|
185
|
+
rescue
|
186
|
+
puts "ERROR: bad format string '#{style}'"
|
187
|
+
exit(EXIT_PARSING_CMDLINE)
|
188
|
+
end
|
184
189
|
begin
|
185
190
|
if logo
|
186
191
|
puts BEE_LOGO
|
@@ -372,7 +377,7 @@ EOF
|
|
372
377
|
help << "build: #{build.name}\n"
|
373
378
|
end
|
374
379
|
if build.extends
|
375
|
-
help << "extends: #{build.extends}\n"
|
380
|
+
help << "extends: #{build.extends.map{|b| b.name}.join(', ')}\n"
|
376
381
|
end
|
377
382
|
if build.description
|
378
383
|
help << format_description('description', build.description, 0, false)
|
@@ -434,10 +439,8 @@ EOF
|
|
434
439
|
end
|
435
440
|
description = 'No description found'
|
436
441
|
if properties
|
437
|
-
|
438
|
-
|
439
|
-
description = property['description']
|
440
|
-
end
|
442
|
+
if properties['description']
|
443
|
+
description = properties['description']
|
441
444
|
end
|
442
445
|
end
|
443
446
|
help << format_title(name)
|
@@ -475,33 +478,27 @@ EOF
|
|
475
478
|
return colorized
|
476
479
|
end
|
477
480
|
|
478
|
-
# Parse style from command line.
|
479
|
-
# nil (which means default style).
|
481
|
+
# Parse style from command line.
|
480
482
|
# - string: style to parse.
|
481
483
|
def parse_style_from_command_line(string)
|
482
484
|
return if not string
|
483
485
|
style = {}
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
not COLORS.member?(value) and not STYLES.member?(value)
|
497
|
-
end
|
498
|
-
style[key] = value
|
486
|
+
for pair in string.split(',')
|
487
|
+
key, value = pair.split(':')
|
488
|
+
key = SHORT_STYLE_KEYS[key] || key
|
489
|
+
key = key.to_sym
|
490
|
+
if key == :line_length
|
491
|
+
value = value.to_i
|
492
|
+
elsif key == :line_character
|
493
|
+
value = ' ' if not value or value.length == 0
|
494
|
+
else
|
495
|
+
value = value.to_sym
|
496
|
+
error "Unkown color or style '#{value}'" if
|
497
|
+
not COLORS.member?(value) and not STYLES.member?(value)
|
499
498
|
end
|
500
|
-
|
501
|
-
rescue
|
502
|
-
# if parsing fails, return default style (nil)
|
503
|
-
return nil
|
499
|
+
style[key] = value
|
504
500
|
end
|
501
|
+
return style
|
505
502
|
end
|
506
503
|
|
507
504
|
# Format a description.
|
data/lib/bee_context.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
# Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# Module for Bee core classes.
|
16
|
+
module Bee
|
17
|
+
|
18
|
+
# Class for Ruby scripts context. All embedded Ruby scripts run in this
|
19
|
+
# context where build properties are defined as Ruby variables.
|
20
|
+
class Context
|
21
|
+
|
22
|
+
include Bee::Util::BuildErrorMixin
|
23
|
+
|
24
|
+
# The binding of this context.
|
25
|
+
attr_reader :context_binding
|
26
|
+
|
27
|
+
# Constructor.
|
28
|
+
def initialize(properties)
|
29
|
+
@properties = properties
|
30
|
+
@context_binding = get_binding
|
31
|
+
end
|
32
|
+
|
33
|
+
# Set a given property in context.
|
34
|
+
# - name: the property name.
|
35
|
+
# - value: the property value.
|
36
|
+
# - override: tells if we can overwrite an existing value.
|
37
|
+
def set_property(name, value, overwrite=true)
|
38
|
+
error "Property '#{name}' was already defined" if
|
39
|
+
!overwrite and properties.include?(name.to_s)
|
40
|
+
begin
|
41
|
+
eval("#{name} = #{value.inspect}", @context_binding)
|
42
|
+
rescue Exception
|
43
|
+
error "Error setting property '#{name} = #{value.inspect}': #{$!}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Get a given property in context.
|
48
|
+
# - name: the property name.
|
49
|
+
# - strict: raise an error if given property was not set.
|
50
|
+
def get_property(name, strict=false)
|
51
|
+
error "Property '#{name}' was not set" if
|
52
|
+
strict and !properties.include?(name.to_s)
|
53
|
+
begin
|
54
|
+
eval("#{name}", @context_binding)
|
55
|
+
rescue NameError
|
56
|
+
error "Property '#{name}' was not set"
|
57
|
+
rescue Exception
|
58
|
+
error "Error getting property '#{name}': #{$!}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return list of properties (as local variables of binding).
|
63
|
+
def properties
|
64
|
+
return eval('local_variables', @context_binding).map{ |var| var.to_s }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Evaluate a script in context.
|
68
|
+
# - script: source of the script to evaluate.
|
69
|
+
def evaluate_script(script)
|
70
|
+
eval(script, @context_binding)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Process a given object, replacing properties references with their
|
74
|
+
# string value, symbol with their raw value. Property references have
|
75
|
+
# same form than variable references in ruby strings: '#{variable}'
|
76
|
+
# will be replaced with variable string value.
|
77
|
+
# - object: object to process.
|
78
|
+
def evaluate_object(object)
|
79
|
+
case object
|
80
|
+
when NilClass
|
81
|
+
# nil: return nil
|
82
|
+
return nil
|
83
|
+
when String
|
84
|
+
# string: replace embedded Ruby expressions
|
85
|
+
object = object.gsub(/#\{.+?\}/) do |match|
|
86
|
+
expression = match[2..-2]
|
87
|
+
begin
|
88
|
+
value = evaluate_script(expression)
|
89
|
+
rescue
|
90
|
+
error "Error evaluating expression '#{expression}': #{$!}"
|
91
|
+
end
|
92
|
+
value
|
93
|
+
end
|
94
|
+
return object
|
95
|
+
when Symbol
|
96
|
+
# symbol: return property object
|
97
|
+
property = object.to_s
|
98
|
+
begin
|
99
|
+
value = eval("#{property}", @context_binding)
|
100
|
+
rescue
|
101
|
+
error "Property '#{property}' was not set"
|
102
|
+
end
|
103
|
+
return evaluate_object(value)
|
104
|
+
when Array
|
105
|
+
# array: evaluate each element
|
106
|
+
return object.collect { |element| evaluate_object(element) }
|
107
|
+
when Hash
|
108
|
+
# hash: evaluate all keys and values
|
109
|
+
evaluated = {}
|
110
|
+
object.each_pair do |key, value|
|
111
|
+
evaluated[evaluate_object(key)] = evaluate_object(value)
|
112
|
+
end
|
113
|
+
return evaluated
|
114
|
+
else
|
115
|
+
return object
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Get a binding as script context.
|
122
|
+
def get_binding
|
123
|
+
return binding
|
124
|
+
end
|
125
|
+
|
126
|
+
# Catch missing properties
|
127
|
+
def method_missing(name, *args, &block)
|
128
|
+
stack = Thread.current[:stack]
|
129
|
+
if stack
|
130
|
+
@properties.evaluate_property(name, self)
|
131
|
+
else
|
132
|
+
raise NoMethodError.new("undefined method `#{name}'", name, args)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'bee_context'
|
16
|
+
|
17
|
+
# Module for Bee core classes.
|
18
|
+
module Bee
|
19
|
+
|
20
|
+
# Class to manage properties.
|
21
|
+
class Properties
|
22
|
+
|
23
|
+
include Bee::Util::BuildErrorMixin
|
24
|
+
|
25
|
+
# Key for properties entry.
|
26
|
+
KEY = 'properties'
|
27
|
+
|
28
|
+
# List of system properties
|
29
|
+
SYSTEM_PROPERTIES = [:base, :here]
|
30
|
+
|
31
|
+
# Properties expressions as a hash.
|
32
|
+
attr_reader :expressions
|
33
|
+
# Properties values as a hash
|
34
|
+
attr_reader :values
|
35
|
+
|
36
|
+
# Constructor.
|
37
|
+
# - build: build object.
|
38
|
+
def initialize(build)
|
39
|
+
@build = build
|
40
|
+
@expressions = {}
|
41
|
+
@values = {}
|
42
|
+
defaults
|
43
|
+
end
|
44
|
+
|
45
|
+
# Write properties. Will raise an error on duplicate definitions.
|
46
|
+
# - object: object tree resulting from YAML build file parsing or string
|
47
|
+
# for a properties file to load.
|
48
|
+
def write(object)
|
49
|
+
properties = object[Properties::KEY]
|
50
|
+
if properties.kind_of?(String)
|
51
|
+
begin
|
52
|
+
source = Bee::Util::get_file(properties, @build.base)
|
53
|
+
hash = YAML::load(source)
|
54
|
+
set_properties(hash, false)
|
55
|
+
rescue Exception
|
56
|
+
error "Error loading properties file '#{properties}': #{$!}"
|
57
|
+
end
|
58
|
+
else
|
59
|
+
set_properties(properties, false)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Overwrite properties with those passed.
|
64
|
+
# - properties: properties as a hash.
|
65
|
+
def overwrite(properties)
|
66
|
+
set_properties(properties, true)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Extend with properties of parent build.
|
70
|
+
# - properties: properties of parent build.
|
71
|
+
def extend(properties)
|
72
|
+
for name in properties.expressions.keys
|
73
|
+
@expressions[name] = properties.expressions[name] if
|
74
|
+
!@expressions.include?(name)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Evaluate properties in context.
|
79
|
+
# - context: build context where properties must be evaluated.
|
80
|
+
def evaluate(context)
|
81
|
+
for name in @expressions.keys
|
82
|
+
Thread.current[:stack] = []
|
83
|
+
evaluate_property(name, context) if !@values[name]
|
84
|
+
end
|
85
|
+
Thread.current[:stack] = nil
|
86
|
+
end
|
87
|
+
|
88
|
+
# Evaluate a given property.
|
89
|
+
# - name: the name of the property to evaluate.
|
90
|
+
# - context: the context in which the property must be evaluated.
|
91
|
+
# - stack: the stack of evaluated objects.
|
92
|
+
def evaluate_property(name, context)
|
93
|
+
stack = Thread.current[:stack]
|
94
|
+
error "Unknown property '#{name}'" if !@expressions.keys.include?(name)
|
95
|
+
error "Circular properties: #{stack.join(', ')}" if stack.include?(name)
|
96
|
+
begin
|
97
|
+
stack.push(name)
|
98
|
+
value = context.evaluate_object(@expressions[name])
|
99
|
+
stack.pop
|
100
|
+
@values[name] = value
|
101
|
+
context.set_property(name, value, true)
|
102
|
+
rescue
|
103
|
+
error "Error evaluating property '#{name}': #{$!}"
|
104
|
+
end
|
105
|
+
value
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# Set default properties.
|
111
|
+
def defaults
|
112
|
+
set(:base, @build.base, false)
|
113
|
+
set(:here, @build.here, false)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Set properties.
|
117
|
+
# - properties: properties as a hash.
|
118
|
+
# - overwrite: tells if we can overwrite existing properties.
|
119
|
+
def set_properties(properties, overwrite)
|
120
|
+
error "Properties must be a hash" if not properties.kind_of?(Hash)
|
121
|
+
for name in properties.keys
|
122
|
+
expression = properties[name]
|
123
|
+
set(name, expression, overwrite)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# Set a property.
|
128
|
+
# - name: property name (as a string or symbol).
|
129
|
+
# - expression: property expression (as a string) to be evaluated in
|
130
|
+
# context to get value.
|
131
|
+
# - overwrite: tells if we can overwrite existing properties.
|
132
|
+
def set(name, expression, overwrite)
|
133
|
+
error "Property '#{name}' collides with a function of the context" if
|
134
|
+
Bee::Context.method_defined?(name) or
|
135
|
+
Bee::Context.private_method_defined?(name)
|
136
|
+
return if expression == nil
|
137
|
+
name = name.to_sym
|
138
|
+
error "Duplicate property definition: '#{name}'" if
|
139
|
+
not overwrite and @expressions.has_key?(name)
|
140
|
+
@expressions[name] = expression
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
data/lib/bee_target.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
# Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# Module for Bee core classes.
|
16
|
+
module Bee
|
17
|
+
|
18
|
+
# Class for a target. It is built from the YAML build file and manages a
|
19
|
+
# target, in particular, tasks execution.
|
20
|
+
class Target
|
21
|
+
|
22
|
+
include Bee::Util::BuildErrorMixin
|
23
|
+
include Bee::Util::HashCheckerMixin
|
24
|
+
|
25
|
+
# Target key.
|
26
|
+
KEY = 'target'
|
27
|
+
# Target entry description.
|
28
|
+
DESCRIPTION = {
|
29
|
+
'target' => :mandatory,
|
30
|
+
'depends' => :optional,
|
31
|
+
'description' => :optional,
|
32
|
+
'script' => :optional}
|
33
|
+
|
34
|
+
# Targets for build.
|
35
|
+
attr_accessor :targets
|
36
|
+
# Name of the target.
|
37
|
+
attr_reader :name
|
38
|
+
# Target dependencies.
|
39
|
+
attr_accessor :depends
|
40
|
+
# Target description.
|
41
|
+
attr_accessor :description
|
42
|
+
# Script that run in the target.
|
43
|
+
attr_reader :script
|
44
|
+
|
45
|
+
# Constructor.
|
46
|
+
# - object: object for target, resulting from YAML parsing.
|
47
|
+
# - targets: build targets.
|
48
|
+
def initialize(object, targets)
|
49
|
+
check_hash(object, Target::DESCRIPTION)
|
50
|
+
@targets = targets
|
51
|
+
@name = object[Target::KEY]
|
52
|
+
error "Target name cannot be 'null'" if @name == nil
|
53
|
+
@depends = object['depends']||[]
|
54
|
+
@depends = Array(@depends)
|
55
|
+
@description = object['description']
|
56
|
+
@script = object['script']
|
57
|
+
@script = [@script] if @script.kind_of?(String)
|
58
|
+
@script = [] if not @script
|
59
|
+
end
|
60
|
+
|
61
|
+
# Run target.
|
62
|
+
# - dry: tells if we run in dry mode. Defaults to false.
|
63
|
+
def run(dry=false)
|
64
|
+
current_dir = Dir.pwd
|
65
|
+
begin
|
66
|
+
for depend in @depends
|
67
|
+
@targets.run_target(depend, dry)
|
68
|
+
end
|
69
|
+
@targets.build.listener.target(self) if
|
70
|
+
@targets.build.listener and @targets.is_last(self)
|
71
|
+
run_block(@script, dry)
|
72
|
+
ensure
|
73
|
+
Dir.chdir(current_dir)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
# Run a task.
|
80
|
+
# - task: the task to run.
|
81
|
+
# - dry: whether to just print.
|
82
|
+
def run_task(task, dry=false)
|
83
|
+
@targets.build.listener.task(task) if @targets.build.listener
|
84
|
+
case task
|
85
|
+
when String
|
86
|
+
# shell script
|
87
|
+
run_shell(task, dry)
|
88
|
+
when Hash
|
89
|
+
if task.keys.length > 1
|
90
|
+
# construct
|
91
|
+
run_construct(task, dry)
|
92
|
+
else
|
93
|
+
if task.key?('rb')
|
94
|
+
# ruby script
|
95
|
+
script = task['rb']
|
96
|
+
run_ruby(script, dry)
|
97
|
+
elsif task.key?('sh')
|
98
|
+
# shell script
|
99
|
+
script = task['sh']
|
100
|
+
run_shell(script, dry)
|
101
|
+
elsif task.key?('super')
|
102
|
+
# call super target
|
103
|
+
targets.call_super(self, dry)
|
104
|
+
else
|
105
|
+
# must be a task
|
106
|
+
run_bee_task(task, dry)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Run a given shell script.
|
113
|
+
# - script: the scrip to run.
|
114
|
+
def run_shell(script, dry=false)
|
115
|
+
@listener.task(script) if @listener
|
116
|
+
return if dry
|
117
|
+
evaluated_script = @targets.build.context.evaluate_object(script)
|
118
|
+
if evaluated_script != ''
|
119
|
+
system(evaluated_script)
|
120
|
+
error "Script exited with value #{$?}" if $? != 0
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Run a given shell script.
|
125
|
+
# - script: the scrip to run.
|
126
|
+
# - dry: tells if we run in dry mode.
|
127
|
+
def run_ruby(script, dry=false)
|
128
|
+
@listener.task(script) if @listener
|
129
|
+
return if dry
|
130
|
+
begin
|
131
|
+
@targets.build.context.evaluate_script(script)
|
132
|
+
rescue Exception
|
133
|
+
error "Error running Ruby script: #{$!}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Run a given bee task.
|
138
|
+
# - task: task to run as a Hash.
|
139
|
+
def run_bee_task(task, dry=false)
|
140
|
+
@listener.task(task) if @listener
|
141
|
+
return if dry
|
142
|
+
@targets.build.package_manager.run_task(task)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Run a given construct.
|
146
|
+
# - construct: construct to run as a Hash.
|
147
|
+
def run_construct(construct, dry=false)
|
148
|
+
@listener.task(construct) if @listener
|
149
|
+
return if dry
|
150
|
+
# if construct
|
151
|
+
if construct.keys.include?('if')
|
152
|
+
construct_if(construct, dry)
|
153
|
+
# while construct
|
154
|
+
elsif construct.keys.include?('while')
|
155
|
+
construct_while(construct, dry)
|
156
|
+
# for construct
|
157
|
+
elsif construct.keys.include?('for')
|
158
|
+
construct_for(construct, dry)
|
159
|
+
# try construct
|
160
|
+
elsif construct.keys.include?('try')
|
161
|
+
construct_try(construct, dry)
|
162
|
+
else
|
163
|
+
error "Unknown construct '#{construct.keys.join('-')}'"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# Run if construct.
|
168
|
+
# - task: the construct as a hash.
|
169
|
+
# - dry: tells if we run in dry mode.
|
170
|
+
def construct_if(task, dry)
|
171
|
+
# test entries
|
172
|
+
error "If-then-else construct must include 'then' entry" if
|
173
|
+
not task.keys.include?('then')
|
174
|
+
unknown_keys = task.keys - ['if', 'then', 'else']
|
175
|
+
error "If-then-else construct may only include 'if', 'then' and 'else' entries" if
|
176
|
+
unknown_keys.length > 0
|
177
|
+
error "If entry in if-then-else construct must be a string" if
|
178
|
+
not task['if'].kind_of?(String)
|
179
|
+
error "Then entry in if-then-else construct must be a list" if
|
180
|
+
not task['then'].kind_of?(Array)
|
181
|
+
error "Else entry in if-then-else construct must be a list" if
|
182
|
+
task['else'] and not task['else'].kind_of?(Array)
|
183
|
+
# evaluate condition in the build context
|
184
|
+
if evaluate(task['if'])
|
185
|
+
run_block(task['then'], dry)
|
186
|
+
else
|
187
|
+
run_block(task['else'], dry) if task['else']
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Run while construct.
|
192
|
+
# - task: the construct as a hash.
|
193
|
+
# - dry: tells if we run in dry mode.
|
194
|
+
def construct_while(task, dry)
|
195
|
+
# test entries
|
196
|
+
error "While-do construct must include 'do' entry" if
|
197
|
+
not task.keys.include?('do')
|
198
|
+
unknown_keys = task.keys - ['while', 'do']
|
199
|
+
error "While-do construct may only include 'while' and 'do' entries" if
|
200
|
+
unknown_keys.length > 0
|
201
|
+
error "While entry in while-do construct must be a string" if
|
202
|
+
not task['while'].kind_of?(String)
|
203
|
+
error "Do entry in while-do construct must be a list" if
|
204
|
+
not task['do'].kind_of?(Array)
|
205
|
+
# evaluate condition in the build context
|
206
|
+
while evaluate(task['while'])
|
207
|
+
run_block(task['do'], dry)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Run for construct.
|
212
|
+
# - task: the construct as a hash.
|
213
|
+
# - dry: tells if we run in dry mode.
|
214
|
+
def construct_for(task, dry)
|
215
|
+
# test entries
|
216
|
+
error "For-in-do construct must include 'in' and 'do' entries" if
|
217
|
+
not task.keys.include?('in') or not task.keys.include?('do')
|
218
|
+
unknown_keys = task.keys - ['for', 'in', 'do']
|
219
|
+
error "For-in-do construct may only include 'for', 'in' and 'do' entries" if
|
220
|
+
unknown_keys.length > 0
|
221
|
+
error "For entry in for-in-do construct must be a string" if
|
222
|
+
not task['for'].kind_of?(String)
|
223
|
+
error "In entry in for-in-do construct must be a list or a string" if
|
224
|
+
not task['in'].kind_of?(Enumerable) and not task['in'].kind_of?(String)
|
225
|
+
error "Do entry in for-in-do construct must be a list" if
|
226
|
+
not task['do'].kind_of?(Array)
|
227
|
+
# iterate over list
|
228
|
+
if task['in'].kind_of?(String)
|
229
|
+
enumerable = evaluate(@targets.build.context.
|
230
|
+
evaluate_object(task['in']))
|
231
|
+
else
|
232
|
+
enumerable = task['in']
|
233
|
+
end
|
234
|
+
for element in enumerable
|
235
|
+
begin
|
236
|
+
@targets.build.context.set_property(task['for'], element)
|
237
|
+
rescue
|
238
|
+
error "Error setting property '#{task['for']}'"
|
239
|
+
end
|
240
|
+
run_block(task['do'], dry)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Run try-catch construct.
|
245
|
+
# - task: the construct as a hash.
|
246
|
+
# - dry: tells if we run in dry mode.
|
247
|
+
def construct_try(task, dry)
|
248
|
+
# test entries
|
249
|
+
error "Try-catch construct must include 'catch' entry" if
|
250
|
+
not task.keys.include?('catch')
|
251
|
+
unknown_keys = task.keys - ['try', 'catch']
|
252
|
+
error "Try-catch construct may only include 'try' and 'catch' entries" if
|
253
|
+
unknown_keys.length > 0
|
254
|
+
error "Try entry in try-catch construct must be a list" if
|
255
|
+
not task['try'].kind_of?(Array)
|
256
|
+
error "Catch entry in try-catch construct must be a list" if
|
257
|
+
not task['catch'].kind_of?(Array)
|
258
|
+
# try and catch errors
|
259
|
+
begin
|
260
|
+
run_block(task['try'], dry)
|
261
|
+
rescue
|
262
|
+
@targets.build.listener.recover if @targets.build.listener
|
263
|
+
run_block(task['catch'], dry)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# Run a block, that is a list of tasks.
|
268
|
+
# - block: the block to run as a list of tasks.
|
269
|
+
# - dry: tells if we run in dry mode.
|
270
|
+
def run_block(block, dry)
|
271
|
+
for task in block
|
272
|
+
run_task(task, dry)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Evaluate a given expression and raise a BuildError if an error happens.
|
277
|
+
def evaluate(expression)
|
278
|
+
begin
|
279
|
+
return @targets.build.context.evaluate_script(expression)
|
280
|
+
rescue
|
281
|
+
error "Error evaluating expression: #{$!}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|