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.
@@ -13,23 +13,24 @@
13
13
  # limitations under the License.
14
14
 
15
15
  require 'rubygems'
16
- require 'bee'
17
- require 'bee_task'
16
+ require 'bee_build'
18
17
  require 'bee_util'
18
+ require 'bee_listener'
19
+ require 'bee_console_formatter'
19
20
  require 'getoptlong'
20
21
  require 'yaml'
21
22
 
22
- # Module for Bee stuff.
23
23
  module Bee
24
24
 
25
25
  module Console
26
26
 
27
27
  # Command line help.
28
- HELP = 'Usage: bee [options] [targets]
28
+ HELP = <<'EOF'
29
+ Usage: bee [options] [targets]
29
30
  -V Print version and exit.
30
31
  -h Print help about usage and exit.
31
32
  -b Print help about build and exit.
32
- -n Don\'t actually run any commands; just print them.
33
+ -n Don't actually run any commands; just print them.
33
34
  -k task Print help about tasks in a package (writing "foo.?") or a
34
35
  given one (writing "foo.bar") and exit.
35
36
  -e egg Print help about templates in a given package (writing
@@ -45,7 +46,10 @@ module Bee
45
46
  -l Print bee logo on console.
46
47
  -a Print list of available targets.
47
48
  -o Print list of available options.
48
- targets Targets to run (default target if omitted).'
49
+ -f Print list of available tasks.
50
+ -g Print list of available templates.
51
+ targets Targets to run (default target if omitted).
52
+ EOF
49
53
  # Options descriptions.
50
54
  OPTIONS = [
51
55
  ['--version', '-V', GetoptLong::NO_ARGUMENT],
@@ -65,6 +69,8 @@ targets Targets to run (default target if omitted).'
65
69
  ['--logo', '-l', GetoptLong::NO_ARGUMENT],
66
70
  ['--targets', '-a', GetoptLong::NO_ARGUMENT],
67
71
  ['--options', '-o', GetoptLong::NO_ARGUMENT],
72
+ ['--tasks', '-x', GetoptLong::NO_ARGUMENT],
73
+ ['--templates', '-y', GetoptLong::NO_ARGUMENT],
68
74
  ]
69
75
  # Name for default build file.
70
76
  DEFAULT_BUILD_FILE = 'build.yml'
@@ -109,6 +115,8 @@ EOF
109
115
  logo = false
110
116
  print_targets = false
111
117
  print_options = false
118
+ print_tasks = false
119
+ print_templates = false
112
120
  targets = []
113
121
  # read options in BEEOPT environment variable
114
122
  options = ENV[BEE_OPT_ENV]
@@ -158,13 +166,18 @@ EOF
158
166
  print_targets = true
159
167
  when '--options'
160
168
  print_options = true
169
+ when '--tasks'
170
+ print_tasks = true
171
+ when '--templates'
172
+ print_templates = true
161
173
  end
162
174
  end
163
175
  targets = Array.new(ARGV)
164
176
  ARGV.replace(old_argv)
165
- return [version, help, help_build, help_task, help_template, task,
166
- properties, dry_run, template, verbose, style, color, file,
167
- recursive, logo, print_targets, print_options, targets]
177
+ return version, help, help_build, help_task, task, help_template,
178
+ template, properties, dry_run, verbose, style, color, file,
179
+ recursive, logo, print_targets, print_options, print_tasks,
180
+ print_templates, targets
168
181
  end
169
182
 
170
183
  # Parse a command line property.
@@ -173,7 +186,7 @@ EOF
173
186
  def self.parse_property(property)
174
187
  begin
175
188
  index = property.index('=')
176
- raise "No = sign" if not index
189
+ raise "No = sign (should be 'name=value')" if not index
177
190
  name = property[0..index-1]
178
191
  value = YAML::load(property[index+1..-1])
179
192
  return name, value
@@ -187,33 +200,28 @@ EOF
187
200
  def self.start_command_line(arguments)
188
201
  STDOUT.sync = true
189
202
  begin
190
- version, help, help_build, help_task, help_template, task,
191
- properties, dry_run, template, verbose, style, color, file,
192
- recursive, logo, print_targets, print_options,
193
- targets = parse_command_line(arguments)
203
+ version, help, help_build, help_task, task, help_template,
204
+ template, properties, dry_run, verbose, style, color, file,
205
+ recursive, logo, print_targets, print_options, print_tasks,
206
+ print_templates, targets = parse_command_line(arguments)
194
207
  rescue
195
- # DEBUG
196
- puts $!.backtrace
197
- puts "ERROR: parsing command line (type 'bee -h' for help)"
208
+ puts "ERROR: parsing command line: #{$!}"
198
209
  exit(EXIT_PARSING_CMDLINE)
199
210
  end
200
211
  begin
201
- formatter = Formatter.new(style, color)
212
+ formatter = Formatter.new(style, color, verbose)
202
213
  rescue
203
214
  puts "ERROR: bad format string '#{style}'"
204
215
  exit(EXIT_PARSING_CMDLINE)
205
216
  end
206
217
  begin
207
- if logo
208
- puts BEE_LOGO
209
- end
218
+ puts BEE_LOGO if logo
210
219
  if version
211
220
  puts Bee.version
212
221
  elsif help
213
222
  puts HELP
214
223
  elsif help_build
215
224
  build = Build.load(file, recursive, properties)
216
- build.evaluate_properties
217
225
  puts formatter.help_build(build)
218
226
  elsif help_task
219
227
  puts formatter.help_task(task)
@@ -221,7 +229,7 @@ EOF
221
229
  puts formatter.help_template(template)
222
230
  elsif template
223
231
  file = Bee::Util::find_template(template)
224
- listener = Listener.new(formatter, verbose)
232
+ listener = Listener.new(formatter)
225
233
  build = Build.load(file, false, properties)
226
234
  build.run(targets, listener, dry_run)
227
235
  elsif print_targets
@@ -234,459 +242,30 @@ EOF
234
242
  print targets.join(' ')
235
243
  elsif print_options
236
244
  print OPTIONS.map {|o| o[0]}.join(' ')
245
+ elsif print_tasks
246
+ print Bee::Task::PackageManager.list_tasks.join(' ')
247
+ elsif print_templates
248
+ print Bee::Task::PackageManager.list_templates.join(' ')
237
249
  else
238
- listener = Listener.new(formatter, verbose)
250
+ listener = Listener.new(formatter)
239
251
  build = Build.load(file, recursive, properties)
240
252
  build.run(targets, listener, dry_run)
253
+ puts formatter.format_success('OK')
241
254
  end
242
- rescue Bee::Util::BuildError => e
243
- puts "#{formatter.format_error('ERROR')}: #{$!}"
244
- puts e.backtrace.join("\n") if verbose
255
+ rescue Bee::Util::BuildError
256
+ puts formatter.format_error_message($!)
245
257
  exit(EXIT_BUILD_ERROR)
246
- rescue Interrupt => e
247
- puts "#{formatter.format_error('ERROR')}: Build was interrupted!"
248
- puts e.backtrace.join("\n") if verbose
258
+ rescue Interrupt
259
+ puts "\n#{formatter.format_error('ERROR')}: Build was interrupted!"
260
+ puts $!.backtrace.join("\n") if verbose
249
261
  exit(EXIT_INTERRUPT_ERROR)
250
- rescue Exception => e
262
+ rescue Exception
251
263
  puts "#{formatter.format_error('ERROR')}: #{$!}"
252
- puts e.backtrace.join("\n")
264
+ puts $!.backtrace.join("\n")
253
265
  exit(EXIT_UNKNOWN_ERROR)
254
266
  end
255
267
  end
256
268
 
257
- # Class to format build output on console.
258
- class Formatter
259
-
260
- include Bee::Util::BuildErrorMixin
261
-
262
- # List of colors.
263
- COLORS = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
264
- # Foreground color codes.
265
- FOREGROUND_COLOR_CODES = {
266
- :black => 30,
267
- :red => 31,
268
- :green => 32,
269
- :yellow => 33,
270
- :blue => 34,
271
- :magenta => 35,
272
- :cyan => 36,
273
- :white => 37
274
- }
275
- # Background color codes.
276
- BACKGROUND_COLOR_CODES = {
277
- :black => 40,
278
- :red => 41,
279
- :green => 42,
280
- :yellow => 43,
281
- :blue => 44,
282
- :magenta => 45,
283
- :cyan => 46,
284
- :white => 47
285
- }
286
- # List of styles.
287
- STYLES = [:reset, :bright, :dim, :underscore, :blink, :reverse, :hidden]
288
- # Style codes.
289
- STYLE_CODES = {
290
- :reset => 0,
291
- :bright => 1,
292
- :dim => 2,
293
- :underscore => 4,
294
- :blink => 5,
295
- :reverse => 7,
296
- :hidden => 8
297
- }
298
-
299
- # Default style (supposed to work on any configuration).
300
- DEFAULT_STYLE = {
301
- :line_character => '-'
302
- }
303
- # Color style (supposed to work on color terminals).
304
- COLOR_STYLE = {
305
- :line_character => '-',
306
- :target_foreground => :yellow,
307
- :task_foreground => :blue,
308
- :success_style => :bright,
309
- :success_foreground => :green,
310
- :error_style => :bright,
311
- :error_foreground => :red
312
- }
313
- # Short style keys for command line
314
- SHORT_STYLE_KEYS = {
315
- 'lc' => 'line_character',
316
- 'll' => 'line_length',
317
- 'ts' => 'target_style',
318
- 'tf' => 'target_foreground',
319
- 'tb' => 'target_background',
320
- 'ks' => 'task_style',
321
- 'kf' => 'task_foreground',
322
- 'kb' => 'task_background',
323
- 'ss' => 'success_style',
324
- 'sf' => 'success_foreground',
325
- 'sb' => 'success_background',
326
- 'es' => 'error_style',
327
- 'ef' => 'error_foreground',
328
- 'eb' => 'error_background'
329
- }
330
-
331
- # Constructor.
332
- # - style: style as a Hash or a String.
333
- # - color: a boolean telling if we use default color scheme.
334
- def initialize(style, color=false)
335
- # set default or color style
336
- if color
337
- @style = COLOR_STYLE.clone
338
- else
339
- @style = DEFAULT_STYLE.clone
340
- end
341
- # if style is a String, this is command line argument
342
- if style.kind_of?(String)
343
- @style.merge!(parse_style_from_command_line(style))
344
- elsif style.kind_of?(Hash)
345
- @style.merge!(style)
346
- end
347
- end
348
-
349
- # Format a target.
350
- # - target: target to format.
351
- def format_target(target)
352
- name = target.name
353
- return format_title(name)
354
- end
355
-
356
- # Format a task.
357
- # - task: task to format.
358
- def format_task(task)
359
- if task.kind_of?(String)
360
- source = task
361
- elsif task.kind_of?(Hash)
362
- if task.key?('rb')
363
- source = "rb: #{task['rb']}"
364
- else
365
- source = YAML::dump(task)
366
- source = source.sub(/---/, '')
367
- end
368
- end
369
- formatted = '- ' + source.strip.gsub(/\n/, "\n. ")
370
- styled = style(formatted,
371
- @style[:task_style],
372
- @style[:task_foreground],
373
- @style[:task_background])
374
- return styled
375
- end
376
-
377
- # Format a success string.
378
- # - string: string to format.
379
- def format_success(string)
380
- string = style(string,
381
- @style[:success_style],
382
- @style[:success_foreground],
383
- @style[:success_background])
384
- return string
385
- end
386
-
387
- # Format an error string.
388
- # - string: string to format.
389
- def format_error(string)
390
- string = style(string,
391
- @style[:error_style],
392
- @style[:error_foreground],
393
- @style[:error_background])
394
- return string
395
- end
396
-
397
- # Return help about build.
398
- # - build: running build.
399
- def help_build(build)
400
- help = ''
401
- # print build name and description
402
- if build.name
403
- help << "build: #{build.name}\n"
404
- end
405
- if build.extends
406
- help << "extends: #{build.extends.map{|b| b.name}.join(', ')}\n"
407
- end
408
- if build.description
409
- help << format_description('description', build.description, 0, false)
410
- end
411
- # print build properties
412
- if build.context.properties.length > 0
413
- help << "properties:\n"
414
- for property in build.context.properties.sort
415
- help << "- #{property}: " +
416
- "#{build.context.get_property(property, true).inspect}\n"
417
- end
418
- end
419
- # print build targets
420
- description = build.targets.description
421
- if description.length > 0
422
- help << "targets:\n"
423
- for name in description.keys.sort
424
- help << format_description(name, description[name], 0)
425
- end
426
- end
427
- # print default target
428
- help << "default: #{build.default}\n"
429
- return help.strip
430
- end
431
-
432
- # Return help about task(s).
433
- # - task: task to print help about (all tasks if nil).
434
- def help_task(task)
435
- task = '?' if task == nil or task.length == 0
436
- package_manager = Bee::Task::PackageManager.new(nil)
437
- methods = package_manager.help_task(task)
438
- help = ''
439
- for method in methods.keys.sort
440
- text = methods[method].strip
441
- help << format_title(method)
442
- help << "\n"
443
- help << text
444
- help << "\n"
445
- if text =~ /Alias for \w+/
446
- alias_method = text.scan(/Alias for (\w+)/).flatten[0]
447
- help << "\n"
448
- help << package_manager.help_task(alias_method)[alias_method].strip
449
- help << "\n"
450
- end
451
- end
452
- return help
453
- end
454
-
455
- # Return help about template(s).
456
- # - template: template to print help about (all templates if nil).
457
- def help_template(template)
458
- templates = Bee::Util::search_templates(template)
459
- help = ''
460
- for name in templates.keys
461
- build = YAML::load(File.read(templates[name]))
462
- properties = nil
463
- for entry in build
464
- properties = entry['properties'] if entry['properties']
465
- end
466
- description = 'No description found'
467
- if properties
468
- if properties['description']
469
- description = properties['description']
470
- end
471
- end
472
- help << format_title(name)
473
- help << "\n"
474
- help << description
475
- help << "\n"
476
- end
477
- return help
478
- end
479
-
480
- private
481
-
482
- # Apply style to a string:
483
- # - string: the string to apply style to.
484
- # - style: style to apply on string.
485
- # - foreground: foreground color for string.
486
- # - background: background color for string.
487
- def style(string, style, foreground, background)
488
- # check style, foreground and background colors
489
- error "Unknown style '#{style}'" unless
490
- STYLES.member?(style) or not style
491
- error "Unknown color '#{foreground}'" unless
492
- COLORS.member?(foreground) or not foreground
493
- error "Unknown color '#{background}'" unless
494
- COLORS.member?(background) or not background
495
- # if no style nor colors, return raw string
496
- return string if not foreground and not background and not style
497
- # insert style and colors in string
498
- colorized = "\e["
499
- colorized << "#{STYLE_CODES[style]};" if style
500
- colorized << "#{FOREGROUND_COLOR_CODES[foreground]};" if foreground
501
- colorized << "#{BACKGROUND_COLOR_CODES[background]};" if background
502
- colorized = colorized[0..-2]
503
- colorized << "m#{string}\e[#{STYLE_CODES[:reset]}m"
504
- return colorized
505
- end
506
-
507
- # Parse style from command line.
508
- # - string: style to parse.
509
- def parse_style_from_command_line(string)
510
- return if not string
511
- style = {}
512
- for pair in string.split(',')
513
- key, value = pair.split(':')
514
- key = SHORT_STYLE_KEYS[key] || key
515
- key = key.to_sym
516
- if key == :line_length
517
- value = value.to_i
518
- elsif key == :line_character
519
- value = ' ' if not value or value.length == 0
520
- else
521
- value = value.to_sym
522
- error "Unkown color or style '#{value}'" if
523
- not COLORS.member?(value) and not STYLES.member?(value)
524
- end
525
- style[key] = value
526
- end
527
- return style
528
- end
529
-
530
- # Format a description.
531
- # - title: description title (project, property or target name).
532
- # - text: description text.
533
- # - indent: indentation width.
534
- # - bullet: tells if we must put a bullet.
535
- def format_description(title, text=nil, indent=0, bullet=true)
536
- string = ' '*indent
537
- string << '- ' if bullet
538
- string << title
539
- if text and !text.empty?
540
- string << ": "
541
- if text.split("\n").length > 1
542
- string << "\n"
543
- text.split("\n").each do |line|
544
- string << ' '*(indent+2) + line.strip + "\n"
545
- end
546
- else
547
- string << text.strip + "\n"
548
- end
549
- else
550
- string << "\n"
551
- end
552
- return string
553
- end
554
-
555
- # Format a title.
556
- # - title: title to format.
557
- def format_title(title)
558
- length = @style[:line_length] || Bee::Util::term_width
559
- right = ' ' + @style[:line_character]*2
560
- size = length - (title.length + 4)
561
- size = 2 if size <= 0
562
- left = @style[:line_character]*size + ' '
563
- line = left + title + right
564
- # apply style
565
- formatted = style(line,
566
- @style[:target_style],
567
- @style[:target_foreground],
568
- @style[:target_background])
569
- return formatted
570
- end
571
-
572
- end
573
-
574
- # Listener when running in a console. Prints messages on the console using
575
- # a given formatter.
576
- class Listener
577
-
578
- # Formatter used by listener.
579
- attr_reader :formatter
580
- # Verbosity flag.
581
- attr_reader :verbose
582
- # Build start time.
583
- attr_reader :start_time
584
- # Build end time.
585
- attr_reader :end_time
586
- # Build duration.
587
- attr_reader :duration
588
- # Build success.
589
- attr_reader :success
590
- # Last target met.
591
- attr_reader :last_target
592
- # Last task met.
593
- attr_reader :last_task
594
- # Minimum duration to print on console even if not verbose (in seconds)
595
- AUTO_DURATION = 60
596
-
597
- # Constructor.
598
- # - formatter: the formatter to use to output on console.
599
- # - verbose: tells if we run in verbose mode.
600
- def initialize(formatter, verbose)
601
- @formatter = formatter
602
- @verbose = verbose
603
- end
604
-
605
- # Called when build is started.
606
- # - build: the build object.
607
- def build_started(build, dry_run)
608
- @start_time = Time.now
609
- @end_time = nil
610
- @duration = nil
611
- @success = nil
612
- @last_target = nil
613
- @last_task = nil
614
- build_type = dry_run ? "dry run of" : "build"
615
- puts "Starting #{build_type} '#{build.file}'..." if @verbose
616
- end
617
-
618
- # Called when a target is met.
619
- # - target: the target object.
620
- def target(target)
621
- @last_target = target
622
- @last_task = nil
623
- puts @formatter.format_target(target)
624
- end
625
-
626
- # Called when a task is met.
627
- # - task: task source (shell, Ruby or task).
628
- def task(task)
629
- @last_task = task
630
- puts @formatter.format_task(task) if @verbose
631
- end
632
-
633
- # Called when build is finished.
634
- # - build: the build object.
635
- def build_finished(build, dry_run)
636
- duration unless dry_run
637
- @success = true
638
- puts @formatter.format_success('OK')
639
- end
640
-
641
- # Called when an error was raised.
642
- # - exception: raised exception.
643
- def error(exception)
644
- duration
645
- @success = false
646
- message = ''
647
- message << "In target '#{@last_target.name}'" if @last_target
648
- message << ", in task:\n#{@formatter.format_task(@last_task)}\n" if
649
- @last_task
650
- message << ': ' if @last_target and not @last_task
651
- message << exception.to_s
652
- raise Bee::Util::BuildError.new(message)
653
- end
654
-
655
- # Recover from a previous error (catching it for instance).
656
- def recover
657
- @success = true
658
- end
659
-
660
- # Print text on the console.
661
- # - text: text to print.
662
- def print(text)
663
- Kernel.print(text)
664
- end
665
-
666
- # Puts text on the console.
667
- # - text: text to puts.
668
- def puts(text)
669
- Kernel.puts(text)
670
- end
671
-
672
- # Get input string.
673
- # Return string entered by the user.
674
- def gets
675
- return STDIN.gets
676
- end
677
-
678
- private
679
-
680
- # Compute build duration and print it if verbose.
681
- def duration
682
- @end_time = Time.now
683
- @duration = @end_time - @start_time
684
- @duration = (@duration * 1000).round / 1000
685
- puts "Built in #{@duration} s" if @verbose or @duration >= AUTO_DURATION
686
- end
687
-
688
- end
689
-
690
269
  end
691
270
 
692
271
  end