detroit 0.1.0 → 0.2.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/.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.
|