detroit 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.