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.
@@ -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