bee 0.3.1 → 0.4.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.
data/README CHANGED
@@ -25,4 +25,4 @@ or go to URL http://www.apache.org/licenses/LICENSE-2.0).
25
25
 
26
26
  = Copyright
27
27
 
28
- bee version 0.3.1 (C) Michel Casabianca - 2006
28
+ bee version 0.4.0 (C) Michel Casabianca & Contributors - 2006-2007
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
 
@@ -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 <casa@sweetohm.net>
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
- # Module for Bee stuff.
16
- module Bee
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
- end
35
-
36
- #########################################################################
37
- # BUILD CLASS #
38
- #########################################################################
18
+ # Module for Bee core classes.
19
+ module Bee
39
20
 
40
- # Class for a given build.
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
- # Loaded tasks.
62
- attr_reader :tasks
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
- # - file: build file to load.
68
- def initialize(file)
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
- default_context_file = File.join(File.dirname(__FILE__),
75
- 'bee_default_context.rb')
76
- source = File.read(default_context_file)
77
- load_context(source)
78
- @base = File.expand_path(File.dirname(@file))
79
- @context.set('base', @base)
80
- @properties['base'] = @base
81
- # load build file
82
- begin
83
- source = File.read(@file)
84
- build = YAML::load(source)
85
- # parse object entries
86
- for entry in build
87
- if entry.key?('build')
88
- # build info entry
89
- error "Duplicate build info" if @name
90
- @name = entry['build']
91
- @default = entry['default']
92
- @description = entry['description']
93
- # load context files if any
94
- if entry['context']
95
- for script in entry['context']
96
- begin
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
- name = property.keys[0]
111
- value = @context.evaluate_object(property[name])
112
- error "Duplicate property '#{name}' definition" if
113
- @properties[name]
114
- @properties[name] = value
115
- @context.set(name, value)
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
- elsif entry.key?('target')
121
- # target entry
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
- @default = target.name if not @default and @targets.keys.length == 0
124
- error "Duplicate target definition: '#{target.name}'" if
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
- # TARGET CLASS #
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
- # - target: target for target, resulting from YAML parsing.
206
+ # - object: object for target, resulting from YAML parsing.
210
207
  # - build: build that encapsulate this target.
211
- def initialize(target, build)
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 = target['target']
214
- @depends = target['depends']||[]
215
- @description = target['description']
216
- @script = target['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
- run_extension(task)
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 BuildError
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 run_extension(task)
292
+ def run_bee_task(task)
293
+ require 'bee_task'
291
294
  @listener.task(task) if @listener
292
- name = task.keys[0]
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
- # CONTEXT CLASS #
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 value in context.
324
- # - name: the variable name to set.
325
- # - value: the variable value.
326
- def set(name, value)
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 value in context.
335
- # - name: the variable name.
336
- def get(name)
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 = get(property)
365
- error ("Property '#{property}' was not defined") unless value
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 = get(property)
373
- error ("Property '#{property}' was not defined") unless value
374
- return value
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.