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.
- data.tar.gz.sig +0 -0
- data/History.txt +28 -1
- data/Manifest.txt +91 -52
- data/README.txt +63 -0
- data/Rakefile +20 -23
- data/bin/build-tool +53 -0
- data/lib/build-tool.rb +7 -0
- data/lib/build-tool/GUI.rb +360 -0
- data/lib/build-tool/application.rb +84 -0
- data/lib/build-tool/build-system/autoconf.rb +60 -0
- data/lib/build-tool/build-system/base.rb +142 -0
- data/lib/build-tool/build-system/cmake.rb +119 -0
- data/lib/build-tool/build-system/custom.rb +115 -0
- data/lib/build-tool/build-system/qt.rb +113 -0
- data/lib/build-tool/cfg/lexer.rb +558 -0
- data/lib/build-tool/cfg/lexer.rex +248 -0
- data/lib/build-tool/cfg/lexer_base.rb +82 -0
- data/lib/build-tool/cfg/node.rb +94 -0
- data/lib/build-tool/cfg/parser.rb +871 -0
- data/lib/build-tool/cfg/parser.y +279 -0
- data/lib/build-tool/cfg/visitor.rb +471 -0
- data/lib/build-tool/commands.rb +639 -0
- data/lib/build-tool/commands/build.rb +120 -0
- data/lib/build-tool/commands/configure.rb +73 -0
- data/lib/build-tool/commands/ctags.rb +46 -0
- data/lib/build-tool/commands/environments.rb +29 -0
- data/lib/build-tool/commands/environments/list.rb +37 -0
- data/lib/build-tool/commands/environments/set.rb +33 -0
- data/lib/build-tool/commands/fetch.rb +50 -0
- data/lib/build-tool/commands/files.rb +73 -0
- data/lib/build-tool/commands/help.rb +22 -0
- data/lib/build-tool/commands/info.rb +48 -0
- data/lib/build-tool/commands/install.rb +56 -0
- data/lib/build-tool/commands/modules.rb +29 -0
- data/lib/build-tool/commands/modules/info.rb +75 -0
- data/lib/build-tool/commands/modules/list.rb +49 -0
- data/lib/build-tool/commands/modules/shell.rb +40 -0
- data/lib/build-tool/commands/rebase.rb +46 -0
- data/lib/build-tool/commands/recipes.rb +32 -0
- data/lib/build-tool/commands/recipes/info.rb +46 -0
- data/lib/build-tool/commands/recipes/install.rb +184 -0
- data/lib/build-tool/commands/recipes/list.rb +33 -0
- data/lib/build-tool/configuration.rb +115 -0
- data/lib/build-tool/environment.rb +119 -0
- data/lib/build-tool/errors.rb +9 -0
- data/lib/build-tool/module.rb +366 -0
- data/lib/build-tool/pluginbase.rb +43 -0
- data/lib/build-tool/recipe.rb +180 -0
- data/lib/build-tool/repository.rb +59 -0
- data/lib/build-tool/server.rb +43 -0
- data/lib/build-tool/singleton.rb +50 -0
- data/lib/build-tool/sshkey.rb +22 -0
- data/lib/build-tool/vcs/base.rb +105 -0
- data/lib/build-tool/vcs/git-svn.rb +154 -0
- data/lib/build-tool/vcs/git.rb +187 -0
- data/lib/build-tool/vcs/svn.rb +136 -0
- data/lib/mj/logging.rb +31 -0
- data/lib/mj/tools/ssh.rb +64 -0
- data/lib/{kde-build → mj/tools}/subprocess.rb +21 -16
- data/lib/mj/visitor.rb +21 -0
- data/recipes/kde/files/finish_installation.sh +16 -0
- data/recipes/kde/files/kde4.desktop +22 -0
- data/recipes/kde/files/xsession +89 -0
- data/recipes/kde/info.yaml +10 -0
- data/recipes/kde/recipe +585 -0
- data/recipes/kde/recipe-local +90 -0
- data/recipes/kde/settings.yaml +52 -0
- data/recipes/kde43/info.yaml +10 -0
- data/recipes/kde43/recipe +256 -0
- data/recipes/kde43/recipe-local +90 -0
- data/recipes/kde43/settings.yaml +32 -0
- data/recipes/kdeqt4.6/custom/qt/qtscriptgenerator/compile.sh +77 -0
- data/recipes/kdeqt4.6/custom/qt/qtscriptgenerator/configure.sh +70 -0
- data/recipes/kdeqt4.6/custom/qt/qtscriptgenerator/install.sh +39 -0
- data/recipes/kdeqt4.6/info.yaml +7 -0
- data/recipes/kdeqt4.6/recipe +155 -0
- data/recipes/kdeqt4.6/recipe-local +30 -0
- data/recipes/kdeqt4.6/settings.yaml +27 -0
- data/tags +745 -0
- data/tasks/genfiles.rake +28 -0
- data/tasks/rdoc.rake +34 -0
- data/tasks/rspec.rake +21 -0
- data/test.rb +28 -0
- data/test/commands/test_build.rb +29 -0
- data/test/test_build_system.rb +98 -0
- data/test/test_cli.rb +61 -0
- data/test/test_command.rb +175 -0
- data/test/test_configuration_parser.rb +542 -0
- data/test/test_environment.rb +82 -0
- data/test/test_helper.rb +39 -7
- data/test/test_module.rb +158 -0
- data/test/test_repository.rb +75 -0
- data/test/test_singleton.rb +51 -0
- data/test/test_ssh_key.rb +14 -0
- data/test/test_svn_parser.rb +28 -0
- data/test/test_vcs.rb +33 -0
- metadata +139 -90
- metadata.gz.sig +0 -0
- data/PostInstall.txt +0 -3
- data/TODO +0 -2
- data/bin/kde-build.rb +0 -21
- data/config/website.yml +0 -2
- data/config/website.yml.sample +0 -2
- data/lib/kde-build.rb +0 -18
- data/lib/kde-build/application.rb +0 -270
- data/lib/kde-build/build_system.rb +0 -28
- data/lib/kde-build/build_system/autoconf.rb +0 -108
- data/lib/kde-build/build_system/base.rb +0 -139
- data/lib/kde-build/build_system/cmake.rb +0 -94
- data/lib/kde-build/build_system/qtcopy.rb +0 -127
- data/lib/kde-build/command.rb +0 -42
- data/lib/kde-build/command/build.rb +0 -106
- data/lib/kde-build/command/compile.rb +0 -39
- data/lib/kde-build/command/configure.rb +0 -48
- data/lib/kde-build/command/ctags.rb +0 -41
- data/lib/kde-build/command/fetch.rb +0 -33
- data/lib/kde-build/command/help.rb +0 -71
- data/lib/kde-build/command/info.rb +0 -45
- data/lib/kde-build/command/install.rb +0 -39
- data/lib/kde-build/command/module_based.rb +0 -44
- data/lib/kde-build/command/rebase.rb +0 -50
- data/lib/kde-build/command/version.rb +0 -43
- data/lib/kde-build/configuration.rb +0 -209
- data/lib/kde-build/exception.rb +0 -6
- data/lib/kde-build/metaaid.rb +0 -18
- data/lib/kde-build/module.rb +0 -227
- data/lib/kde-build/module_configuration.rb +0 -107
- data/lib/kde-build/moduleregistry.rb +0 -85
- data/lib/kde-build/tools/ctags.rb +0 -59
- data/lib/kde-build/tools/logging.rb +0 -49
- data/lib/kde-build/tools/make.rb +0 -58
- data/lib/kde-build/tools/ssh.rb +0 -47
- data/lib/kde-build/vcs.rb +0 -28
- data/lib/kde-build/vcs/base.rb +0 -85
- data/lib/kde-build/vcs/git-svn.rb +0 -139
- data/lib/kde-build/vcs/git.rb +0 -121
- data/lib/kde-build/vcs/svn.rb +0 -102
- data/script/console +0 -10
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/txt2html +0 -71
- data/test.yaml.tmpl +0 -632
- data/test/test_kde-build.rb +0 -11
- data/test/test_vcs_svn.rb +0 -44
- data/website/index.html +0 -84
- data/website/index.txt +0 -59
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -159
- 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
|
+
|