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.
@@ -27,14 +27,15 @@ module Detroit
27
27
  # Run the command line interface.
28
28
  def cli(*argv)
29
29
  cli_options = {
30
- :schedules => [],
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).parse!(argv)
35
+ usage = cli_usage(cli_options)
36
+ usage.parse!(argv)
36
37
 
37
- #if /\.schedule$/ =~ argv[0]
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('-a', '--assembly=NAME', "Select assembly. Default is `standard'.") do |assembly|
72
- options[:assembly] = assembly
72
+ usage.on('-s', '--system=NAME', "Select assembly system. Default is `standard'.") do |system|
73
+ options[:system] = system
73
74
  end
74
- usage.on('-s', '--schedule [FILE]', 'Use specific schedule file(s).') do |file|
75
- options[:schedules] << file
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', "Provided extra output.") do
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
- puts usage
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
@@ -42,8 +42,6 @@ end
42
42
 
43
43
  # TODO: Replace these with facets/shellwords !!!
44
44
 
45
- # TODO: Belongs in Redtools, no?
46
-
47
45
  #
48
46
  class Array #:nodoc:
49
47
 
@@ -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 == 'service'
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
- super(s, *a, &b) if @context.respond_to?(s)
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
@@ -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 ServiceWrapper
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.__send__(name) # public_send
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 vast majority of
4
- # cases this is all that will ever be used.
5
- assembly :standard do
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
@@ -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
- # Add an assembly to which the tool applies.
42
- # By default the `standard` assembly is implied.
43
- def self.assembly(assembly=nil)
44
- @assembly ||= []
45
- if assembly
46
- @assembly << assembly.to_sym
47
- @assembly.uniq!
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
- # Override the `tracks` method to limit the lines a service
53
- # will work with by default. Generally this is not used,
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
- # Override this method if the tools availability is conditional.
62
- def self.available?
63
- true
64
- end
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
- # Returns list of writer method names.
67
- def self.options(service_class=self)
68
- service_class.instance_methods.
69
- select{ |m| m.to_s =~ /\w+=$/ && !%w{taguri=}.include?(m.to_s) }.
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
- # Returns a Class which is a new subclass of the current class.
74
- def self.factory(&block)
75
- Class.new(self, &block)
76
- end
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
- # When inherited, add class to tool registry.
79
- def self.inherited(base)
80
- Detroit.register_tool(base)
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 of
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
- if Net::SMTP.respond_to?(:enable_tls) && secure
165
- Net::SMTP.enable_tls
166
- Net::SMTP.start(server, port, domain, account, passwd, login, secure) do |smtp|
167
- smtp.send_message(msg, from, mailto)
168
- end
169
- else
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 'facets/net/smtp_tls'
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
- extend(fileutils)
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
- stdout.print(str.to_s) unless quiet?
90
+ return if silent?
91
+ stdout.print(str.to_s)
76
92
  end
77
93
 
78
94
  #
79
95
  def puts(str=nil)
80
- stdout.puts(str.to_s) unless quiet?
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
- # TODO: deprecate in favor of #report ?
84
- def report(message)
85
- stderr.puts message unless quiet?
106
+ #
107
+ def status(message)
108
+ return if silent?
109
+ stdout.puts "#{message}".ansi(:bold)
86
110
  end
87
111
 
88
- alias_method :status, :report
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
- stderr.puts message if trace?
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 = File.join(::Config::CONFIG['bindir'], ::Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
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.