build-tool 0.0.3 → 0.1.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.
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
+