detroit 0.3.0 → 0.4.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.
- checksums.yaml +7 -0
- data/.index +59 -0
- data/EXAMPLE.md +66 -64
- data/{HISTORY.rdoc → HISTORY.md} +32 -5
- data/{COPYING.rdoc → LICENSE.txt} +0 -0
- data/README.md +142 -0
- data/bin/detroit +1 -1
- data/lib/detroit.rb +112 -40
- data/lib/detroit.yml +44 -29
- data/lib/detroit/assembly.rb +49 -193
- data/lib/detroit/basic_tool.rb +200 -0
- data/lib/detroit/basic_utils.rb +66 -0
- data/lib/detroit/core_ext.rb +2 -136
- data/lib/detroit/{tool/core_ext → core_ext}/facets.rb +3 -0
- data/lib/detroit/{tool/core_ext → core_ext}/filetest.rb +0 -0
- data/lib/detroit/{tool/core_ext → core_ext}/shell_extensions.rb +0 -0
- data/lib/detroit/{tool/core_ext → core_ext}/to_actual_filename.rb +0 -0
- data/lib/detroit/{tool/core_ext → core_ext}/to_console.rb +1 -0
- data/lib/detroit/{tool/core_ext → core_ext}/to_list.rb +0 -0
- data/lib/detroit/{tool/core_ext → core_ext}/to_yamlfrag.rb +0 -0
- data/lib/detroit/{tool/core_ext → core_ext}/unfold_paragraphs.rb +0 -0
- data/lib/detroit/{tool/email_utils.rb → email_utils.rb} +3 -1
- data/lib/detroit/exec.rb +55 -0
- data/lib/detroit/project.rb +134 -0
- data/lib/detroit/ruby_utils.rb +29 -0
- data/lib/detroit/{tool/shell_utils.rb → shell_utils.rb} +10 -5
- data/lib/detroit/toolchain.rb +6 -0
- data/lib/detroit/toolchain/cli.rb +320 -0
- data/lib/detroit/toolchain/config.rb +223 -0
- data/lib/detroit/toolchain/runner.rb +678 -0
- data/lib/detroit/toolchain/script.rb +248 -0
- data/lib/detroit/toolchain/worker.rb +84 -0
- data/man/detroit.1 +116 -0
- data/man/detroit.1.html +171 -0
- data/man/detroit.1.ronn +99 -0
- metadata +90 -51
- data/.ruby +0 -44
- data/README.rdoc +0 -132
- data/lib/detroit/application.rb +0 -463
- data/lib/detroit/assembly_system.rb +0 -80
- data/lib/detroit/config.rb +0 -203
- data/lib/detroit/control.rb +0 -129
- data/lib/detroit/custom.rb +0 -102
- data/lib/detroit/dsl.rb +0 -55
- data/lib/detroit/service.rb +0 -78
- data/lib/detroit/standard_assembly.rb +0 -51
- data/lib/detroit/tool.rb +0 -295
- data/lib/detroit/tool/core_ext.rb +0 -3
- data/lib/detroit/tool/project_utils.rb +0 -41
data/lib/detroit/application.rb
DELETED
@@ -1,463 +0,0 @@
|
|
1
|
-
module Detroit
|
2
|
-
|
3
|
-
# The default assembly system to use.
|
4
|
-
DEFAULT_ASSEMBLY_SYSTEM = :standard
|
5
|
-
|
6
|
-
# Application class is the main controller class for running
|
7
|
-
# a session of Detroit.
|
8
|
-
#--
|
9
|
-
# TODO: Rename Application to `Session`?
|
10
|
-
#++
|
11
|
-
class Application
|
12
|
-
|
13
|
-
# Options (generally from #cli).
|
14
|
-
attr :options
|
15
|
-
|
16
|
-
# Create a new Detroit Application instance.
|
17
|
-
def initialize(options)
|
18
|
-
@options = options
|
19
|
-
#load_standard_plugins
|
20
|
-
|
21
|
-
self.skip = options[:skip]
|
22
|
-
self.quiet = options[:quiet]
|
23
|
-
self.system = options[:system]
|
24
|
-
self.multitask = options[:multitask]
|
25
|
-
self.assemblies = options[:assemblies]
|
26
|
-
end
|
27
|
-
|
28
|
-
# Quiet mode?
|
29
|
-
def quiet?
|
30
|
-
@quiet
|
31
|
-
end
|
32
|
-
|
33
|
-
# Set quiet mode.
|
34
|
-
def quiet=(boolean)
|
35
|
-
@quiet = !!boolean
|
36
|
-
end
|
37
|
-
|
38
|
-
# List of service names to skip.
|
39
|
-
def skip
|
40
|
-
@skip
|
41
|
-
end
|
42
|
-
|
43
|
-
# Set skip list.
|
44
|
-
def skip=(list)
|
45
|
-
@skip = list.to_list.map{ |s| s.downcase }
|
46
|
-
end
|
47
|
-
|
48
|
-
# The selected assembly system.
|
49
|
-
def system
|
50
|
-
@system
|
51
|
-
end
|
52
|
-
|
53
|
-
# Set assembly system to use.
|
54
|
-
def system=(name)
|
55
|
-
@system = (name || DEFAULT_ASSEMBLY_SYSTEM)
|
56
|
-
end
|
57
|
-
|
58
|
-
# Alias for #system.
|
59
|
-
alias :assembly_system :system
|
60
|
-
|
61
|
-
# Multitask mode?
|
62
|
-
def multitask?
|
63
|
-
@multitask
|
64
|
-
end
|
65
|
-
|
66
|
-
# Set multi-task mode.
|
67
|
-
def multitask=(boolean)
|
68
|
-
if boolean && !defined?(Parallel)
|
69
|
-
puts "Parallel gem must be installed to multitask."
|
70
|
-
@multitask = false
|
71
|
-
else
|
72
|
-
@multitask = boolean
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# List of assembly files to use.
|
77
|
-
def assemblies
|
78
|
-
@assemblies
|
79
|
-
end
|
80
|
-
|
81
|
-
#
|
82
|
-
def assemblies=(files)
|
83
|
-
@assemblies = files
|
84
|
-
end
|
85
|
-
|
86
|
-
# Detroit configuration.
|
87
|
-
def config
|
88
|
-
@config ||= Detroit::Config.new(assemblies)
|
89
|
-
end
|
90
|
-
|
91
|
-
# Provides access to the Project instance via `Detroit.project` class method.
|
92
|
-
def project
|
93
|
-
@project ||= POM::Project.find
|
94
|
-
end
|
95
|
-
|
96
|
-
# User-defined service defaults.
|
97
|
-
#
|
98
|
-
# Returns Hash of service defaults.
|
99
|
-
def defaults
|
100
|
-
config.defaults
|
101
|
-
end
|
102
|
-
|
103
|
-
# # Load standard plugins.
|
104
|
-
# def load_standard_plugins
|
105
|
-
# #::Plugin.find("detroit/*.rb").each do |file|
|
106
|
-
# Detroit.standard_plugins.each do |file|
|
107
|
-
# begin
|
108
|
-
# require(file)
|
109
|
-
# rescue => err
|
110
|
-
# $stderr.puts err if $DEBUG
|
111
|
-
# end
|
112
|
-
# end
|
113
|
-
# end
|
114
|
-
|
115
|
-
# Display detailed help for a given tool.
|
116
|
-
def display_help(name)
|
117
|
-
if not Detroit.tools.key?(name)
|
118
|
-
config.load_plugin(name)
|
119
|
-
end
|
120
|
-
tool = Detroit.tools[name]
|
121
|
-
if tool.respond_to?(:man_page)
|
122
|
-
Kernel.system "man #{tool.man_page}"
|
123
|
-
else
|
124
|
-
puts "Sorry, no detailed help available for `#{name}'."
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
# Generates a configuration template for particular tool.
|
129
|
-
# This is only used for reference purposes.
|
130
|
-
def config_template(name)
|
131
|
-
if not Detroit.tools.key?(name)
|
132
|
-
config.load_plugin(name)
|
133
|
-
end
|
134
|
-
list = {name => Detroit.tools[name]}
|
135
|
-
cfg = {}
|
136
|
-
list.each do |srv_name, srv_class|
|
137
|
-
attrs = srv_class.options #instance_methods.select{ |m| m.to_s =~ /\w+=$/ && !%w{taguri=}.include?(m.to_s) }
|
138
|
-
atcfg = attrs.inject({}){ |h, m| h[m.to_s.chomp('=')] = nil; h }
|
139
|
-
atcfg['service'] = srv_class.basename.downcase
|
140
|
-
atcfg['active'] = false
|
141
|
-
cfg[srv_name] = atcfg
|
142
|
-
end
|
143
|
-
cfg
|
144
|
-
end
|
145
|
-
|
146
|
-
# TODO: Setup all services, then ween out inactive ones?
|
147
|
-
#def services
|
148
|
-
#end
|
149
|
-
|
150
|
-
# Active services are services defined in assembly files and do not
|
151
|
-
# have their active setting turned off.
|
152
|
-
#
|
153
|
-
# Returns Array of active services.
|
154
|
-
def active_services
|
155
|
-
@active_services ||= (
|
156
|
-
list = []
|
157
|
-
|
158
|
-
config.each do |key, opts|
|
159
|
-
next unless opts
|
160
|
-
next unless opts['active'] != false
|
161
|
-
next if skip.include?(key.to_s)
|
162
|
-
|
163
|
-
tool_name = (
|
164
|
-
opts.delete('tool') ||
|
165
|
-
opts.delete('service') ||
|
166
|
-
key
|
167
|
-
).to_s.downcase
|
168
|
-
|
169
|
-
unless Detroit.tools.key?(tool_name)
|
170
|
-
config.load_plugin(tool_name)
|
171
|
-
end
|
172
|
-
|
173
|
-
tool_class = Detroit.tools[tool_name]
|
174
|
-
|
175
|
-
abort "Unknown tool `#{tool_name}'." unless tool_class
|
176
|
-
|
177
|
-
if tool_class.available? #(project)
|
178
|
-
#opts = inject_environment(opts) # TODO: DEPRECATE
|
179
|
-
options = defaults[tool_name.downcase].to_h
|
180
|
-
options = options.merge(common_tool_options)
|
181
|
-
options = options.merge(opts)
|
182
|
-
|
183
|
-
list << Service.new(key, tool_class, options) #script,
|
184
|
-
#else
|
185
|
-
# warn "Service #{tool_class} is not available."
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
# sorting here trickles down to processing later
|
190
|
-
#list = list.sort_by{ |s| s.priority || 0 }
|
191
|
-
|
192
|
-
list
|
193
|
-
)
|
194
|
-
end
|
195
|
-
|
196
|
-
# Change direectory to project root and run.
|
197
|
-
def start(stop)
|
198
|
-
Dir.chdir(project.root) do # change into project directory
|
199
|
-
run(stop)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
# Run up to the specified +track_and_stop+.
|
204
|
-
def run(track_and_stop)
|
205
|
-
raise "Malformed destination -- #{track_and_stop}" unless /^\w+\:{0,1}\w+$/ =~ track_and_stop
|
206
|
-
|
207
|
-
if track_and_stop
|
208
|
-
name, stop = track_and_stop.split(':')
|
209
|
-
name, stop = 'main', name unless stop
|
210
|
-
else
|
211
|
-
name = 'main'
|
212
|
-
stop = nil
|
213
|
-
end
|
214
|
-
|
215
|
-
name = name.to_sym
|
216
|
-
stop = stop.to_sym if stop
|
217
|
-
|
218
|
-
assm = Detroit.assembly_systems[system]
|
219
|
-
|
220
|
-
raise "Unkown assembly system `#{system}'" unless assm
|
221
|
-
|
222
|
-
track = assm.get_track(name, stop)
|
223
|
-
|
224
|
-
#if stop
|
225
|
-
# system = track.route_with_stop(stop)
|
226
|
-
# raise "Unknown stop -- #{stop}" unless system
|
227
|
-
|
228
|
-
if not track.include?(stop)
|
229
|
-
#overview
|
230
|
-
$stderr.puts "Unknown stop for track `#{name}'."
|
231
|
-
exit 0
|
232
|
-
end
|
233
|
-
|
234
|
-
@destination = stop
|
235
|
-
|
236
|
-
# TODO: Using #preconfigure as part of the protocol should probably change.
|
237
|
-
|
238
|
-
# prime the services (so as to fail early)
|
239
|
-
active_services.each do |srv|
|
240
|
-
srv.preconfigure if srv.respond_to?("preconfigure")
|
241
|
-
end
|
242
|
-
|
243
|
-
status_header(*header_message)
|
244
|
-
|
245
|
-
start_time = Time.now
|
246
|
-
|
247
|
-
track.each do |run_stop|
|
248
|
-
next if skip.include?("#{run_stop}") # TODO: Should we really allow skipping stops?
|
249
|
-
service_hooks(name, ('pre_' + run_stop.to_s).to_sym)
|
250
|
-
service_calls(name, ('pre_' + run_stop.to_s).to_sym)
|
251
|
-
service_calls(name, run_stop)
|
252
|
-
service_calls(name, ('aft_' + run_stop.to_s).to_sym)
|
253
|
-
service_hooks(name, ('aft_' + run_stop.to_s).to_sym)
|
254
|
-
break if stop == run_stop
|
255
|
-
end
|
256
|
-
|
257
|
-
stop_time = Time.now
|
258
|
-
puts "\nFinished in #{stop_time - start_time} seconds." unless quiet?
|
259
|
-
end
|
260
|
-
|
261
|
-
# TODO: Deprecate service hooks?
|
262
|
-
|
263
|
-
#
|
264
|
-
# Execute service hook for given track and destination.
|
265
|
-
#
|
266
|
-
# @todo Currently only stop counts, maybe add track subdirs.
|
267
|
-
#
|
268
|
-
def service_hooks(track, stop)
|
269
|
-
#hook = dir + ("#{track}/#{stop}.rb".gsub('_', '-'))
|
270
|
-
dir = hook_directory
|
271
|
-
return unless dir
|
272
|
-
name = stop.to_s.gsub('_', '-')
|
273
|
-
hook = dir + "#{name}.rb"
|
274
|
-
if hook.exist?
|
275
|
-
status_line("hook", name.capitalize)
|
276
|
-
hook_tool.instance_eval(hook.read)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
# Returns a project's Detroit hooks directory.
|
281
|
-
def hook_directory
|
282
|
-
project.root.glob("{.,}detroit/hooks").first
|
283
|
-
end
|
284
|
-
|
285
|
-
#
|
286
|
-
def hook_tool
|
287
|
-
@hook_tool ||= Tool.new(common_tool_options)
|
288
|
-
end
|
289
|
-
|
290
|
-
# TODO: Do we need verbose?
|
291
|
-
def common_tool_options
|
292
|
-
{
|
293
|
-
'project' => project,
|
294
|
-
'trial' => options[:trial],
|
295
|
-
'trace' => options[:trace],
|
296
|
-
'quiet' => options[:quiet],
|
297
|
-
'force' => options[:force],
|
298
|
-
'verbose' => options[:verbose]
|
299
|
-
}
|
300
|
-
end
|
301
|
-
|
302
|
-
# Make service calls.
|
303
|
-
#
|
304
|
-
# This groups services by priority b/c groups of the same priority can be run
|
305
|
-
# in parallel if the multitask option is on.
|
306
|
-
def service_calls(track, stop)
|
307
|
-
prioritized_services = active_services.group_by{ |srv| srv.priority }.sort_by{ |k,v| k }
|
308
|
-
prioritized_services.each do |priority, services|
|
309
|
-
## remove any services specified by the --skip option on the comamndline
|
310
|
-
#services = services.reject{ |srv| skip.include?(srv.key.to_s) }
|
311
|
-
## only servies that are on the track
|
312
|
-
services = services.select{ |srv| srv.tracks.nil? or srv.tracks.include?(track.to_s) }
|
313
|
-
|
314
|
-
tasklist = services.map{ |srv| [srv, track, stop] }
|
315
|
-
if multitask?
|
316
|
-
results = Parallel.in_processes(tasklist.size) do |i|
|
317
|
-
run_a_service(*tasklist[i])
|
318
|
-
end
|
319
|
-
else
|
320
|
-
tasklist.each do |args|
|
321
|
-
run_a_service(*args)
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
#
|
328
|
-
# Run a service given the service, track and stop name.
|
329
|
-
#
|
330
|
-
def run_a_service(srv, track, stop)
|
331
|
-
# run if the service supports the track and stop.
|
332
|
-
#if srv.respond_to?("#{track}_#{stop}")
|
333
|
-
if srv.stop?(stop, @destination)
|
334
|
-
if options[:trace] #options[:verbose]
|
335
|
-
#status_line("#{srv.key.to_s} (#{srv.class}##{track}_#{stop})", stop.to_s.gsub('_', '-').capitalize)
|
336
|
-
status_line("#{srv.key.to_s} (#{srv.class}##{stop})", stop.to_s.gsub('_', '-').capitalize)
|
337
|
-
else
|
338
|
-
status_line("#{srv.key.to_s}", stop.to_s.gsub('_', '-').capitalize)
|
339
|
-
end
|
340
|
-
#srv.__send__("#{track}_#{stop}")
|
341
|
-
srv.invoke(stop, @destination)
|
342
|
-
end
|
343
|
-
end
|
344
|
-
|
345
|
-
# --- Print Methods -------------------------------------------------------
|
346
|
-
|
347
|
-
def header_message
|
348
|
-
if multitask?
|
349
|
-
["#{project.metadata.title} v#{project.metadata.version} [M]", "#{project.root}"]
|
350
|
-
else
|
351
|
-
["#{project.metadata.title} v#{project.metadata.version}", "#{project.root}"]
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
# Print a status header, which consists of project name and version on the
|
356
|
-
# left and stop location on the right.
|
357
|
-
#
|
358
|
-
def status_header(left, right='')
|
359
|
-
left, right = left.to_s, right.to_s
|
360
|
-
#left.color = 'blue'
|
361
|
-
#right.color = 'magenta'
|
362
|
-
unless quiet?
|
363
|
-
puts
|
364
|
-
print_header(left, right)
|
365
|
-
#puts "=" * io.screen_width
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
# Print a status line, which consists of service name on the left
|
370
|
-
# and stop name on the right.
|
371
|
-
#
|
372
|
-
def status_line(left, right='')
|
373
|
-
left, right = left.to_s, right.to_s
|
374
|
-
#left.color = 'blue'
|
375
|
-
#right.color = 'magenta'
|
376
|
-
unless quiet?
|
377
|
-
puts
|
378
|
-
#puts "-" * io.screen_width
|
379
|
-
print_phase(left, right)
|
380
|
-
#puts "-" * io.screen_width
|
381
|
-
#puts
|
382
|
-
end
|
383
|
-
end
|
384
|
-
|
385
|
-
#
|
386
|
-
def display_action(action_item)
|
387
|
-
phase, service, action, parameters = *action_item
|
388
|
-
puts " %-10s %-10s %-10s" % [phase.to_s.capitalize, service.service_title, action]
|
389
|
-
#status_line(service.service_title, phase.to_s.capitalize)
|
390
|
-
end
|
391
|
-
|
392
|
-
#
|
393
|
-
def print_header(left, right)
|
394
|
-
if $ansi #ANSI::SUPPORTED
|
395
|
-
printline('', '', :pad=>1, :sep=>' ', :style=>[:negative, :bold], :left=>[:bold], :right=>[:bold])
|
396
|
-
printline(left, right, :pad=>2, :sep=>' ', :style=>[:negative, :bold], :left=>[:bold], :right=>[:bold])
|
397
|
-
printline('', '', :pad=>1, :sep=>' ', :style=>[:negative, :bold], :left=>[:bold], :right=>[:bold])
|
398
|
-
else
|
399
|
-
printline(left, right, :pad=>2, :sep=>'=')
|
400
|
-
end
|
401
|
-
end
|
402
|
-
|
403
|
-
#
|
404
|
-
def print_phase(left, right)
|
405
|
-
if $ansi #ANSI::SUPPORTED
|
406
|
-
printline(left, right, :pad=>2, :sep=>' ', :style=>[:on_white, :black, :bold], :left=>[:bold], :right=>[:bold])
|
407
|
-
else
|
408
|
-
printline(left, right, :pad=>2, :sep=>'-')
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
|
-
#
|
413
|
-
def printline(left, right='', options={})
|
414
|
-
return if quiet?
|
415
|
-
|
416
|
-
separator = options[:seperator] || options[:sep] || ' '
|
417
|
-
padding = options[:padding] || options[:pad] || 0
|
418
|
-
|
419
|
-
left, right = left.to_s, right.to_s
|
420
|
-
|
421
|
-
left_size = left.size
|
422
|
-
right_size = right.size
|
423
|
-
|
424
|
-
#left = colorize(left)
|
425
|
-
#right = colorize(right)
|
426
|
-
|
427
|
-
l = padding
|
428
|
-
r = -(right_size + padding)
|
429
|
-
|
430
|
-
style = options[:style] || []
|
431
|
-
lstyle = options[:left] || []
|
432
|
-
rstyle = options[:right] || []
|
433
|
-
|
434
|
-
left = lstyle.inject(left) { |s, c| ansize(s, c) }
|
435
|
-
right = rstyle.inject(right){ |s, c| ansize(s, c) }
|
436
|
-
|
437
|
-
line = separator * screen_width
|
438
|
-
line[l, left_size] = left if left_size != 0
|
439
|
-
line[r, right_size] = right if right_size != 0
|
440
|
-
|
441
|
-
line = style.inject(line){ |s, c| ansize(s, c) }
|
442
|
-
|
443
|
-
puts line + ansize('', :clear)
|
444
|
-
end
|
445
|
-
|
446
|
-
#
|
447
|
-
def ansize(text, code)
|
448
|
-
#return text unless text.color
|
449
|
-
if RUBY_PLATFORM =~ /win/
|
450
|
-
text.to_s
|
451
|
-
else
|
452
|
-
ANSI::Code.send(code.to_sym) + text
|
453
|
-
end
|
454
|
-
end
|
455
|
-
|
456
|
-
#
|
457
|
-
def screen_width
|
458
|
-
ANSI::Terminal.terminal_width
|
459
|
-
end
|
460
|
-
|
461
|
-
end
|
462
|
-
|
463
|
-
end #module Detroit
|