bee 0.10.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- # Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
1
+ # Copyright 2006-2011 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,44 +12,60 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- # Module for Bee core classes.
15
+ require 'rubygems'
16
+ require 'bee_util'
17
+ require 'bee_properties'
18
+
16
19
  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
+
21
+ # Class for build context where properties live as local variables and where
22
+ # all scripts (from context or in Ruby tasks) are evaluated.
20
23
  class Context
21
24
 
22
25
  include Bee::Util::BuildErrorMixin
23
-
24
- # The binding of this context.
26
+
27
+ # The context binding
25
28
  attr_reader :context_binding
26
-
29
+
27
30
  # Constructor.
28
- def initialize(properties)
29
- @properties = properties
31
+ # - properties: properties as a hash that gives expression for a given
32
+ # property.
33
+ # - scripts: list of script files to run in context.
34
+ def initialize(properties={}, scripts=[])
30
35
  @context_binding = get_binding
36
+ @properties = properties
37
+ @scripts = scripts
31
38
  end
32
-
39
+
40
+ # Evaluate properties and scripts in the context. Should run while running
41
+ # the build, not while loading it.
42
+ def evaluate
43
+ evaluate_default_properties
44
+ evaluate_scripts
45
+ evaluate_properties
46
+ end
47
+
48
+ # Return the list of properties (that is the list of local variables of
49
+ # context) as an unsorted list of strings.
50
+ def properties
51
+ return eval('local_variables', @context_binding).map{|var| var.to_s}
52
+ end
53
+
33
54
  # 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)
55
+ # - name: the property name as a string or symbol.
56
+ # - value: the property value as an object.
57
+ def set_property(name, value)
40
58
  begin
41
59
  eval("#{name} = #{value.inspect}", @context_binding)
42
60
  rescue Exception
43
61
  error "Error setting property '#{name} = #{value.inspect}': #{$!}"
44
62
  end
45
63
  end
46
-
47
- # Get a given property in context.
64
+
65
+ # Get a given property in context. Raises an error if the property was not
66
+ # set.
48
67
  # - 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)
68
+ def get_property(name)
53
69
  begin
54
70
  eval("#{name}", @context_binding)
55
71
  rescue NameError
@@ -58,18 +74,13 @@ module Bee
58
74
  error "Error getting property '#{name}': #{$!}"
59
75
  end
60
76
  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
-
77
+
67
78
  # Evaluate a script in context.
68
- # - script: source of the script to evaluate.
69
- def evaluate_script(script)
70
- eval(script, @context_binding)
79
+ # - source: source of the script to evaluate.
80
+ def evaluate_script(source)
81
+ eval(source, @context_binding)
71
82
  end
72
-
83
+
73
84
  # Process a given object, replacing properties references with their
74
85
  # string value, symbol with their raw value. Property references have
75
86
  # same form than variable references in ruby strings: '#{variable}'
@@ -85,7 +96,7 @@ module Bee
85
96
  object = object.gsub(/#\{.+?\}/) do |match|
86
97
  expression = match[2..-2]
87
98
  begin
88
- value = evaluate_script(expression)
99
+ value = eval(expression, @context_binding)
89
100
  rescue
90
101
  error "Error evaluating expression '#{expression}': #{$!}"
91
102
  end
@@ -115,24 +126,76 @@ module Bee
115
126
  return object
116
127
  end
117
128
  end
118
-
129
+
119
130
  private
120
-
121
- # Get a binding as script context.
122
- def get_binding
123
- return binding
131
+
132
+ # Evaluate properties in context, except system properties.
133
+ def evaluate_properties
134
+ for name in (@properties.keys - Bee::Properties::SYSTEM_PROPERTIES)
135
+ begin
136
+ Thread.current[:stack] = []
137
+ evaluate_property(name)
138
+ ensure
139
+ Thread.current[:stack] = nil
140
+ end
141
+ end
124
142
  end
125
143
 
126
- # Catch missing properties
127
- def method_missing(name, *args, &block)
144
+ # Evaluate default properties in context.
145
+ def evaluate_default_properties
146
+ for name in Bee::Properties::SYSTEM_PROPERTIES
147
+ begin
148
+ Thread.current[:stack] = []
149
+ evaluate_property(name)
150
+ ensure
151
+ Thread.current[:stack] = nil
152
+ end
153
+ end
154
+ end
155
+
156
+ # Evaluate a property with given name.
157
+ # - name: the name of the property to evaluate.
158
+ def evaluate_property(name)
128
159
  stack = Thread.current[:stack]
129
- if stack
130
- @properties.evaluate_property(name, self)
160
+ error "Circular properties: #{stack.join(', ')}" if stack.include?(name)
161
+ begin
162
+ stack.push(name)
163
+ value = evaluate_object(@properties[name])
164
+ stack.pop
165
+ set_property(name, value)
166
+ return value
167
+ rescue
168
+ error "Error evaluating property '#{name}': #{$!}"
169
+ end
170
+ end
171
+
172
+ # Evaluate scripts in the context.
173
+ def evaluate_scripts
174
+ for script in @scripts
175
+ begin
176
+ source = Bee::Util::get_file(script, @base)
177
+ evaluate_script(source)
178
+ rescue Exception
179
+ error "Error loading context '#{script}': #{$!}"
180
+ end
181
+ end
182
+ end
183
+
184
+ # Catch missing properties as missing methods.
185
+ # - name: the name of the missing property or method.
186
+ def method_missing(name, *args, &block)
187
+ if Thread.current[:stack]
188
+ return evaluate_property(name)
131
189
  else
132
190
  raise NoMethodError.new("undefined method `#{name}'", name, args)
133
191
  end
134
- end
135
-
192
+ end
193
+
194
+ # Get a binding as script context.
195
+ def get_binding
196
+ return binding
197
+ end
198
+
136
199
  end
137
200
 
138
201
  end
@@ -0,0 +1,114 @@
1
+ # Copyright 2006-2011 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 'rubygems'
16
+
17
+ module Bee
18
+
19
+ # Listener called when build events are triggered. Calls formatter to print
20
+ # events on the console.
21
+ class Listener
22
+
23
+ # Formatter used by listener.
24
+ attr_reader :formatter
25
+ # Build start time.
26
+ attr_reader :start_time
27
+ # Build end time.
28
+ attr_reader :end_time
29
+ # Build duration.
30
+ attr_reader :duration
31
+ # Build success.
32
+ attr_reader :successful
33
+ # Last target met.
34
+ attr_reader :last_target
35
+ # Last task met.
36
+ attr_reader :last_task
37
+ # Raised exception during build
38
+ attr_reader :exception
39
+
40
+ # Constructor.
41
+ # - formatter: the formatter to use to output on console.
42
+ def initialize(formatter)
43
+ @formatter = formatter
44
+ end
45
+
46
+ # Called when build is started.
47
+ # - build: the build object.
48
+ # - dry_run: tells if we are running in dry run.
49
+ def start(build, dry_run)
50
+ @start_time = Time.now
51
+ @end_time = nil
52
+ @duration = nil
53
+ @successful = nil
54
+ @last_target = nil
55
+ @last_task = nil
56
+ @formatter.print_build_started(build, dry_run)
57
+ end
58
+
59
+ # Called when build is finished.
60
+ def stop()
61
+ stop_chrono()
62
+ @formatter.print_build_finished(@duration)
63
+ end
64
+
65
+ # Called when a target is met.
66
+ # - target: the target object.
67
+ def target(target)
68
+ @last_target = target
69
+ @last_task = nil
70
+ @formatter.print_target(target)
71
+ end
72
+
73
+ # Called when a task is met.
74
+ # - task: task source (shell, Ruby or task).
75
+ def task(task)
76
+ @last_task = task
77
+ @formatter.print_task(task)
78
+ end
79
+
80
+ # Called when the build is a success.
81
+ def success()
82
+ @successful = true
83
+ @exception = nil
84
+ end
85
+
86
+ # Called when an error was raised.
87
+ # - exception: raised exception.
88
+ def error(exception)
89
+ @successful = false
90
+ @exception = exception
91
+ if exception.kind_of?(Bee::Util::BuildError)
92
+ exception.target = @last_target if @last_target
93
+ exception.task = @last_task if @last_task
94
+ end
95
+ end
96
+
97
+ # Recover from a previous error (catching it for instance).
98
+ def recover()
99
+ @successful = true
100
+ @exception = nil
101
+ end
102
+
103
+ private
104
+
105
+ # Stop chronometer, write build end time and build duration.
106
+ def stop_chrono()
107
+ @end_time = Time.now
108
+ @duration = @end_time - @start_time
109
+ @duration = (@duration * 1000).round / 1000
110
+ end
111
+
112
+ end
113
+
114
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2006-2010 Michel Casabianca <michel.casabianca@gmail.com>
1
+ # Copyright 2006-2011 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,9 +12,9 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'bee_context'
15
+ require 'rubygems'
16
+ require 'bee_util'
16
17
 
17
- # Module for Bee core classes.
18
18
  module Bee
19
19
 
20
20
  # Class to manage properties.
@@ -22,117 +22,88 @@ module Bee
22
22
 
23
23
  include Bee::Util::BuildErrorMixin
24
24
 
25
+ # System properties
26
+ SYSTEM_PROPERTIES = [:base, :here]
27
+
25
28
  # Key for properties entry.
26
29
  KEY = 'properties'
27
30
 
28
- # List of system properties
29
- SYSTEM_PROPERTIES = [:base, :here]
30
-
31
- # Properties expressions as a hash.
31
+ # Properties expressions
32
32
  attr_reader :expressions
33
- # Properties values as a hash
34
- attr_reader :values
35
33
 
36
34
  # Constructor.
37
- # - build: build object.
38
- def initialize(build)
39
- @build = build
35
+ # - properties: properties as a hash.
36
+ def initialize(properties={})
40
37
  @expressions = {}
41
- @values = {}
42
- defaults
38
+ check_properties(properties)
39
+ set_properties(properties, false)
43
40
  end
44
41
 
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
42
+ # Write new properties with passed expressions.
43
+ # - properties: properties as a hash.
44
+ def write(properties)
45
+ check_properties(properties)
46
+ set_properties(properties, false)
61
47
  end
62
48
 
63
49
  # Overwrite properties with those passed.
64
50
  # - properties: properties as a hash.
65
51
  def overwrite(properties)
52
+ check_properties(properties)
53
+ set_properties(properties, true)
54
+ end
55
+
56
+ # Set default properties: if they are already defined, will raise an error.
57
+ # - properties: default properties as a hash.
58
+ def defaults(properties)
66
59
  set_properties(properties, true)
67
60
  end
68
61
 
69
62
  # Extend with properties of parent build.
70
- # - properties: properties of parent build.
63
+ # - properties: properties of parent build as a hash.
71
64
  def extend(properties)
72
- for name in properties.expressions.keys
73
- @expressions[name] = properties.expressions[name] if
74
- !@expressions.include?(name)
65
+ check_properties_type(properties)
66
+ for name in properties.keys
67
+ @expressions[name] = properties[name] if !@expressions.include?(name)
75
68
  end
76
69
  end
77
70
 
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
71
+ private
87
72
 
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
73
+ # Check that properties are a hash and raise a BuildError if not.
74
+ # - properties: properties to check as a hash.
75
+ def check_properties_type(properties)
76
+ error "Properties must be a hash" if not properties.kind_of?(Hash)
106
77
  end
107
78
 
108
- private
109
-
110
- # Set default properties.
111
- def defaults
112
- set(:base, @build.base, false)
113
- set(:here, @build.here, false)
79
+ # Check properties for system ones:
80
+ # - properties: properties expressions as a hash.
81
+ def check_properties(properties)
82
+ check_properties_type(properties)
83
+ names = SYSTEM_PROPERTIES & properties.keys.map {|k| k.to_sym}
84
+ if names.length > 1
85
+ error "#{names.join(' and ')} are reserved property names"
86
+ elsif names.length > 0
87
+ error "#{names[0]} is a reserved property name"
88
+ end
114
89
  end
115
90
 
116
91
  # Set properties.
117
92
  # - properties: properties as a hash.
118
93
  # - overwrite: tells if we can overwrite existing properties.
119
94
  def set_properties(properties, overwrite)
120
- error "Properties must be a hash" if not properties.kind_of?(Hash)
95
+ check_properties_type(properties)
121
96
  for name in properties.keys
122
97
  expression = properties[name]
123
- set(name, expression, overwrite)
98
+ set_property(name, expression, overwrite)
124
99
  end
125
100
  end
126
101
 
127
- # Set a property.
102
+ # Set a given named property with an expression.
128
103
  # - name: property name (as a string or symbol).
129
- # - expression: property expression (as a string) to be evaluated in
130
- # context to get value.
104
+ # - expression: property expression as a string.
131
105
  # - 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)
106
+ def set_property(name, expression, overwrite)
136
107
  return if expression == nil
137
108
  name = name.to_sym
138
109
  error "Duplicate property definition: '#{name}'" if