detroit 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +36 -38
- data/COPYING.rdoc +15 -11
- data/HISTORY.rdoc +20 -0
- data/QED.rdoc +87 -0
- data/README.rdoc +5 -5
- data/lib/detroit.rb +6 -9
- data/lib/detroit.yml +36 -38
- data/lib/detroit/application.rb +120 -89
- data/lib/detroit/assembly.rb +194 -55
- data/lib/detroit/assembly_system.rb +80 -0
- data/lib/detroit/config.rb +35 -29
- data/lib/detroit/control.rb +17 -12
- data/lib/detroit/core_ext.rb +0 -2
- data/lib/detroit/custom.rb +21 -6
- data/lib/detroit/service.rb +14 -7
- data/lib/detroit/standard_assembly.rb +5 -6
- data/lib/detroit/tool.rb +51 -36
- data/lib/detroit/tool/email_utils.rb +13 -11
- data/lib/detroit/tool/shell_utils.rb +88 -47
- data/qed/{01_schedule → 01_assembly}/02_initialize.md +0 -0
- metadata +62 -63
- data/lib/detroit/schedule.rb +0 -187
data/lib/detroit/control.rb
CHANGED
@@ -27,14 +27,15 @@ module Detroit
|
|
27
27
|
# Run the command line interface.
|
28
28
|
def cli(*argv)
|
29
29
|
cli_options = {
|
30
|
-
:
|
30
|
+
:system => nil, :assemblies => [],
|
31
31
|
:trace=>nil, :trial=>nil, :debug=>nil, :quiet=>nil, :verbose=>nil,
|
32
32
|
:force=>nil, :multitask=>nil, :skip=>[]
|
33
33
|
}
|
34
34
|
|
35
|
-
cli_usage(cli_options)
|
35
|
+
usage = cli_usage(cli_options)
|
36
|
+
usage.parse!(argv)
|
36
37
|
|
37
|
-
#if /\.
|
38
|
+
#if /\.assembly$/ =~ argv[0]
|
38
39
|
# job = argv[1]
|
39
40
|
# begin
|
40
41
|
# application(cli_options).runscript(argv[0], job)
|
@@ -68,11 +69,11 @@ module Detroit
|
|
68
69
|
options[:skip] << skip
|
69
70
|
end
|
70
71
|
|
71
|
-
usage.on('-
|
72
|
-
options[:
|
72
|
+
usage.on('-s', '--system=NAME', "Select assembly system. Default is `standard'.") do |system|
|
73
|
+
options[:system] = system
|
73
74
|
end
|
74
|
-
usage.on('-
|
75
|
-
options[:
|
75
|
+
usage.on('-a', '--assembly [FILE]', 'Use specific assembly file(s).') do |file|
|
76
|
+
options[:assemblies] << file
|
76
77
|
end
|
77
78
|
|
78
79
|
usage.on('-F', '--force', "Force operations.") do
|
@@ -87,7 +88,7 @@ module Detroit
|
|
87
88
|
options[:trial] = true
|
88
89
|
end
|
89
90
|
# TODO: do we really need verbose?
|
90
|
-
usage.on('--verbose', "
|
91
|
+
usage.on('--verbose', "Provide extra output.") do
|
91
92
|
options[:verbose] = true
|
92
93
|
end
|
93
94
|
usage.on('-q', '--quiet', "Run silently.") do
|
@@ -106,12 +107,16 @@ module Detroit
|
|
106
107
|
usage.on('--warn', "Run with $VERBOSE set to true.") do
|
107
108
|
$VERBOSE = true # wish this were called $WARN
|
108
109
|
end
|
109
|
-
usage.on_tail('--help', "Display this help message.") do
|
110
|
-
|
110
|
+
usage.on_tail('--help [TOOL]', "Display this help message.") do |tool|
|
111
|
+
if tool
|
112
|
+
application.display_help(tool)
|
113
|
+
else
|
114
|
+
puts usage
|
115
|
+
end
|
111
116
|
exit
|
112
117
|
end
|
113
|
-
usage.on_tail('--config', "Produce a configuration template.") do
|
114
|
-
puts application.config_template.to_yaml
|
118
|
+
usage.on_tail('-c', '--config TOOL', "Produce a configuration template.") do |tool|
|
119
|
+
puts application.config_template(tool).to_yaml
|
115
120
|
exit
|
116
121
|
end
|
117
122
|
end
|
data/lib/detroit/core_ext.rb
CHANGED
data/lib/detroit/custom.rb
CHANGED
@@ -23,6 +23,11 @@ module Detroit
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
+
SPECIAL_OPTIONS = %w{
|
27
|
+
service track tracks active priority project
|
28
|
+
trial trace verbose force quiet
|
29
|
+
}
|
30
|
+
|
26
31
|
# Instantiate new custom plugin.
|
27
32
|
#
|
28
33
|
# FIXME: Custom#initialize seems to be running twice at startup. Why?
|
@@ -34,14 +39,11 @@ module Detroit
|
|
34
39
|
super(options)
|
35
40
|
options.each do |stop, script|
|
36
41
|
# skip specific names used for configuration
|
37
|
-
next if stop
|
38
|
-
next if stop == 'tracks' or stop == 'track'
|
39
|
-
next if stop == 'active'
|
40
|
-
next if stop == 'priority'
|
42
|
+
next if SPECIAL_OPTIONS.include? stop
|
41
43
|
# remaining options are names of track stops
|
42
44
|
#tracks.each do |t|
|
43
45
|
src = %{
|
44
|
-
def #{stop}
|
46
|
+
def station_#{stop}
|
45
47
|
#{script}
|
46
48
|
end
|
47
49
|
}
|
@@ -57,9 +59,22 @@ module Detroit
|
|
57
59
|
|
58
60
|
#
|
59
61
|
def method_missing(s, *a, &b)
|
60
|
-
|
62
|
+
if @context.respond_to?(s)
|
63
|
+
@context.__send__(s,*a,&b)
|
64
|
+
else
|
65
|
+
super(s, *a, &b)
|
66
|
+
end
|
61
67
|
end
|
62
68
|
|
69
|
+
public
|
70
|
+
|
71
|
+
#
|
72
|
+
#def respond_to?(name)
|
73
|
+
# r = super(name)
|
74
|
+
# return r if r
|
75
|
+
# @context.respond_to?(s)
|
76
|
+
#end
|
77
|
+
|
63
78
|
end
|
64
79
|
|
65
80
|
end
|
data/lib/detroit/service.rb
CHANGED
@@ -5,12 +5,11 @@ module Detroit
|
|
5
5
|
# @registry ||= {}
|
6
6
|
#end
|
7
7
|
|
8
|
-
# Service class wraps a Tool instance
|
9
|
-
#
|
10
|
-
# TODO: change name ?
|
8
|
+
# Service class wraps a Tool instance when it is made
|
9
|
+
# part of an assembly.
|
11
10
|
#
|
12
11
|
# TODO: Need to work on how to limit a service's tracks per-assembly.
|
13
|
-
class
|
12
|
+
class Service
|
14
13
|
attr :key
|
15
14
|
attr :tracks
|
16
15
|
attr :priority
|
@@ -52,18 +51,26 @@ module Detroit
|
|
52
51
|
|
53
52
|
# Does the service support the given stop.
|
54
53
|
def stop?(name)
|
55
|
-
@service.respond_to?(name)
|
54
|
+
@service.respond_to?("station_#{name}")
|
56
55
|
end
|
57
56
|
|
58
57
|
# Run the service stop procedure.
|
59
|
-
def invoke(name)
|
60
|
-
@service.
|
58
|
+
def invoke(name, stop=nil)
|
59
|
+
sm = @service.method("station_#{name}") # public_send
|
60
|
+
sm.arity == 0 ? sm.call : sm.call(stop)
|
61
61
|
end
|
62
62
|
|
63
63
|
#
|
64
64
|
def inspect
|
65
65
|
"<#{self.class}:#{object_id} @key='#{key}'>"
|
66
66
|
end
|
67
|
+
|
68
|
+
#
|
69
|
+
#def self.assemble(name, method=nil)
|
70
|
+
# define_method("assembly_#{name}") do
|
71
|
+
# __send__(method || name) # public_send
|
72
|
+
# end
|
73
|
+
#end
|
67
74
|
end
|
68
75
|
|
69
76
|
end
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module Detroit
|
2
2
|
|
3
|
-
# Standard assembly is the default. In the
|
4
|
-
#
|
5
|
-
|
3
|
+
# Standard assembly is the default. In the majority of cases this
|
4
|
+
# is all that will be needed. It represents the workflow of
|
5
|
+
# a developing project (particularly Ruby project).
|
6
|
+
assembly_system :standard do
|
6
7
|
|
7
8
|
# Main track.
|
8
9
|
#
|
9
|
-
# TODO: Should :install comes before :verify b/c verfication might
|
10
|
-
# require a local installation?
|
11
10
|
track :main,
|
12
11
|
:prepare, # prepare services / ensure service requirements
|
13
12
|
:generate, # code generation
|
@@ -16,8 +15,8 @@ module Detroit
|
|
16
15
|
:analyze, # perform code analysis
|
17
16
|
:document, # generate documentation
|
18
17
|
:package, # create packages
|
19
|
-
:verify, # post package verification / integration tests
|
20
18
|
:install, # install the package locally (if need be)
|
19
|
+
:verify, # post package verification / integration tests
|
21
20
|
:publish, # publish website/documentation
|
22
21
|
:release, # release packages
|
23
22
|
:deploy, # deploy system to servers
|
data/lib/detroit/tool.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Detroit
|
2
2
|
|
3
|
+
# TODO: The plan is to replace most, if not all, of the fileutils
|
4
|
+
# functionality with Ratch when it is ready.
|
5
|
+
|
3
6
|
require 'detroit/tool/core_ext'
|
4
7
|
require 'detroit/tool/shell_utils'
|
5
8
|
require 'detroit/tool/project_utils'
|
@@ -38,46 +41,59 @@ module Detroit
|
|
38
41
|
# all of the utility methods provided by the regular Tool
|
39
42
|
# class.
|
40
43
|
class BasicTool
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
44
|
+
class << self
|
45
|
+
# Add an assembly system to which the tool applies.
|
46
|
+
# By default the `standard` ssystem is implied.
|
47
|
+
def assembly_system(assembly=nil)
|
48
|
+
@assembly ||= []
|
49
|
+
if assembly
|
50
|
+
@assembly << assembly.to_sym
|
51
|
+
@assembly.uniq!
|
52
|
+
end
|
53
|
+
@assembly
|
48
54
|
end
|
49
|
-
@assembly
|
50
|
-
end
|
51
55
|
|
52
|
-
|
53
|
-
|
54
|
-
# and a return value of +nil+ means all lines apply.
|
55
|
-
#--
|
56
|
-
# TODO: Rename to #lines ?
|
57
|
-
#++
|
58
|
-
def self.tracks
|
59
|
-
end
|
56
|
+
# Shorter alias for #assembly_system.
|
57
|
+
alias_method :assembly, :assembly_system
|
60
58
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
# Override the `tracks` method to limit the lines a service
|
60
|
+
# will work with by default. Generally this is not used,
|
61
|
+
# and a return value of +nil+ means all lines apply.
|
62
|
+
#--
|
63
|
+
# TODO: Rename to #lines ?
|
64
|
+
#++
|
65
|
+
def tracks
|
66
|
+
end
|
65
67
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
map{ |m| m.to_s.chomp('=') }
|
71
|
-
end
|
68
|
+
# Override this method if the tools availability is conditional.
|
69
|
+
def available?
|
70
|
+
true
|
71
|
+
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
73
|
+
# Returns list of writer method names. This is used for reference.
|
74
|
+
def options(service_class=self)
|
75
|
+
i = service_class.ancestors.index(Tool) ||
|
76
|
+
service_class.ancestors.index(BasicTool)
|
77
|
+
m = []
|
78
|
+
service_class.ancestors[0..i].each do |sc|
|
79
|
+
sc.public_instance_methods(false).each do |pm|
|
80
|
+
next if pm !~ /\w+=$/
|
81
|
+
next if %w{taguri=}.include?(m.to_s)
|
82
|
+
m << pm.to_s.chomp('=')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
m
|
86
|
+
end
|
77
87
|
|
78
|
-
|
79
|
-
|
80
|
-
|
88
|
+
# Returns a Class which is a new subclass of the current class.
|
89
|
+
def factory(&block)
|
90
|
+
Class.new(self, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
# When inherited, add class to tool registry.
|
94
|
+
def inherited(base)
|
95
|
+
Detroit.register_tool(base)
|
96
|
+
end
|
81
97
|
end
|
82
98
|
|
83
99
|
# TODO: Needed? Rename?
|
@@ -134,7 +150,7 @@ module Detroit
|
|
134
150
|
end
|
135
151
|
|
136
152
|
# TODO: It would be best if an error were raised if an option is not
|
137
|
-
# supported, however for now only a warning will be issued, b/c
|
153
|
+
# supported, however for now only a warning will be issued, b/c
|
138
154
|
# subclassing makes things more complicated.
|
139
155
|
def initialize_options(options)
|
140
156
|
@options = options
|
@@ -183,7 +199,6 @@ module Detroit
|
|
183
199
|
Platform.local.to_s
|
184
200
|
end
|
185
201
|
|
186
|
-
# TODO: Is naming_policy really useful?
|
187
202
|
# TODO: How to set this in a more universal manner?
|
188
203
|
#
|
189
204
|
def naming_policy(*policies)
|
@@ -147,7 +147,7 @@ module Detroit
|
|
147
147
|
raise ArgumentError, "missing email field -- mailto" unless mailto
|
148
148
|
raise ArgumentError, "missing email field -- subject" unless subject
|
149
149
|
|
150
|
-
passwd ||= password("#{account} password:")
|
150
|
+
passwd ||= password("#{account} password: ")
|
151
151
|
|
152
152
|
mailto = [mailto].flatten.compact
|
153
153
|
|
@@ -161,16 +161,18 @@ module Detroit
|
|
161
161
|
#p server, port, domain, account, passwd, login, secure if verbose?
|
162
162
|
|
163
163
|
begin
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
Net::SMTP.start(server, port, domain, account, passwd, login) do |smtp|
|
171
|
-
smtp.send_message(msg, from, mailto)
|
172
|
-
end
|
164
|
+
smtp = Net::SMTP.new(server, port)
|
165
|
+
|
166
|
+
if smtp.respond_to?(:enable_starttls_auto)
|
167
|
+
smtp.enable_starttls_auto
|
168
|
+
elsif secure #&& smtp.respond_to?(:enable_tls)
|
169
|
+
smtp.enable_tls
|
173
170
|
end
|
171
|
+
|
172
|
+
smtp.start(domain, account, passwd, login) do |smtp|
|
173
|
+
smtp.send_message(msg, from, mailto)
|
174
|
+
end
|
175
|
+
|
174
176
|
return mailto
|
175
177
|
rescue Exception => e
|
176
178
|
return e
|
@@ -202,7 +204,7 @@ module Detroit
|
|
202
204
|
#
|
203
205
|
def require_smtp
|
204
206
|
begin
|
205
|
-
require '
|
207
|
+
require 'net/smtp_tls'
|
206
208
|
rescue LoadError
|
207
209
|
require 'net/smtp'
|
208
210
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'detroit/tool/core_ext/shell_extensions'
|
2
2
|
require 'rbconfig'
|
3
|
+
require 'ansi/core'
|
3
4
|
|
4
5
|
module Detroit
|
5
6
|
|
@@ -14,16 +15,26 @@ module Detroit
|
|
14
15
|
@quiet = false
|
15
16
|
@trial = false
|
16
17
|
@noop = false
|
17
|
-
@force = false
|
18
|
+
@force = false
|
19
|
+
|
18
20
|
super() if defined?(super)
|
19
21
|
end
|
20
22
|
|
21
23
|
#
|
22
24
|
def initialize_extensions
|
23
|
-
|
25
|
+
# extend(fileutils)
|
24
26
|
super() if defined?(super)
|
25
27
|
end
|
26
28
|
|
29
|
+
# Fallback to filutils.
|
30
|
+
def method_missing(s, *a, &b)
|
31
|
+
if fileutils.respond_to?(s)
|
32
|
+
fileutils.send(s, *a, &b)
|
33
|
+
else
|
34
|
+
super(s, *a, &b)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
27
38
|
# A path is required for shell methods to operate.
|
28
39
|
# If no path is set than the current working path is used.
|
29
40
|
def path
|
@@ -35,22 +46,6 @@ module Detroit
|
|
35
46
|
@path = dir
|
36
47
|
end
|
37
48
|
|
38
|
-
attr_writer :stdout
|
39
|
-
attr_writer :stdin
|
40
|
-
attr_writer :stderr
|
41
|
-
|
42
|
-
def stdout
|
43
|
-
@stdout ||= $stdout
|
44
|
-
end
|
45
|
-
|
46
|
-
def stdin
|
47
|
-
@stdin ||= $stdin
|
48
|
-
end
|
49
|
-
|
50
|
-
def stderr
|
51
|
-
@stdout ||= $stderr
|
52
|
-
end
|
53
|
-
|
54
49
|
attr_writer :force
|
55
50
|
attr_writer :quiet
|
56
51
|
attr_writer :trace
|
@@ -70,26 +65,63 @@ module Detroit
|
|
70
65
|
def noop? ; @trial ; end
|
71
66
|
def dryrun? ; verbose? && noop? ; end
|
72
67
|
|
68
|
+
def silent? ; @quiet ; end
|
69
|
+
|
70
|
+
# -- Standard IO ----------------------------------------------------------
|
71
|
+
|
72
|
+
attr_writer :stdout
|
73
|
+
attr_writer :stdin
|
74
|
+
attr_writer :stderr
|
75
|
+
|
76
|
+
def stdout
|
77
|
+
@stdout ||= $stdout
|
78
|
+
end
|
79
|
+
|
80
|
+
def stdin
|
81
|
+
@stdin ||= $stdin
|
82
|
+
end
|
83
|
+
|
84
|
+
def stderr
|
85
|
+
@stdout ||= $stderr
|
86
|
+
end
|
87
|
+
|
73
88
|
#
|
74
89
|
def print(str=nil)
|
75
|
-
|
90
|
+
return if silent?
|
91
|
+
stdout.print(str.to_s)
|
76
92
|
end
|
77
93
|
|
78
94
|
#
|
79
95
|
def puts(str=nil)
|
80
|
-
|
96
|
+
return if silent?
|
97
|
+
stdout.puts(str.to_s)
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
def warn(message)
|
102
|
+
return if silent?
|
103
|
+
stderr.puts "WARNING ".ansi(:yellow) + message.to_s
|
81
104
|
end
|
82
105
|
|
83
|
-
#
|
84
|
-
def
|
85
|
-
|
106
|
+
#
|
107
|
+
def status(message)
|
108
|
+
return if silent?
|
109
|
+
stdout.puts "#{message}".ansi(:bold)
|
86
110
|
end
|
87
111
|
|
88
|
-
|
112
|
+
# Same as status.
|
113
|
+
#
|
114
|
+
# @deprecated
|
115
|
+
# Doubley redundant with #status and #puts.
|
116
|
+
alias report status
|
89
117
|
|
90
118
|
# Internal trace report. Only output if in trace mode.
|
91
119
|
def trace(message)
|
92
|
-
|
120
|
+
return if silent?
|
121
|
+
if trace?
|
122
|
+
stdout.print "TRIAL RUN " if trial?
|
123
|
+
stdout.puts message
|
124
|
+
end
|
93
125
|
end
|
94
126
|
|
95
127
|
# Convenient method to get simple console reply.
|
@@ -107,6 +139,8 @@ module Detroit
|
|
107
139
|
ask(prompt)
|
108
140
|
end
|
109
141
|
|
142
|
+
# -- Shell ----------------------------------------------------------------
|
143
|
+
|
110
144
|
# Delegate to Ratch::Shell instance.
|
111
145
|
#def shell(path=Dir.pwd)
|
112
146
|
# @shell ||= {}
|
@@ -125,21 +159,28 @@ module Detroit
|
|
125
159
|
trace cmd
|
126
160
|
return true if noop?
|
127
161
|
|
162
|
+
success = nil
|
128
163
|
if quiet?
|
129
|
-
silently{ system(cmd) }
|
164
|
+
silently{ success = system(cmd) }
|
130
165
|
else
|
131
|
-
system(cmd)
|
166
|
+
success = system(cmd)
|
132
167
|
end
|
168
|
+
success
|
133
169
|
end
|
134
170
|
|
135
171
|
# Current ruby binary.
|
136
|
-
RUBY =
|
172
|
+
RUBY = (
|
173
|
+
bindir = ::RbConfig::CONFIG['bindir']
|
174
|
+
rubyname = ::RbConfig::CONFIG['ruby_install_name']
|
175
|
+
File.join(bindir, rubyname).sub(/.*\s.*/m, '"\&"')
|
176
|
+
)
|
137
177
|
|
138
178
|
# Shell-out to ruby.
|
139
179
|
def ruby(cmd)
|
140
180
|
sh RUBY + " " + cmd
|
141
181
|
end
|
142
182
|
|
183
|
+
# -- Dir Methods ----------------------------------------------------------
|
143
184
|
|
144
185
|
# TODO: Ultimately merge #glob and #multiglob.
|
145
186
|
def multiglob(*args, &blk)
|
@@ -151,25 +192,6 @@ module Detroit
|
|
151
192
|
Dir.multiglob_r(*args, &blk)
|
152
193
|
end
|
153
194
|
|
154
|
-
# -- File IO Shortcuts ----------------------------------------------------
|
155
|
-
|
156
|
-
# Read file.
|
157
|
-
def read(path)
|
158
|
-
File.read(path)
|
159
|
-
end
|
160
|
-
|
161
|
-
# Write file.
|
162
|
-
def write(path, text)
|
163
|
-
$stderr.puts "write #{path}" if trace?
|
164
|
-
File.open(path, 'w'){ |f| f << text } unless noop?
|
165
|
-
end
|
166
|
-
|
167
|
-
# Append to file.
|
168
|
-
def append(path, text)
|
169
|
-
$stderr.puts "append #{path}" if trace?
|
170
|
-
File.open(path, 'a'){ |f| f << text } unless noop?
|
171
|
-
end
|
172
|
-
|
173
195
|
# -- File Testing ---------------------------------------------------------
|
174
196
|
|
175
197
|
def size(path) ; FileTest.size(path) ; end
|
@@ -215,6 +237,25 @@ module Detroit
|
|
215
237
|
|
216
238
|
def utime(*args) ; File.utime(*args) unless noop? ; end
|
217
239
|
|
240
|
+
# -- File IO Shortcuts ----------------------------------------------------
|
241
|
+
|
242
|
+
# Read file.
|
243
|
+
def read(path)
|
244
|
+
File.read(path)
|
245
|
+
end
|
246
|
+
|
247
|
+
# Write file.
|
248
|
+
def write(path, text)
|
249
|
+
$stderr.puts "write #{path}" if trace?
|
250
|
+
File.open(path, 'w'){ |f| f << text } unless noop?
|
251
|
+
end
|
252
|
+
|
253
|
+
# Append to file.
|
254
|
+
def append(path, text)
|
255
|
+
$stderr.puts "append #{path}" if trace?
|
256
|
+
File.open(path, 'a'){ |f| f << text } unless noop?
|
257
|
+
end
|
258
|
+
|
218
259
|
private # -----------------------------------------------------------------
|
219
260
|
|
220
261
|
# Returns FileUtils module based on mode.
|