build-tool 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +28 -1
  3. data/Manifest.txt +91 -52
  4. data/README.txt +63 -0
  5. data/Rakefile +20 -23
  6. data/bin/build-tool +53 -0
  7. data/lib/build-tool.rb +7 -0
  8. data/lib/build-tool/GUI.rb +360 -0
  9. data/lib/build-tool/application.rb +84 -0
  10. data/lib/build-tool/build-system/autoconf.rb +60 -0
  11. data/lib/build-tool/build-system/base.rb +142 -0
  12. data/lib/build-tool/build-system/cmake.rb +119 -0
  13. data/lib/build-tool/build-system/custom.rb +115 -0
  14. data/lib/build-tool/build-system/qt.rb +113 -0
  15. data/lib/build-tool/cfg/lexer.rb +558 -0
  16. data/lib/build-tool/cfg/lexer.rex +248 -0
  17. data/lib/build-tool/cfg/lexer_base.rb +82 -0
  18. data/lib/build-tool/cfg/node.rb +94 -0
  19. data/lib/build-tool/cfg/parser.rb +871 -0
  20. data/lib/build-tool/cfg/parser.y +279 -0
  21. data/lib/build-tool/cfg/visitor.rb +471 -0
  22. data/lib/build-tool/commands.rb +639 -0
  23. data/lib/build-tool/commands/build.rb +120 -0
  24. data/lib/build-tool/commands/configure.rb +73 -0
  25. data/lib/build-tool/commands/ctags.rb +46 -0
  26. data/lib/build-tool/commands/environments.rb +29 -0
  27. data/lib/build-tool/commands/environments/list.rb +37 -0
  28. data/lib/build-tool/commands/environments/set.rb +33 -0
  29. data/lib/build-tool/commands/fetch.rb +50 -0
  30. data/lib/build-tool/commands/files.rb +73 -0
  31. data/lib/build-tool/commands/help.rb +22 -0
  32. data/lib/build-tool/commands/info.rb +48 -0
  33. data/lib/build-tool/commands/install.rb +56 -0
  34. data/lib/build-tool/commands/modules.rb +29 -0
  35. data/lib/build-tool/commands/modules/info.rb +75 -0
  36. data/lib/build-tool/commands/modules/list.rb +49 -0
  37. data/lib/build-tool/commands/modules/shell.rb +40 -0
  38. data/lib/build-tool/commands/rebase.rb +46 -0
  39. data/lib/build-tool/commands/recipes.rb +32 -0
  40. data/lib/build-tool/commands/recipes/info.rb +46 -0
  41. data/lib/build-tool/commands/recipes/install.rb +184 -0
  42. data/lib/build-tool/commands/recipes/list.rb +33 -0
  43. data/lib/build-tool/configuration.rb +115 -0
  44. data/lib/build-tool/environment.rb +119 -0
  45. data/lib/build-tool/errors.rb +9 -0
  46. data/lib/build-tool/module.rb +366 -0
  47. data/lib/build-tool/pluginbase.rb +43 -0
  48. data/lib/build-tool/recipe.rb +180 -0
  49. data/lib/build-tool/repository.rb +59 -0
  50. data/lib/build-tool/server.rb +43 -0
  51. data/lib/build-tool/singleton.rb +50 -0
  52. data/lib/build-tool/sshkey.rb +22 -0
  53. data/lib/build-tool/vcs/base.rb +105 -0
  54. data/lib/build-tool/vcs/git-svn.rb +154 -0
  55. data/lib/build-tool/vcs/git.rb +187 -0
  56. data/lib/build-tool/vcs/svn.rb +136 -0
  57. data/lib/mj/logging.rb +31 -0
  58. data/lib/mj/tools/ssh.rb +64 -0
  59. data/lib/{kde-build → mj/tools}/subprocess.rb +21 -16
  60. data/lib/mj/visitor.rb +21 -0
  61. data/recipes/kde/files/finish_installation.sh +16 -0
  62. data/recipes/kde/files/kde4.desktop +22 -0
  63. data/recipes/kde/files/xsession +89 -0
  64. data/recipes/kde/info.yaml +10 -0
  65. data/recipes/kde/recipe +585 -0
  66. data/recipes/kde/recipe-local +90 -0
  67. data/recipes/kde/settings.yaml +52 -0
  68. data/recipes/kde43/info.yaml +10 -0
  69. data/recipes/kde43/recipe +256 -0
  70. data/recipes/kde43/recipe-local +90 -0
  71. data/recipes/kde43/settings.yaml +32 -0
  72. data/recipes/kdeqt4.6/custom/qt/qtscriptgenerator/compile.sh +77 -0
  73. data/recipes/kdeqt4.6/custom/qt/qtscriptgenerator/configure.sh +70 -0
  74. data/recipes/kdeqt4.6/custom/qt/qtscriptgenerator/install.sh +39 -0
  75. data/recipes/kdeqt4.6/info.yaml +7 -0
  76. data/recipes/kdeqt4.6/recipe +155 -0
  77. data/recipes/kdeqt4.6/recipe-local +30 -0
  78. data/recipes/kdeqt4.6/settings.yaml +27 -0
  79. data/tags +745 -0
  80. data/tasks/genfiles.rake +28 -0
  81. data/tasks/rdoc.rake +34 -0
  82. data/tasks/rspec.rake +21 -0
  83. data/test.rb +28 -0
  84. data/test/commands/test_build.rb +29 -0
  85. data/test/test_build_system.rb +98 -0
  86. data/test/test_cli.rb +61 -0
  87. data/test/test_command.rb +175 -0
  88. data/test/test_configuration_parser.rb +542 -0
  89. data/test/test_environment.rb +82 -0
  90. data/test/test_helper.rb +39 -7
  91. data/test/test_module.rb +158 -0
  92. data/test/test_repository.rb +75 -0
  93. data/test/test_singleton.rb +51 -0
  94. data/test/test_ssh_key.rb +14 -0
  95. data/test/test_svn_parser.rb +28 -0
  96. data/test/test_vcs.rb +33 -0
  97. metadata +139 -90
  98. metadata.gz.sig +0 -0
  99. data/PostInstall.txt +0 -3
  100. data/TODO +0 -2
  101. data/bin/kde-build.rb +0 -21
  102. data/config/website.yml +0 -2
  103. data/config/website.yml.sample +0 -2
  104. data/lib/kde-build.rb +0 -18
  105. data/lib/kde-build/application.rb +0 -270
  106. data/lib/kde-build/build_system.rb +0 -28
  107. data/lib/kde-build/build_system/autoconf.rb +0 -108
  108. data/lib/kde-build/build_system/base.rb +0 -139
  109. data/lib/kde-build/build_system/cmake.rb +0 -94
  110. data/lib/kde-build/build_system/qtcopy.rb +0 -127
  111. data/lib/kde-build/command.rb +0 -42
  112. data/lib/kde-build/command/build.rb +0 -106
  113. data/lib/kde-build/command/compile.rb +0 -39
  114. data/lib/kde-build/command/configure.rb +0 -48
  115. data/lib/kde-build/command/ctags.rb +0 -41
  116. data/lib/kde-build/command/fetch.rb +0 -33
  117. data/lib/kde-build/command/help.rb +0 -71
  118. data/lib/kde-build/command/info.rb +0 -45
  119. data/lib/kde-build/command/install.rb +0 -39
  120. data/lib/kde-build/command/module_based.rb +0 -44
  121. data/lib/kde-build/command/rebase.rb +0 -50
  122. data/lib/kde-build/command/version.rb +0 -43
  123. data/lib/kde-build/configuration.rb +0 -209
  124. data/lib/kde-build/exception.rb +0 -6
  125. data/lib/kde-build/metaaid.rb +0 -18
  126. data/lib/kde-build/module.rb +0 -227
  127. data/lib/kde-build/module_configuration.rb +0 -107
  128. data/lib/kde-build/moduleregistry.rb +0 -85
  129. data/lib/kde-build/tools/ctags.rb +0 -59
  130. data/lib/kde-build/tools/logging.rb +0 -49
  131. data/lib/kde-build/tools/make.rb +0 -58
  132. data/lib/kde-build/tools/ssh.rb +0 -47
  133. data/lib/kde-build/vcs.rb +0 -28
  134. data/lib/kde-build/vcs/base.rb +0 -85
  135. data/lib/kde-build/vcs/git-svn.rb +0 -139
  136. data/lib/kde-build/vcs/git.rb +0 -121
  137. data/lib/kde-build/vcs/svn.rb +0 -102
  138. data/script/console +0 -10
  139. data/script/destroy +0 -14
  140. data/script/generate +0 -14
  141. data/script/txt2html +0 -71
  142. data/test.yaml.tmpl +0 -632
  143. data/test/test_kde-build.rb +0 -11
  144. data/test/test_vcs_svn.rb +0 -44
  145. data/website/index.html +0 -84
  146. data/website/index.txt +0 -59
  147. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  148. data/website/stylesheets/screen.css +0 -159
  149. data/website/template.html.erb +0 -50
@@ -0,0 +1,639 @@
1
+ require "build-tool/singleton"
2
+ require 'build-tool/errors'
3
+ require 'shellwords'
4
+ require 'optparse'
5
+ require 'delegate'
6
+
7
+
8
+ module BuildTool; module Commands;
9
+
10
+ #
11
+ # Mixin which allows defining attribute easily
12
+ #
13
+ module ClassAttribute
14
+
15
+ def def_attribute( *names )
16
+ class_eval do
17
+ names.each do |name|
18
+ define_method( name ) do |*args|
19
+ case args.size
20
+ when 0 then instance_variable_get( "@#{name}" )
21
+ else instance_variable_set( "@#{name}", *args )
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+
31
+ #
32
+ # Module that provides some standard helptext functionality
33
+ #
34
+ module HelpText
35
+
36
+ module ClassMethods
37
+
38
+ extend ClassAttribute
39
+
40
+ def_attribute :name
41
+ def_attribute :description
42
+ def_attribute :cmdalias
43
+
44
+ end
45
+
46
+ def name
47
+ self.class.name
48
+ end
49
+
50
+ def cmdalias
51
+ self.class.cmdalias
52
+ end
53
+
54
+ def description
55
+ self.class.description
56
+ end
57
+
58
+ def self.included( klass )
59
+ klass.extend( ClassMethods )
60
+ end
61
+
62
+ end # module HelpText
63
+
64
+ #
65
+ # Base class for all commands
66
+ #
67
+ class Base
68
+
69
+ class UsageError < BuildTool::Error; end
70
+
71
+ include HelpText
72
+
73
+ attr_reader :options
74
+ attr_reader :parent
75
+
76
+ def initialize(parent = nil)
77
+ @options = OptionParser.new
78
+ @options.set_program_name( name )
79
+ initialize_options
80
+ @skip_command = false
81
+ @parent = parent
82
+ end
83
+
84
+ def applicable?
85
+ true
86
+ end
87
+
88
+ def configuration
89
+ Application::instance.configuration
90
+ end
91
+
92
+ def initialize_options
93
+ end
94
+
95
+ def complete_readline_1_8( string )
96
+ # Readline in 1.8 does not provide all needed information. We have to hand made
97
+ # it ourselves. We get the complete commandline here.
98
+
99
+ # We want the complete commandline in line_buffer
100
+ line_buffer = string
101
+ # An array of completed arguments/options in args
102
+ args = Shellwords.shellwords( line_buffer )
103
+
104
+ # And the string to complete in string. If the last character is a space we
105
+ # complete from that. if not we take the last arg
106
+ if line_buffer.empty? or line_buffer[-1] == 32
107
+ args << ""
108
+ end
109
+
110
+ do_complete_1_8( args )
111
+ end
112
+
113
+ def do_complete_1_8( args )
114
+ # puts "do_complete_1_8( #{args.inspect} )"
115
+ compl = complete_arguments( args )
116
+ if compl.length >= 1
117
+ return compl.collect do |res|
118
+ args.dup[0..-2].push(res).join(" ")
119
+ end
120
+ else
121
+ return []
122
+ end
123
+ end
124
+
125
+ def complete_readline_1_9( string )
126
+ # We have three sources of information (ruby 1.9 only)
127
+ # argument:
128
+ # See Readline::completer_word_break_characters . The part
129
+ # of the command line to complete
130
+ # Readline::line_buffer
131
+ # The complete command line
132
+ # Readline::point
133
+ # The position of the cursor in commandline
134
+ # Ruby 1.9 <start>
135
+ # First check if we have to complete the first shellword (command)
136
+ args = Shellwords.shellwords( string )
137
+
138
+ # And the string to complete in string. If the last character is a space we
139
+ # complete from that. if not we take the last arg
140
+ if string.empty? or string[-1] == 32
141
+ args << ""
142
+ end
143
+
144
+ do_complete_1_9( args )
145
+ end
146
+
147
+ def do_complete_1_9( args )
148
+ return complete_arguments( args )
149
+ end
150
+
151
+ def complete( string )
152
+ if Readline.respond_to? "line_buffer"
153
+ complete_readline_1_9( string )
154
+ else
155
+ complete_readline_1_8( string )
156
+ end
157
+ end
158
+
159
+ def complete_arguments( args )
160
+ res = each_option.collect { |sw|
161
+ sw.long.collect { |long|
162
+ res = []
163
+ long = long.clone
164
+ if long.sub!( '[no-]', 'no-' )
165
+ res << long if long.start_with? args[-1]
166
+ long = long.sub( 'no-', '' )
167
+ end
168
+ res << long if long.start_with? args[-1]
169
+ res
170
+ }
171
+ }
172
+ res.flatten.compact.sort
173
+ end
174
+
175
+ def each_option
176
+ list = options.instance_variable_get( "@stack" )
177
+ if block_given?
178
+ list.each do |l|
179
+ l.list.each do |sw|
180
+ next if sw.is_a? String
181
+ yield sw
182
+ end
183
+ end
184
+ else
185
+ list.collect { |l| l.list.collect { |sw| sw unless sw.is_a? String } }.flatten.compact
186
+ end
187
+ end
188
+
189
+ def do_execute
190
+ raise NotImplementedError, "#{self.class}.do_execute() not implemented"
191
+ end
192
+
193
+ def execute( args )
194
+ @options = OptionParser.new
195
+ @options.set_program_name( name )
196
+
197
+ @parsing = true
198
+ initialize_options
199
+ begin
200
+ realargs = @options.parse( args )
201
+ rescue OptionParser::ParseError => e
202
+ logger.error( "#{e}" )
203
+ @skip_command = true
204
+ end
205
+ @parsing = false
206
+
207
+ if !@skip_command
208
+ begin
209
+ return do_execute( realargs )
210
+ rescue BuildTool::Error => e
211
+ logger.error e.message
212
+ logger.verbose e.backtrace.join("\n")
213
+ end
214
+ end
215
+
216
+ # Either we skipped the command or we catched an exception
217
+ return -1;
218
+ end
219
+
220
+ def show_help( args = [] )
221
+ # Just ignore potential arguments
222
+ say @options.help
223
+ skip_command
224
+ return 0
225
+ end
226
+
227
+ # During option parsing use this method to tell the class to not
228
+ # execute the command
229
+ def skip_command
230
+ @skip_command = true
231
+ end
232
+
233
+ def say( *args )
234
+ logger.info( *args )
235
+ end
236
+
237
+ def usage( error )
238
+ logger.error error
239
+ show_help
240
+ return -2
241
+ end
242
+
243
+ end # class Base
244
+
245
+
246
+ class Alias < SimpleDelegator
247
+
248
+ attr_reader :name
249
+ def initialize( alternate, cmd )
250
+ super( cmd )
251
+ @name = alternate
252
+ @cmd = cmd
253
+ end
254
+
255
+ end
256
+
257
+
258
+ class Standard < Base
259
+
260
+ def initialize_options
261
+ options.separator "Common options"
262
+
263
+ options.on( "-v", "--verbose", "Enable verbose output" ) do
264
+ Logging.appenders['stdout'].level = [ Logging.appenders['stdout'].level-1, 0 ].max
265
+ end
266
+
267
+ options.on( nil, "--dry-run", "Enable dry run." ) do
268
+ $noop = true
269
+ end
270
+
271
+ options.on( "-h", "--help", "Show this help text" ) do
272
+ show_help
273
+ end
274
+ end
275
+
276
+ def complete_modules( name, all = false )
277
+ res = []
278
+ found = false
279
+ configuration.modules.each do |mod|
280
+ next if ( !all and mod.is_template? )
281
+ # We match on the following conditions:
282
+ # 1. name = mod.name
283
+ # 2. name/ matches beginning of mod.name
284
+ # 3. name starts with ":". Look for package instead of
285
+ # module
286
+ if name.end_with?('/') and mod.name.start_with? name
287
+ res << mod
288
+ found = true
289
+ elsif mod.name == name
290
+ res << mod
291
+ found = true
292
+ end
293
+ end
294
+ raise UsageError, "Unknown module/package #{name}" if !found
295
+ return res
296
+ end
297
+
298
+ def while_logging_to( dir, fname, level, &block )
299
+ got_exception = false
300
+ dirname = @log_directory
301
+ dirname = "#{@log_directory}/#{dir}" if dir
302
+ FileUtils.mkdir_p( dirname )
303
+ Logging.logger['root'].add_appenders(
304
+ Logging.appenders.file(
305
+ fname,
306
+ :filename => dirname + '/' + fname,
307
+ :layout => Logging::Layouts::Pattern.new( :pattern => '%m\n' ),
308
+ :level => level ))
309
+
310
+ begin
311
+ yield
312
+ rescue Interrupt => e
313
+ logger.error "User Interrupt!"
314
+ rescue Exception => e
315
+ logger.error "#{e.class}:#{e.message}"
316
+ got_exception = true
317
+ raise e
318
+ ensure
319
+ Logging.logger['root'].remove_appenders( fname )
320
+ logger.info("More information in #{dirname}/#{fname}") if got_exception
321
+ end
322
+ end
323
+
324
+ def initialize_log_directory
325
+ logdir = configuration.log_directory
326
+
327
+ # Ensure the base log directory exists
328
+ if !File.exist? "#{logdir}"
329
+ FileUtils.mkdir_p "#{logdir}"
330
+ end
331
+
332
+ i = -1
333
+
334
+ begin
335
+ @log_directory = "#{logdir}/#{Date.today.to_s}-%02d" % i+=1
336
+ end until !File.exist?( @log_directory )
337
+
338
+ FileUtils.mkdir_p( @log_directory )
339
+ FileUtils.rm_f( "#{logdir}/latest" )
340
+ FileUtils.ln_sf( @log_directory, "#{logdir}/latest" )
341
+ end
342
+
343
+ end # class Standard
344
+
345
+ class ModuleBasedCommand < Standard
346
+
347
+ def is_module_ready?( mod )
348
+ true
349
+ end
350
+
351
+ def do_execute( args )
352
+
353
+ if args.length == 0
354
+ # *TODO* print better message
355
+ return usage( "Not enough arguments." )
356
+ end
357
+
358
+ # 1. Resolve the modules
359
+ modules = []
360
+ args.each do |arg|
361
+ complete_modules( arg ).each do |mod|
362
+ modules << mod
363
+ end
364
+ end
365
+
366
+ # 2. Check prerequisites
367
+ isready = true
368
+ modules.each do |mod|
369
+ isready &= is_module_ready?( mod )
370
+ end
371
+
372
+ if !isready
373
+ logger.error "Found problems. Exiting"
374
+ return -1
375
+ end
376
+
377
+ # 3. Let's go
378
+ initialize_log_directory
379
+
380
+ rc = 0 # Our return code.
381
+
382
+ while_logging_to nil, 'build-status', :info do
383
+
384
+ modules.each do |mod|
385
+
386
+ begin
387
+ logger.info ""
388
+ logger.info "#### Module #{mod.name}"
389
+ do_execute_module( mod )
390
+ rescue Interrupt => e
391
+ raise e
392
+ rescue BuildTool::Error => e
393
+ logger.error e.message
394
+ logger.verbose e.backtrace.join("\n")
395
+ rc = -1
396
+ rescue Exception => e
397
+ logger.error "#{e.class}:#{e.message}"
398
+ logger.verbose e.backtrace.join("\n")
399
+ rc = -1
400
+ ensure
401
+ logger.info "#### Module #{mod.name} finished"
402
+ end
403
+ end
404
+
405
+ end
406
+
407
+ return rc;
408
+ end
409
+
410
+ end
411
+
412
+
413
+ #
414
+ # Commands that has subcommands
415
+ #
416
+ class SubCommands < Base
417
+
418
+ def initialize( *args )
419
+ super( *args )
420
+ @commands = []
421
+ end
422
+
423
+ def add_command( cmd )
424
+ logger.trace "#{name}: Adding command #{cmd.name}"
425
+ @commands << cmd
426
+ end
427
+
428
+ def get_command( name )
429
+ partial = Array.new
430
+ @commands.each do |cmd|
431
+ return cmd if cmd.name == name
432
+ partial << cmd if cmd.name.start_with? name
433
+ end
434
+ if partial.length == 1
435
+ return partial[0]
436
+ end
437
+ nil
438
+ end
439
+
440
+ def execute( args )
441
+ # There has to be a subcommand
442
+ if args.length == 0
443
+ return show_help
444
+ end
445
+
446
+ cmd = get_command( args[0] )
447
+ if cmd.nil?
448
+ if self.name
449
+ raise UsageError, "Unknown command #{args[0]} for #{self.name}"
450
+ else
451
+ raise UsageError, "Unknown command #{args[0]}"
452
+ end
453
+ end
454
+ cmd.execute( args[1..-1] )
455
+ end
456
+
457
+ def do_complete_1_8( args )
458
+ # puts "#{self.name}.do_complete_1_8( #{args.inspect}"
459
+ if args.length <= 1
460
+ # There is only one or no argument. We try to complete to a
461
+ # command.
462
+ if subcmd = get_command( args[0] )
463
+ # We have a exact match. If we had to complete to get to
464
+ # the commands return here. If not forward to the command
465
+ if args[0] != subcmd.name
466
+ return [ subcmd.name ]
467
+ else
468
+ return subcmd.do_complete_1_8( [""] ).collect do |res|
469
+ [ subcmd.name ].push(res).join(" ")
470
+ end
471
+ end
472
+ else
473
+ # We have a no exact match. Complete the available
474
+ # commands
475
+ return complete_command( args[0] )
476
+ end
477
+ else
478
+ # At least two arguments are present
479
+ if subcmd = get_command( args[0] )
480
+ # We have a exact match. Forward to that command.
481
+ return subcmd.do_complete_1_8( args[1..-1] ).collect do |res|
482
+ [ subcmd.name ].push(res).join(" ")
483
+ end
484
+ else
485
+ # No exact match. Since there is at least on argument
486
+ # behind the current position just keep the user input
487
+ # intact.
488
+ return []
489
+ end
490
+ end
491
+ end
492
+
493
+ def do_complete_1_9( args )
494
+ # puts "#{self.name}.do_complete_1_9( #{args.inspect} )"
495
+ if args.length <= 1
496
+ if subcmd = get_command( args[0] )
497
+ return subcmd.do_complete_1_9( [""] )
498
+ else
499
+ return complete_command( args[0] )
500
+ end
501
+ else
502
+ if subcmd = get_command( args[0] )
503
+ return subcmd.do_complete_1_9( args[1..-1] )
504
+ else
505
+ return args
506
+ end
507
+ end
508
+ end
509
+
510
+ def complete_command( cmdname )
511
+ # puts "#{self.name}.complete_command( #{cmdname.inspect} )"
512
+ cmds = @commands.collect { |com|
513
+ com.name if com.name.start_with? cmdname
514
+ }.compact
515
+ end
516
+
517
+ def complete_arguments( args, string )
518
+ # args[0] is supposed to contain the command name
519
+ if cmd = get_command( args[0] )
520
+ return cmd.complete_arguments( args, string )
521
+ else
522
+ return []
523
+ end
524
+ end
525
+
526
+ def show_help( args = [] )
527
+ if args.length == 0
528
+ @commands.each do |cmd|
529
+ say "%-20s: %s" % [ cmd.name, cmd.description ]
530
+ end
531
+ else
532
+ if cmd = get_command( args[0] )
533
+ cmd.show_help( args[1..-1] )
534
+ else
535
+ if self.name
536
+ raise UsageError, "Unknown command #{args[0]} for #{self.name}"
537
+ else
538
+ raise UsageError, "Unknown command #{args[0]}"
539
+ end
540
+ end
541
+ end
542
+ return 0
543
+ end
544
+
545
+ def load_commands( path, parentmod )
546
+ # puts "load_commands( #{path}, #{parentmod} )"
547
+ # Load the commands
548
+ Dir[ "#{path}/*.rb" ].each do |mod|
549
+ cmdname = Pathname.new( mod ).basename( '.rb' ).to_s
550
+ load_command( path, parentmod, cmdname )
551
+ end
552
+ end
553
+
554
+ def load_command( path, parentmod, mod )
555
+ # puts "load_command( #{path}, #{parentmod}, #{mod} )"
556
+ load "#{path}/#{mod}.rb"
557
+ self.instance_eval %{
558
+ if #{parentmod}::#{mod.capitalize}.instance_of? ::Module
559
+ cmd = #{parentmod}::#{mod.capitalize}.create( self )
560
+ else
561
+ cmd = #{parentmod}::#{mod.capitalize}.new( self )
562
+ end
563
+ return if !cmd.applicable?
564
+
565
+ if cmd.cmdalias
566
+ parent.add_command( Alias.new( cmd.cmdalias, cmd ) )
567
+ end
568
+ if cmd.is_a?( SubCommands )
569
+ cmd.load_commands( "#{path}/#{mod}", "#{parentmod}::#{mod.capitalize}" )
570
+ end
571
+ add_command( cmd )
572
+ }
573
+ end
574
+
575
+ end # class SubCommands
576
+
577
+
578
+ #
579
+ #
580
+ #
581
+ class Shell < SubCommands
582
+
583
+ name "shell"
584
+
585
+ def execute( args )
586
+ if args.length == 0
587
+ return cli
588
+ end
589
+ super
590
+ end
591
+
592
+ def cli
593
+ require 'readline'
594
+
595
+ Readline.completion_proc = method(:complete)
596
+ if !Readline.respond_to? "line_buffer"
597
+ # 1.8 :(
598
+ Readline.completer_word_break_characters = "\x00"
599
+ end
600
+
601
+ while true
602
+
603
+ begin
604
+
605
+ line = Readline.readline('> ', true)
606
+
607
+ return 0 if line.nil?
608
+
609
+ # Ignore whitespace lines
610
+ next if Shellwords.shellwords( line ).length == 0
611
+
612
+ # Remove duplicate or empty lines from history
613
+ if line =~ /^\s*$/ or Readline::HISTORY.to_a[-2] == line
614
+ Readline::HISTORY.pop
615
+ end
616
+
617
+ # Split the line like bash would do it
618
+ execute Shellwords.shellwords( line )
619
+
620
+ rescue BuildTool::Error => e
621
+ logger.error e.message
622
+ logger.verbose e.backtrace.join("\n")
623
+ rescue StandardError => e
624
+ logger.error e.message
625
+ logger.error e.backtrace.join("\n")
626
+ rescue Interrupt => e
627
+ say "Use CTRL-D for exit!"
628
+ end
629
+
630
+ end
631
+
632
+ return 0
633
+ end
634
+
635
+ end # class Shell
636
+
637
+
638
+ end; end;
639
+