bee 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/README CHANGED
@@ -1,4 +1,28 @@
1
- Bee is a simple build tool. It is inspired from Make (for intensive
2
- usage of command line to build projects) and Ant (for its build file).
3
- The result is aimed to keep benefits of both and get rid of their
4
- defaults (if any :o). Enjoy!
1
+ = bee
2
+
3
+ bee is a build tool running YAML build files la Ant (but with a Shopping
4
+ List syntax), which won't bother you with writing code when not necessary
5
+ and happens to be as fast as Make. These build files are thin layers around
6
+ scripts written in Shell, Ruby or bee tasks for platform independant builds
7
+ (feature currently under development).
8
+
9
+ = Home Page
10
+
11
+ This software is hosted on RubyForge (thanks to them for their great job!)
12
+ at http://bee.rubyforge.org.
13
+
14
+ = Documentation
15
+
16
+ For more information about this software, please read the documentation
17
+ in doc directory of the distribution archive (if you installed it from
18
+ installation archive) or see "bee" section on Gem server (type "gem_server"
19
+ and go at URL http://localhost:8808) if you installed it using Gem.
20
+
21
+ = License
22
+
23
+ bee is Open Source and released under the Apache License (see LICENE file
24
+ or go to URL http://www.apache.org/licenses/LICENSE-2.0).
25
+
26
+ = Copyright
27
+
28
+ bee version 0.2.0 (C) Michel Casabianca - 2006
data/bin/bee CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
- require 'bee'
4
+ require 'bee_console'
5
5
 
6
- Bee.start_command_line
6
+ Bee::Console.start_command_line
data/lib/bee.rb CHANGED
@@ -16,107 +16,6 @@
16
16
  module Bee
17
17
 
18
18
  require 'yaml'
19
- require 'getoptlong'
20
-
21
- # Copyright notice.
22
- COPYRIGHT = 'Bee version 0.1.1 (C) Michel Casabianca - 2006'
23
- # Command line help.
24
- HELP = 'Usage: bee [options] [targets]
25
- -h Print help about usage and exit.
26
- -b Print help about build and exit.
27
- -t Write template build file on disk.
28
- -v Enable verbose mode.
29
- -s style Define style for output (see documentation).
30
- -f file Build file to run (defaults to "build.yml").
31
- targets Targets to run (default target if omitted).'
32
- # Name for default build file.
33
- DEFAULT_BUILD_FILE = 'build.yml'
34
- # Exit value on error parsing command line
35
- EXIT_PARSING_CMDLINE = 1
36
- # Exit value on build error
37
- EXIT_BUILD_ERROR = 2
38
- # Exit value on unknown error
39
- EXIT_UNKNOWN_ERROR = 3
40
-
41
- # Parse command line and return parsed arguments.
42
- def self.parse_command_line
43
- help = false
44
- help_build = false
45
- template = false
46
- verbose = false
47
- style = nil
48
- file = DEFAULT_BUILD_FILE
49
- targets = []
50
- # read options in BEEOPT environment variable
51
- options = ENV['BEEOPT']
52
- options.split(' ').reverse.each { |option| ARGV.unshift(option) } if options
53
- # parse command line arguments
54
- opts = GetoptLong.new(['--help', '-h', GetoptLong::NO_ARGUMENT ],
55
- ['--help-build', '-b', GetoptLong::NO_ARGUMENT ],
56
- ['--template', '-t', GetoptLong::NO_ARGUMENT ],
57
- ['--verbose', '-v', GetoptLong::NO_ARGUMENT],
58
- ['--style', '-s', GetoptLong::REQUIRED_ARGUMENT],
59
- ['--file', '-f', GetoptLong::REQUIRED_ARGUMENT])
60
- opts.each do |opt, arg|
61
- case opt
62
- when '--help'
63
- help = true
64
- when '--help-build'
65
- help_build = true
66
- when '--template'
67
- template = true
68
- when '--verbose'
69
- verbose = true
70
- when '--style'
71
- style = arg
72
- when '--file'
73
- file = arg
74
- end
75
- end
76
- targets = ARGV
77
- return [help, help_build, template, verbose, style, file, targets]
78
- end
79
-
80
- # Start build from command line.
81
- def self.start_command_line
82
- STDOUT.sync = true
83
- begin
84
- help, help_build, template, verbose, style, file, targets =
85
- parse_command_line
86
- rescue
87
- puts "ERROR: parsing command line (type 'bee -h' for help)"
88
- exit(EXIT_PARSING_CMDLINE)
89
- end
90
- formatter = ConsoleFormatter.new(style)
91
- begin
92
- if help
93
- puts COPYRIGHT
94
- puts HELP
95
- elsif help_build
96
- build = Build.new(file)
97
- puts formatter.help_build(build)
98
- elsif template
99
- puts "Writing build template in file '#{file}'..."
100
- raise BuildError.new("Build file '#{file}' already exists") if
101
- File.exists?(file)
102
- File.open(file, 'w') { |file| file.write(BUILD_TEMPLATE) }
103
- puts formatter.format_success("OK")
104
- else
105
- listener = ConsoleListener.new(formatter, verbose)
106
- build = Build.new(file)
107
- build.run(targets, listener)
108
- end
109
- rescue BuildError
110
- puts "#{formatter.format_error('ERROR')}: #{$!}"
111
- exit(EXIT_BUILD_ERROR)
112
- rescue SystemExit
113
- # do nothing, exit in code
114
- rescue Exception => e
115
- puts "#{formatter.format_error('ERROR')}: #{$!}"
116
- puts e.backtrace.join("\n")
117
- exit(EXIT_UNKNOWN_ERROR)
118
- end
119
- end
120
19
 
121
20
  #########################################################################
122
21
  # BUILD ERROR #
@@ -134,361 +33,6 @@ targets Targets to run (default target if omitted).'
134
33
 
135
34
  end
136
35
 
137
- #########################################################################
138
- # CONSOLE FORMATTER CLASS #
139
- #########################################################################
140
-
141
- # Class to format build output on console.
142
- class ConsoleFormatter
143
-
144
- include BuildErrorMixin
145
-
146
- ###################### ANSI COLORS AND STYLES #########################
147
-
148
- # List of colors.
149
- COLORS = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
150
- # Foreground color codes.
151
- FOREGROUND_COLOR_CODES = {
152
- :black => 30,
153
- :red => 31,
154
- :green => 32,
155
- :yellow => 33,
156
- :blue => 34,
157
- :magenta => 35,
158
- :cyan => 36,
159
- :white => 37
160
- }
161
- # Background color codes.
162
- BACKGROUND_COLOR_CODES = {
163
- :black => 40,
164
- :red => 41,
165
- :green => 42,
166
- :yellow => 43,
167
- :blue => 44,
168
- :magenta => 45,
169
- :cyan => 46,
170
- :white => 47
171
- }
172
- # List of styles.
173
- STYLES = [:reset, :bright, :dim, :underscore, :blink, :reverse, :hidden]
174
- # Style codes.
175
- STYLE_CODES = {
176
- :reset => 0,
177
- :bright => 1,
178
- :dim => 2,
179
- :underscore => 4,
180
- :blink => 5,
181
- :reverse => 7,
182
- :hidden => 8
183
- }
184
-
185
- ############################ DEFAULT STYLE ############################
186
-
187
- # Default style (supposed to work on any configuration).
188
- DEFAULT_STYLE = {
189
- :line_character => '-'
190
- }
191
- # Default line length.
192
- DEFAULT_LINE_LENGTH = 80
193
- # Short style keys for command line
194
- SHORT_STYLE_KEYS = {
195
- 'lc' => 'line_character',
196
- 'll' => 'line_length',
197
- 'ts' => 'target_style',
198
- 'tf' => 'target_foreground',
199
- 'tb' => 'target_background',
200
- 'ks' => 'task_style',
201
- 'kf' => 'task_foreground',
202
- 'kb' => 'task_background',
203
- 'ss' => 'success_style',
204
- 'sf' => 'success_foreground',
205
- 'sb' => 'success_background',
206
- 'es' => 'error_style',
207
- 'ef' => 'error_foreground',
208
- 'eb' => 'error_background'
209
- }
210
-
211
- ############################## METHODS ################################
212
-
213
- # Constructor.
214
- # - style: style as a Hash or a String.
215
- def initialize(style)
216
- # if style is a String, this is command line argument
217
- style = parse_style_from_command_line(style) if style.kind_of?(String)
218
- # if style is nil, set default style
219
- @style = style || DEFAULT_STYLE
220
- # set default values for keys if nil
221
- for key in DEFAULT_STYLE.keys
222
- @style[key] = @style[key] || DEFAULT_STYLE[key]
223
- end
224
- end
225
-
226
- # Format a target.
227
- # - target: target to format.
228
- def format_target(target)
229
- name = target.name
230
- # generate title line
231
- length = @style[:line_length] || line_length || DEFAULT_LINE_LENGTH
232
- right = ' ' + @style[:line_character]*2
233
- left = @style[:line_character]*(length - (name.length + 4)) + ' '
234
- line = left + name + right
235
- # apply style
236
- formatted = style(line,
237
- @style[:target_style],
238
- @style[:target_foreground],
239
- @style[:target_background])
240
- return formatted
241
- end
242
-
243
- # Format a task.
244
- # - task: task to format.
245
- def format_task(task)
246
- if task.kind_of?(String)
247
- source = task
248
- elsif task.kind_of?(Hash)
249
- if task.key?('rb')
250
- source = task['rb']
251
- else
252
- source = YAML::dump(task)
253
- source = source.sub(/---/, '')
254
- end
255
- end
256
- formatted = '- ' + source.strip.gsub(/\n/, "\n. ")
257
- styled = style(formatted,
258
- @style[:task_style],
259
- @style[:task_foreground],
260
- @style[:task_background])
261
- return styled
262
- end
263
-
264
- # Format a success string.
265
- # - string: string to format.
266
- def format_success(string)
267
- string = style(string,
268
- @style[:success_style],
269
- @style[:success_foreground],
270
- @style[:success_background])
271
- return string
272
- end
273
-
274
- # Format an error string.
275
- # - string: string to format.
276
- def format_error(string)
277
- string = style(string,
278
- @style[:error_style],
279
- @style[:error_foreground],
280
- @style[:error_background])
281
- return string
282
- end
283
-
284
- # Return help about build.
285
- def help_build(build)
286
- help = ''
287
- if build.name
288
- help << "- Build: #{build.name.inspect}\n"
289
- end
290
- if build.description
291
- help << format_description('Description', build.description, 2, false)
292
- end
293
- if build.properties.keys.length > 0
294
- help << "- Properties:\n"
295
- for property in build.properties.keys.sort
296
- help << " - #{property}: #{build.properties[property].inspect}\n"
297
- end
298
- end
299
- if build.targets.length > 0
300
- help << "- Targets:\n"
301
- for target in build.targets.values.sort { |a, b| a.name <=> b.name }
302
- help << format_description(target.name, target.description, 2)
303
- end
304
- end
305
- help << "- Default: #{build.default}"
306
- return help.strip
307
- end
308
-
309
- private
310
-
311
- # Apply style to a string:
312
- # - string: the string to apply style to.
313
- # - style: style to apply on string.
314
- # - foreground: foreground color for string.
315
- # - background: background color for string.
316
- def style(string, style, foreground, background)
317
- # check style, foreground and background colors
318
- error "Unknown style '#{style}'" unless
319
- STYLES.member?(style) or not style
320
- error "Unknown color '#{foreground}'" unless
321
- COLORS.member?(foreground) or not foreground
322
- error "Unknown color '#{background}'" unless
323
- COLORS.member?(background) or not background
324
- # if no style nor colors, return raw string
325
- return string if not foreground and not background and not style
326
- # insert style and colors in string
327
- colorized = "\e["
328
- colorized << "#{STYLE_CODES[style]};" if style
329
- colorized << "#{FOREGROUND_COLOR_CODES[foreground]};" if foreground
330
- colorized << "#{BACKGROUND_COLOR_CODES[background]};" if background
331
- colorized = colorized[0..-2]
332
- colorized << "m#{string}\e[#{STYLE_CODES[:reset]}m"
333
- return colorized
334
- end
335
-
336
- # Get line length calling IOCTL. Return nil if call failed.
337
- def line_length
338
- begin
339
- tiocgwinsz = 0x5413
340
- string = [0, 0, 0, 0].pack('SSSS')
341
- if $stdin.ioctl(tiocgwinsz, string) >= 0 then
342
- rows, cols, xpixels, ypixels = string.unpack('SSSS')
343
- return cols
344
- end
345
- rescue
346
- return nil
347
- end
348
- end
349
-
350
- # Parse style from command line. If error occurs parsing style, return
351
- # nil (which means default style).
352
- # - string: style to parse.
353
- def parse_style_from_command_line(string)
354
- return if not string
355
- style = {}
356
- begin
357
- for pair in string.split(',')
358
- key, value = pair.split(':')
359
- key = SHORT_STYLE_KEYS[key] || key
360
- key = key.to_sym
361
- if key == :line_length
362
- value = value.to_i
363
- elsif key == :line_character
364
- value = ' ' if not value or value.length == 0
365
- else
366
- value = value.to_sym
367
- error "Unkown color or style '#{value}'" if
368
- not COLORS.member?(value) and not STYLES.member?(value)
369
- end
370
- style[key] = value
371
- end
372
- return style
373
- rescue
374
- # if parsing fails, return default style (nil)
375
- return nil
376
- end
377
- end
378
-
379
- # Format a description.
380
- # - title: description title (project, property or target name).
381
- # - text: description text.
382
- # - indent: indentation width.
383
- # - bullet: tells if we must put a bullet.
384
- def format_description(title, text=nil, indent=0, bullet=true)
385
- string = ' '*indent
386
- string << '- ' if bullet
387
- string << title
388
- if text
389
- string << ": "
390
- if text.split("\n").length > 1
391
- string << "\n"
392
- text.split("\n").each do |line|
393
- string << ' '*(indent+2) + line.strip + "\n"
394
- end
395
- else
396
- string << text.strip + "\n"
397
- end
398
- end
399
- return string
400
- end
401
-
402
- end
403
-
404
- #########################################################################
405
- # CONSOLE LISTENER #
406
- #########################################################################
407
-
408
- # Listener when running in a console. Prints messages on the console using
409
- # a given formatter.
410
- class ConsoleListener
411
-
412
- # Formatter used by listener.
413
- attr_reader :formatter
414
- # Verbosity flag.
415
- attr_reader :verbose
416
- # Build start time.
417
- attr_reader :start_time
418
- # Build end time.
419
- attr_reader :end_time
420
- # Build duration.
421
- attr_reader :duration
422
- # Build success.
423
- attr_reader :success
424
- # Last target met.
425
- attr_reader :last_target
426
- # Last task met.
427
- attr_reader :last_task
428
-
429
- # Constructor.
430
- # - formatter: the formatter to use to output on console.
431
- # - verbose: tells if we run in verbose mode.
432
- def initialize(formatter, verbose)
433
- @formatter = formatter
434
- @verbose = verbose
435
- end
436
-
437
- # Called when build is started.
438
- # - build: the build object.
439
- def build_started(build)
440
- @start_time = Time.now
441
- @end_time = nil
442
- @duration = nil
443
- @success = nil
444
- @last_target = nil
445
- @last_task = nil
446
- puts "Starting build '#{build.file}'..." if @verbose
447
- end
448
-
449
- # Called when build is finished.
450
- # - build: the build object.
451
- def build_finished(build)
452
- @end_time = Time.now
453
- @duration = @end_time - @start_time
454
- @success = true
455
- puts "Built in #{@duration} s" if @verbose
456
- puts @formatter.format_success('OK')
457
- end
458
-
459
- # Called when a target is met.
460
- # - target: the target object.
461
- def target(target)
462
- @last_target = target
463
- @last_task = nil
464
- puts @formatter.format_target(target)
465
- end
466
-
467
- # Called when a task is met.
468
- # - task: task source (shell, Ruby or task).
469
- def task(task)
470
- @last_task = task
471
- puts @formatter.format_task(task) if @verbose
472
- end
473
-
474
- # Called when an error was raised.
475
- # - exception: raised exception.
476
- def error(exception)
477
- @end_time = Time.now
478
- @duration = @end_time - @start_time
479
- @success = false
480
- puts "Built in #{@duration} s" if @verbose
481
- message = ''
482
- message << "In target '#{@last_target.name}'" if @last_target
483
- message << ", in task:\n#{@formatter.format_task(@last_task)}\n" if
484
- @last_task
485
- message << ': ' if @last_target and not @last_task
486
- message << exception.to_s
487
- puts "#{@formatter.format_error('ERROR')}: #{message}"
488
- end
489
-
490
- end
491
-
492
36
  #########################################################################
493
37
  # BUILD CLASS #
494
38
  #########################################################################
@@ -514,8 +58,8 @@ targets Targets to run (default target if omitted).'
514
58
  attr_reader :targets
515
59
  # Context for Ruby scripts and properties.
516
60
  attr_reader :context
517
- # Loaded extensions.
518
- attr_reader :extensions
61
+ # Loaded tasks.
62
+ attr_reader :tasks
519
63
  # Build listener.
520
64
  attr_reader :listener
521
65
 
@@ -525,12 +69,15 @@ targets Targets to run (default target if omitted).'
525
69
  @file = file
526
70
  @properties = {}
527
71
  @targets = {}
72
+ @tasks = {}
528
73
  @context = Context.new
529
- @extensions = {}
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)
530
78
  @base = File.expand_path(File.dirname(@file))
531
79
  @context.set('base', @base)
532
80
  @properties['base'] = @base
533
- load_context(DEFAULT_CONTEXT)
534
81
  # load build file
535
82
  begin
536
83
  source = File.read(@file)
@@ -623,11 +170,17 @@ targets Targets to run (default target if omitted).'
623
170
 
624
171
  private
625
172
 
626
- # Load a given context.
173
+ # Load a given context and add last expression evaluated in context to
174
+ # extension tasks mapping.
627
175
  # - source: the context source.
628
176
  def load_context(source)
629
- @context.evaluate(source)
630
- @extensions = @context.get('TASKS')
177
+ new_tasks = @context.evaluate(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
631
184
  end
632
185
 
633
186
  end
@@ -721,7 +274,11 @@ targets Targets to run (default target if omitted).'
721
274
  # - script: the scrip to run.
722
275
  def run_ruby(script)
723
276
  @listener.task(script) if @listener
724
- @build.context.evaluate(script)
277
+ begin
278
+ @build.context.evaluate(script)
279
+ rescue BuildError
280
+ error "Error running Ruby script: #{$!}"
281
+ end
725
282
  end
726
283
 
727
284
  # Run a given task.
@@ -730,10 +287,14 @@ targets Targets to run (default target if omitted).'
730
287
  @listener.task(task) if @listener
731
288
  name = task.keys[0]
732
289
  error "Unknown task '#{name}'" if
733
- not @build.extensions.key?(name)
290
+ not @build.tasks.key?(name)
734
291
  parameters = task[name]
735
292
  script = "#{name}(#{parameters.inspect})"
736
- @build.context.evaluate(script)
293
+ begin
294
+ @build.context.evaluate(script)
295
+ rescue BuildError
296
+ error "Error running task #{name}: #{$!}"
297
+ end
737
298
  end
738
299
 
739
300
  end
@@ -747,9 +308,12 @@ targets Targets to run (default target if omitted).'
747
308
 
748
309
  include BuildErrorMixin
749
310
 
311
+ # The binding of this context.
312
+ attr_reader :context_binding
313
+
750
314
  # Constructor.
751
315
  def initialize
752
- @binding = get_binding
316
+ @context_binding = get_binding
753
317
  end
754
318
 
755
319
  # Set a given value in context.
@@ -757,7 +321,7 @@ targets Targets to run (default target if omitted).'
757
321
  # - value: the variable value.
758
322
  def set(name, value)
759
323
  begin
760
- eval("#{name} = #{value.inspect}", @binding)
324
+ eval("#{name} = #{value.inspect}", @context_binding)
761
325
  rescue
762
326
  error "Error setting property '#{name} = #{value.inspect}': #{$!}"
763
327
  end
@@ -767,7 +331,7 @@ targets Targets to run (default target if omitted).'
767
331
  # - name: the variable name.
768
332
  def get(name)
769
333
  begin
770
- eval("#{name}", @binding)
334
+ eval("#{name}", @context_binding)
771
335
  rescue
772
336
  error "Error getting property '#{name}': #{$!}"
773
337
  end
@@ -776,11 +340,7 @@ targets Targets to run (default target if omitted).'
776
340
  # Evaluate a script in context.
777
341
  # - script: script to evaluate.
778
342
  def evaluate(script)
779
- begin
780
- eval(script, @binding)
781
- rescue
782
- error "Error running script: #{$!}"
783
- end
343
+ eval(script, @context_binding)
784
344
  end
785
345
 
786
346
  # Process a given string, replacing properties references with their
@@ -808,109 +368,4 @@ targets Targets to run (default target if omitted).'
808
368
 
809
369
  end
810
370
 
811
- #########################################################################
812
- # DEFAULT CONTEXT #
813
- #########################################################################
814
-
815
- DEFAULT_CONTEXT = '
816
- # Default context script loaded at startup.
817
-
818
- # Hash of tasks help indexed by their name.
819
- TASKS = {}
820
-
821
- ######################### TASKS UTILITY FUNCTIONS #########################
822
-
823
- # Bind tasks. This method must be called by context scripts defining tasks.
824
- # - tasks: Hash indexing task help with task names.
825
- def bind_tasks(tasks)
826
- for name, help in tasks
827
- raise "Task \'#{name}\' already bound" if TASKS.key?(name)
828
- TASKS[name] = help
829
- end
830
- end
831
-
832
- # Check a task parameters. Raise a RuntimeError with explanation message if
833
- # a mandatory parameter is missing or an unknown parameter was found.
834
- # - params: task parameters as a Hash.
835
- # - description: parameters description as a Hash associating a parameter
836
- # name with symbol :mandatory or :optional.
837
- def check_parameters(params, description)
838
- raise "Parameters must be a Hash" unless params.kind_of?(Hash)
839
- for param in description.keys
840
- raise "Missing mandatory parameter \'#{param}\'" unless
841
- params[param] or description[param] == :optional
842
- end
843
- for param in params.keys
844
- raise "Unknown parameter \'#{param}\'" if not description.key?(param)
845
- end
846
- end
847
-
848
- ############################ TASK DEFINITIONS #############################
849
-
850
- # bind tasks defined hereafter
851
- bind_tasks({
852
- "mkdir" =>
853
- "Create a directory and all parent directories if necessary. Do nothing if
854
- directory already exists. Parameter is a String for directory to create."
855
- })
856
-
857
- # Make a directory and parent directories if necessary.
858
- def self.mkdir(dir)
859
- raise "Parameter must be a String" unless dir.kind_of?(String)
860
- require "fileutils"
861
- FileUtils.makedirs(dir)
862
- end
863
-
864
- ############################ UTILITY FUNCTIONS ############################
865
-
866
- # Run a shell script and raise an exception if script returned a value
867
- # different of 0.
868
- # - script: script to run.
869
- def sh(script)
870
- system(script) or raise "Script \'#{script}\' exited with value \'#{$?}\'"
871
- end
872
-
873
- # Find files that match a given pattern.
874
- # - pattern: pattern to select files.
875
- # - base: base directory for search.
876
- # - dir: tells if we must include directories.
877
- # Return: a file list.
878
- def find(pattern=//, base=\'.\', dir=true)
879
- require \'find\'
880
- files = []
881
- Find.find(base) do |path|
882
- if path =~ pattern and (File.file?(path) or (File.directory?(path) and dir))
883
- files << path
884
- end
885
- end
886
- return files
887
- end
888
- '
889
-
890
- #########################################################################
891
- # BUILD TEMPLATE #
892
- #########################################################################
893
-
894
- BUILD_TEMPLATE =
895
- '# Template build file
896
- - build: template
897
- description: Template build file.
898
- default: hello
899
-
900
- # Build properties
901
- - properties:
902
- - user: "#{ENV[\'USER\']}"
903
-
904
- # Build targets
905
- - target: capitalize
906
- description: Capitalize user name
907
- script:
908
- - rb: "who = user.capitalize"
909
-
910
- - target: hello
911
- depends: capitalize
912
- description: Print greatings.
913
- script:
914
- - "echo \"Hello #{who}!\""
915
- '
916
371
  end