bee 0.10.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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