detroit 0.1.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.
Files changed (51) hide show
  1. data/.ruby +45 -0
  2. data/COPYING.rdoc +19 -0
  3. data/EXAMPLE.md +188 -0
  4. data/GPL3.txt +675 -0
  5. data/HISTORY.rdoc +14 -0
  6. data/README.rdoc +139 -0
  7. data/bin/detroit +9 -0
  8. data/lib/detroit.rb +67 -0
  9. data/lib/detroit.yml +45 -0
  10. data/lib/detroit/application.rb +427 -0
  11. data/lib/detroit/assembly.rb +80 -0
  12. data/lib/detroit/config.rb +197 -0
  13. data/lib/detroit/control.rb +124 -0
  14. data/lib/detroit/core_ext.rb +139 -0
  15. data/lib/detroit/custom.rb +65 -0
  16. data/lib/detroit/dsl.rb +55 -0
  17. data/lib/detroit/schedule.rb +187 -0
  18. data/lib/detroit/service.rb +188 -0
  19. data/lib/detroit/standard_assembly.rb +52 -0
  20. data/lib/detroit/tool.rb +216 -0
  21. data/lib/detroit/tool/core_ext.rb +3 -0
  22. data/lib/detroit/tool/core_ext/facets.rb +11 -0
  23. data/lib/detroit/tool/core_ext/filetest.rb +29 -0
  24. data/lib/detroit/tool/core_ext/shell_extensions.rb +7 -0
  25. data/lib/detroit/tool/core_ext/to_actual_filename.rb +19 -0
  26. data/lib/detroit/tool/core_ext/to_console.rb +97 -0
  27. data/lib/detroit/tool/core_ext/to_list.rb +29 -0
  28. data/lib/detroit/tool/core_ext/to_yamlfrag.rb +9 -0
  29. data/lib/detroit/tool/core_ext/unfold_paragraphs.rb +27 -0
  30. data/lib/detroit/tool/email_utils.rb +288 -0
  31. data/lib/detroit/tool/project_utils.rb +41 -0
  32. data/lib/detroit/tool/shell_utils.rb +235 -0
  33. data/qed/01_schedule/02_initialize.md +57 -0
  34. data/qed/99_plugins/rdoc/rdoc-plugin.rdoc +22 -0
  35. data/qed/99_plugins/rdoc/sample/Syckfile +6 -0
  36. data/qed/99_plugins/rdoc/sample/lib/sandbox/.xxx +1 -0
  37. data/qed/99_plugins/rdoc/sample/lib/sandbox/hello.rb +5 -0
  38. data/qed/99_plugins/rdoc/sample/lib/sandbox/xxx.rb +6 -0
  39. data/qed/99_plugins/rdoc/sample/lib/xxx/bye.rb +4 -0
  40. data/qed/99_plugins/rdoc/sample/meta/name +1 -0
  41. data/qed/99_plugins/rdoc/sample/meta/version +1 -0
  42. data/qed/samples/example_project/.ruby +0 -0
  43. data/qed/samples/example_project/Schedule +9 -0
  44. data/qed/samples/example_project/lib/foo/.xxx +1 -0
  45. data/qed/samples/example_project/lib/foo/hello.rb +7 -0
  46. data/qed/samples/example_project/lib/foo/xxx.rb +6 -0
  47. data/qed/samples/example_project/lib/foo/xxx/bye.rb +4 -0
  48. data/qed/samples/example_project/meta/name +1 -0
  49. data/qed/samples/example_project/meta/version +1 -0
  50. data/qed/samples/example_schedule.rb +57 -0
  51. metadata +139 -0
@@ -0,0 +1,14 @@
1
+ = RELEASE HISTORY
2
+
3
+ == 0.1.0 / 2011-06-29
4
+
5
+ Detroit is a lifecycle build system for Ruby. Detroit was originally
6
+ called Syckle, and was developed and used in house for Rubyworks projects
7
+ for several years. With the renaming of the project, the system has
8
+ been simplified, the code cleaned up and the version count reset, in
9
+ preperation of it's wider public release.
10
+
11
+ Changes:
12
+
13
+ * Happy Release Day!
14
+
@@ -0,0 +1,139 @@
1
+ = Detroit
2
+
3
+ Author:: Thomas Sawyer
4
+ Licence:: GPL v.3
5
+ Copyright:: (c) 2011 Rubyworks, Thomas Sawyer
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ Detroit is a software production management aid for Ruby developers.
11
+ Detroit utilizes a lifecycle methodology to help developers prepare and
12
+ release Ruby software in a clear, repeatable, linear fashion.
13
+
14
+
15
+ == RESOURCES
16
+
17
+ * {Homepage}[http://rubyworks.github.com/detroit]
18
+ * {Development}[http://github.com/rubyworks/detroit]
19
+ * {Mailing List}[http://googlegroups.com/group/rubyworks-mailinglist]
20
+
21
+
22
+ == HOW IT WORKS
23
+
24
+ Detroit defines development processions which consist of a set of named
25
+ production _lines_, or _tracks_, each with a series of named _stations_,
26
+ or _stops_. Developers attach work elements to stations by configuring
27
+ service instances in a project's Schedule or *.schedule files. Schedules
28
+ are written in either YAML or a Ruby DSL.
29
+
30
+ For example, a RubyForge service can be defined:
31
+
32
+ rubyforge:
33
+ service: Rubyforge
34
+ sitemap:
35
+ site: <%= name %>
36
+ active: true
37
+
38
+ As this example demonstrates, service configurations can draw on project
39
+ metadata via ERB embedded tags. Detroit gathers this information using
40
+ {.ruby}[http://dotruby.github.com/dotruby], but the data source can be
41
+ easily customized to meet the needs of different projects.
42
+
43
+ With service configuration and metadata in place, using Detroit is simply
44
+ a matter of passing a line name and stop to the +detroit+ command line
45
+ tool. For example,
46
+
47
+ $ detroit main:document
48
+
49
+ The track name and its stop are separated by a colon. This command
50
+ would run every stop on the +main+ track, in order, until it completes
51
+ the +document+ stop. Since +main+ is the default track, we can acheive
52
+ the same effect without specifying it.
53
+
54
+ $ detroit document
55
+
56
+ The use of tracks may seem constrictive to users of tools like Rake, but
57
+ there is a benefit to this approach. It helps ensure a project is
58
+ always up-to-date and in-sync --that no necessary steps are missed.
59
+ Detroit includes three tracks out of the box. The most significant of
60
+ which is +main+ which entails a route with ordred stops:
61
+
62
+ prepare # prepare services and ensure requirements
63
+ generate # code generation
64
+ compile # compile source code
65
+ test # run tests and/or specifications
66
+ analyze # run code analysis
67
+ document # generate documentation
68
+ package # create packages
69
+ verify # post package verification (eg. integration tests)
70
+ install # install package locally
71
+ publish # publish website/documentation
72
+ release # release packages
73
+ deploy # deply system to servers
74
+ promote # tell the world about you awesome work
75
+
76
+ All tracks also have a maintainence subtrack which consits of three stops:
77
+
78
+ reset # mark build files as out-of-date
79
+ clean # remove minor build files
80
+ purge # remove all build files
81
+
82
+ Where reset marks generated files out-of-date, clean removes temporary
83
+ products and purge removes all generated prodcuts.
84
+
85
+ In additon to +main+, Detroit includes +site+ and +attn+ tracks which are used
86
+ to generate and publish a project's website, and make project announcements
87
+ respectively. They are simply useful subsets of the +main+ track.
88
+
89
+ Please see http://rubyworks.github.com/detroit for more details on how to
90
+ use Detroit, including the creation of custom tracks, stops and service plugins.
91
+ Also try the <tt>--help</tt> option to see the detroit command's help
92
+ information.
93
+
94
+
95
+ == INSTALLATION
96
+
97
+ Detroit can, of course, be installed via RubyGems:
98
+
99
+ $ gem install detroit
100
+
101
+ We no longer recommend it, but Detroit can also be installed the
102
+ old-fashion way by downloading the .tar.gz package and using
103
+ Ruby Setup (See http://setup.rubyforge.org).
104
+
105
+ $ tar -xvzf detroit-1.0.0.tar.gz
106
+ $ cd detroit-1.0.0
107
+ $ sudo setup.rb
108
+
109
+ Ruby Setup is stand-alone version of the original setup.rb script.
110
+
111
+
112
+ == ISSUES
113
+
114
+ All in all, Detroit works well. There are some rough edges with regards
115
+ to the built-in service plugins, so from time to time you might run into
116
+ an odd error. Ususally it just means a service confirguraiton needs
117
+ adjustment.
118
+
119
+ Please note, Windows support has not been considered at all. While I do
120
+ not see any specific reason it should not work, there may well be issues
121
+ I have not considered since I do not use Windows. If you are Windows user
122
+ and give Detroit a try please let us know of any issues you encounter.
123
+
124
+
125
+ == HISTORY
126
+
127
+ Detroit is actaully the offspring of Reap v.10, and was called Syckle for
128
+ a number of years as it matured. It represents many years of design considerations
129
+ (and reconsiderations), that evolved Reap from its simple Rake extension origins,
130
+ which pre-dated Hoe, to the lifecycle system it is today.
131
+
132
+
133
+ == COPYRIGHT & LICENSE
134
+
135
+ (GPL v3 License)
136
+
137
+ Copyright (c) 2007 Thomas Sawyer
138
+
139
+ See COPYING.rdoc and GPL3.txt for details.
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'detroit'
3
+ begin
4
+ Detroit.cli(*ARGV)
5
+ rescue => err
6
+ raise err #if $DEBUG
7
+ $stderr.puts err
8
+ end
9
+
@@ -0,0 +1,67 @@
1
+ module Detroit
2
+ # Access to this project's metadata.
3
+ def self.metadata
4
+ @metadata ||= (
5
+ require 'yaml'
6
+ YAML.load(File.new(File.dirname(__FILE__) + '/detroit.yml'))
7
+ )
8
+ end
9
+
10
+ # Access to project metadata via constants.
11
+ def self.const_missing(name)
12
+ metadata[name.to_s.downcase] || super(name)
13
+ end
14
+
15
+ # TODO: Only here b/c of bug in Ruby 1.8.x
16
+ #VERSION = "0.1.0"
17
+ end
18
+
19
+ # Erb is used to to script YAML-based schedule files.
20
+ require 'erb'
21
+
22
+ # OptionParser is used for command line parsing.
23
+ require 'optparse'
24
+
25
+ # Yea like we don't all ride a YAML.
26
+ require 'yaml'
27
+
28
+ # The ANSI gem is used to colorize terminal output.
29
+ require 'ansi/terminal'
30
+ require 'ansi/code'
31
+
32
+ # The parallel gem is used to (optionally) to multitask services.
33
+ begin
34
+ require 'parallel'
35
+ rescue LoadError
36
+ end
37
+
38
+ # POM is used to access project metadata.
39
+ require 'pom'
40
+
41
+ # Redtools provides the standard services.
42
+ require 'redtools'
43
+
44
+ # And all the rest is Detroit, baby.
45
+ if RUBY_VERSION > '1.9'
46
+ require_relative 'detroit/core_ext'
47
+ require_relative 'detroit/config'
48
+ require_relative 'detroit/service'
49
+ require_relative 'detroit/tool'
50
+ require_relative 'detroit/assembly'
51
+ require_relative 'detroit/standard_assembly'
52
+ require_relative 'detroit/control'
53
+ require_relative 'detroit/application'
54
+ require_relative 'detroit/schedule'
55
+ require_relative 'detroit/custom'
56
+ else
57
+ require 'detroit/core_ext'
58
+ require 'detroit/config'
59
+ require 'detroit/service'
60
+ require 'detroit/tool'
61
+ require 'detroit/assembly'
62
+ require 'detroit/standard_assembly'
63
+ require 'detroit/control'
64
+ require 'detroit/application'
65
+ require 'detroit/schedule'
66
+ require 'detroit/custom'
67
+ end
@@ -0,0 +1,45 @@
1
+ ---
2
+ name: detroit
3
+ version: 0.1.0
4
+ title: Detroit
5
+ summary: Software Production Mangement
6
+ description: Detroit is an advanced lifecycle build system. With Detroit, build tasks are user defined service instances tied to stops along a track. Whenever the detroit console command is run, a track is followed from beginning to designated destination.
7
+ loadpath:
8
+ - lib
9
+ manifest: Manifest
10
+ requires:
11
+ - name: facets
12
+ version: 0+
13
+ group: []
14
+
15
+ - name: pom
16
+ version: 0+
17
+ group: []
18
+
19
+ - name: qed
20
+ version: 0+
21
+ group:
22
+ - test
23
+ conflicts: []
24
+
25
+ replaces: []
26
+
27
+ engine_check: []
28
+
29
+ organization: Rubyworks
30
+ contact: Trans <transfire@gmail.com>
31
+ created: 2007-10-10
32
+ copyright: Copyright (c) 2007 Thomas Sawyer
33
+ licenses:
34
+ - GPL3
35
+ authors:
36
+ - Thomas Sawyer
37
+ maintainers: []
38
+
39
+ resources:
40
+ home: http://rubyworks.github.com/detroit
41
+ code: http://github.com/rubyworks/detroit
42
+ mail: http://groups.google.com/rubyworks-mailinglist
43
+ repositories:
44
+ public: http://github.com/proutils/detroit.git
45
+ spec_version: 1.0.0
@@ -0,0 +1,427 @@
1
+ module Detroit
2
+
3
+ #
4
+ DEFAULT_ASSEMBLY = :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
+ end
21
+
22
+ # # Load standard plugins.
23
+ # def load_standard_plugins
24
+ # #::Plugin.find("detroit/*.rb").each do |file|
25
+ # Detroit.standard_plugins.each do |file|
26
+ # begin
27
+ # require(file)
28
+ # rescue => err
29
+ # $stderr.puts err if $DEBUG
30
+ # end
31
+ # end
32
+ # end
33
+
34
+ # The selected assembly system.
35
+ def assembly
36
+ options[:assembly] || DEFAULT_ASSEMBLY
37
+ end
38
+
39
+ # Quiet mode?
40
+ def quiet?
41
+ options[:quiet]
42
+ end
43
+
44
+ # Multitask mode?
45
+ def multitask?
46
+ options[:multitask] && defined?(Parallel)
47
+ end
48
+
49
+ # Returns a list of services to skip as specificed on the commandline.
50
+ def skip
51
+ @skip ||= options[:skip].to_list.map{ |s| s.downcase }
52
+ end
53
+
54
+ #
55
+ def schedules
56
+ @schedules ||= options[:schedules]
57
+ end
58
+
59
+ # Detroit configuration.
60
+ def config
61
+ @config ||= Detroit::Config.new(schedules)
62
+ end
63
+
64
+ # Provides access to the Project instance via `Detroit.project` class method.
65
+ def project
66
+ @project ||= POM::Project.find
67
+ end
68
+
69
+ # User-defined service defaults.
70
+ #
71
+ # Returns Hash of service defaults.
72
+ def defaults
73
+ config.defaults
74
+ end
75
+
76
+ # Generates a configuration template for particular tool or all tools.
77
+ # This is only used for reference purposes.
78
+ def config_template(name=nil)
79
+ if name
80
+ list = [name, Detroit.tools[name]]
81
+ else
82
+ list = Detroit.tools
83
+ end
84
+ cfg = {}
85
+ list.each do |srv_name, srv_class|
86
+ attrs = srv_class.options #instance_methods.select{ |m| m.to_s =~ /\w+=$/ && !%w{taguri=}.include?(m.to_s) }
87
+ atcfg = attrs.inject({}){ |h, m| h[m.to_s.chomp('=')] = nil; h }
88
+ atcfg['service'] = srv_class.basename.downcase
89
+ atcfg['active'] = false
90
+ cfg[srv_name] = atcfg
91
+ end
92
+ cfg
93
+ end
94
+
95
+ # Active services are services defined in schedule files and do not
96
+ # have their active setting turned off.
97
+ #
98
+ # Returns Array of active services.
99
+ def active_services
100
+ @active_services ||= (
101
+ activelist = []
102
+
103
+ config.each do |key, opts|
104
+ next unless opts && opts['active'] != false
105
+
106
+ # omit any service in the skip list
107
+ next if skip.include?(key.to_s)
108
+
109
+ tool_name = (opts.delete('tool') || opts.delete('service') || key).to_s.downcase
110
+
111
+ unless Detroit.tools.key?(tool_name)
112
+ config.load_plugin(tool_name)
113
+ end
114
+
115
+ tool_class = Detroit.tools[tool_name]
116
+
117
+ abort "Unknown tool `#{tool_name}'." unless tool_class
118
+
119
+ if tool_class.available? #(project)
120
+ #opts = inject_environment(opts) # TODO: DEPRECATE
121
+ options = defaults[tool_name.downcase].to_h
122
+ options = options.merge(common_tool_options)
123
+ options = options.merge(opts)
124
+ #activelist << tool_class.new(key, options) #script,
125
+ ## remove any services specified by the --skip option on the comamndline
126
+ activelist << ServiceWrapper.new(key, tool_class, options) #script,
127
+ #else
128
+ # warn "Service #{tool_class} is not available."
129
+ end
130
+ end
131
+
132
+ # sorting here trickles down to processing later
133
+ activelist = activelist.sort_by{ |s| s.priority || 0 }
134
+
135
+ activelist
136
+ )
137
+ end
138
+
139
+ #alias_method :services, :active_services
140
+
141
+ # Service configuration, from project's schedule file(s).
142
+ #
143
+ # Returns Hash of service name and settings.
144
+ #def service_configs
145
+ # config.services
146
+ #end
147
+
148
+ # Run individual detroit scripts.
149
+ #def runscript(script, stop)
150
+ # @config.services.clear
151
+ # @config.load_schedule_file(script)
152
+ # #@service_configs = load_service_configs(script)
153
+ # run(stop)
154
+ #end
155
+
156
+ # Start the run.
157
+ def start(stop)
158
+ Dir.chdir(project.root) do # change into project directory
159
+ run(stop)
160
+ end
161
+ end
162
+
163
+ # Run up to the specified +track_and_stop+.
164
+ def run(track_and_stop)
165
+ raise "Malformed destination -- #{track_and_stop}" unless /^\w+\:{0,1}\w+$/ =~ track_and_stop
166
+
167
+ if track_and_stop
168
+ name, stop = track_and_stop.split(':')
169
+ name, stop = 'main', name unless stop
170
+ else
171
+ name = 'main'
172
+ stop = nil
173
+ end
174
+
175
+ name = name.to_sym
176
+ stop = stop.to_sym if stop
177
+
178
+ assm = Detroit.assemblies[assembly]
179
+
180
+ raise "Unkown assembly `#{assembly}'" unless assm
181
+
182
+ track = assm.get_track(name, stop)
183
+
184
+ #if stop
185
+ # system = track.route_with_stop(stop)
186
+ # raise "Unknown stop -- #{stop}" unless system
187
+
188
+ if not track.include?(stop)
189
+ #overview
190
+ $stderr.puts "Unknown stop for track `#{name}'."
191
+ exit 0
192
+ end
193
+
194
+ # prime the services (so as to fail early)
195
+ active_services.each do |srv|
196
+ srv.preconfigure if srv.respond_to?("preconfigure")
197
+ end
198
+
199
+ if multitask?
200
+ h = ["#{project.metadata.title} v#{project.metadata.version} [M]", "#{project.root}"]
201
+ else
202
+ h = ["#{project.metadata.title} v#{project.metadata.version}", "#{project.root}"]
203
+ end
204
+ status_header(*h)
205
+
206
+ start_time = Time.now
207
+
208
+ track.each do |run_stop|
209
+ next if skip.include?("#{run_stop}") # TODO: Should we really allow skipping stops?
210
+ service_hooks(name, ('pre_' + run_stop.to_s).to_sym)
211
+ service_calls(name, ('pre_' + run_stop.to_s).to_sym)
212
+ service_calls(name, run_stop)
213
+ service_calls(name, ('aft_' + run_stop.to_s).to_sym)
214
+ service_hooks(name, ('aft_' + run_stop.to_s).to_sym)
215
+ break if stop == run_stop
216
+ end
217
+
218
+ stop_time = Time.now
219
+ puts "\nFinished in #{stop_time - start_time} seconds." unless quiet?
220
+ end
221
+
222
+ # Execute service hook for given track and destination.
223
+ #--
224
+ # TODO: Deprecate service hooks?
225
+ #
226
+ # TODO: Currently only stop counts, maybe add track subdirs.
227
+ #++
228
+ def service_hooks(track, stop)
229
+ #hook = dir + ("#{track}/#{stop}.rb".gsub('_', '-'))
230
+ dir = hook_directory
231
+ return unless dir
232
+ name = stop.to_s.gsub('_', '-')
233
+ hook = dir + "#{name}.rb"
234
+ if hook.exist?
235
+ status_line("hook", name.capitalize)
236
+ hook_tool.instance_eval(hook.read)
237
+ end
238
+ end
239
+
240
+ # Returns a project's Detroit hooks directory.
241
+ def hook_directory
242
+ dir = project.root.glob("{.,}detroit/hooks").first
243
+ end
244
+
245
+ #
246
+ def hook_tool
247
+ @hook_tool ||= Tool.new(common_tool_options)
248
+ end
249
+
250
+ # TODO: Do we need verbose?
251
+ def common_tool_options
252
+ {
253
+ 'project' => project,
254
+ 'trial' => options[:trial],
255
+ 'trace' => options[:trace],
256
+ 'quiet' => options[:quiet],
257
+ 'force' => options[:force],
258
+ 'verbose' => options[:verbose]
259
+ }
260
+ end
261
+
262
+ # Make service calls.
263
+ def service_calls(track, stop)
264
+ prioritized_services = active_services.group_by{ |srv| srv.priority }.sort_by{ |k,v| k }
265
+ prioritized_services.each do |(priority, services)|
266
+ ## remove any services specified by the --skip option on the comamndline
267
+ #services = services.reject{ |srv| skip.include?(srv.key.to_s) }
268
+ ## only servies that are on the track
269
+ services = services.select{ |srv| srv.tracks.nil? or srv.tracks.include?(track.to_s) }
270
+
271
+ tasklist = services.map{ |srv| [srv, track, stop] }
272
+ if multitask?
273
+ results = Parallel.in_processes(tasklist.size) do |i|
274
+ run_a_service(*tasklist[i])
275
+ end
276
+ else
277
+ tasklist.each do |args|
278
+ run_a_service(*args)
279
+ end
280
+ end
281
+ end
282
+ end
283
+
284
+ # Run a service given the service, track name and stop name.
285
+ def run_a_service(srv, track, stop)
286
+ # run if the service supports the track and stop.
287
+ #if srv.respond_to?("#{track}_#{stop}")
288
+ if srv.stop?(stop)
289
+ if options[:verbose]
290
+ #status_line("#{srv.key.to_s} (#{srv.class}##{track}_#{stop})", stop.to_s.gsub('_', '-').capitalize)
291
+ status_line("#{srv.key.to_s} (#{srv.class}##{stop})", stop.to_s.gsub('_', '-').capitalize)
292
+ else
293
+ status_line("#{srv.key.to_s}", stop.to_s.gsub('_', '-').capitalize)
294
+ end
295
+ #srv.__send__("#{track}_#{stop}")
296
+ srv.invoke(stop)
297
+ end
298
+ end
299
+
300
+ # Returns a list of all terminal stops, i.e. stops at a tracks end.
301
+ # FIXME: stop_map is not defined.
302
+ def end_stops
303
+ (stop_map.keys - stop_map.values).compact
304
+ end
305
+
306
+ # Give an overview of stops this track supports.
307
+ # FIXME: end_stops blows up.
308
+ def overview
309
+ end_stops.each do |stop_name|
310
+ action_plan(stop_name).each do |act|
311
+ display_action(act)
312
+ end
313
+ puts
314
+ end
315
+ end
316
+
317
+ # --- Print Methods ------------------------------------------------------
318
+
319
+ # Print a status header, which consists of project name and version on the
320
+ # left and stop location on the right.
321
+ #
322
+ def status_header(left, right='')
323
+ left, right = left.to_s, right.to_s
324
+ #left.color = 'blue'
325
+ #right.color = 'magenta'
326
+ unless quiet?
327
+ puts
328
+ print_header(left, right)
329
+ #puts "=" * io.screen_width
330
+ end
331
+ end
332
+
333
+ # Print a status line, which consists of service name on the left
334
+ # and stop name on the right.
335
+ #
336
+ def status_line(left, right='')
337
+ left, right = left.to_s, right.to_s
338
+ #left.color = 'blue'
339
+ #right.color = 'magenta'
340
+ unless quiet?
341
+ puts
342
+ #puts "-" * io.screen_width
343
+ print_phase(left, right)
344
+ #puts "-" * io.screen_width
345
+ #puts
346
+ end
347
+ end
348
+
349
+ #
350
+ def display_action(action_item)
351
+ phase, service, action, parameters = *action_item
352
+ puts " %-10s %-10s %-10s" % [phase.to_s.capitalize, service.service_title, action]
353
+ #status_line(service.service_title, phase.to_s.capitalize)
354
+ end
355
+
356
+ #
357
+ def print_header(left, right)
358
+ if ANSI::SUPPORTED
359
+ printline('', '', :pad=>1, :sep=>' ', :style=>[:negative, :bold], :left=>[:bold], :right=>[:bold])
360
+ printline(left, right, :pad=>2, :sep=>' ', :style=>[:negative, :bold], :left=>[:bold], :right=>[:bold])
361
+ printline('', '', :pad=>1, :sep=>' ', :style=>[:negative, :bold], :left=>[:bold], :right=>[:bold])
362
+ else
363
+ printline(left, right, :pad=>2, :sep=>'=')
364
+ end
365
+ end
366
+
367
+ #
368
+ def print_phase(left, right)
369
+ if ANSI::SUPPORTED
370
+ printline(left, right, :pad=>2, :sep=>' ', :style=>[:on_white, :black, :bold], :left=>[:bold], :right=>[:bold])
371
+ else
372
+ printline(left, right, :pad=>2, :sep=>'-')
373
+ end
374
+ end
375
+
376
+ #
377
+ def printline(left, right='', options={})
378
+ return if quiet?
379
+
380
+ separator = options[:seperator] || options[:sep] || ' '
381
+ padding = options[:padding] || options[:pad] || 0
382
+
383
+ left, right = left.to_s, right.to_s
384
+
385
+ left_size = left.size
386
+ right_size = right.size
387
+
388
+ #left = colorize(left)
389
+ #right = colorize(right)
390
+
391
+ l = padding
392
+ r = -(right_size + padding)
393
+
394
+ style = options[:style] || []
395
+ lstyle = options[:left] || []
396
+ rstyle = options[:right] || []
397
+
398
+ left = lstyle.inject(left) { |s, c| ansize(s, c) }
399
+ right = rstyle.inject(right){ |s, c| ansize(s, c) }
400
+
401
+ line = separator * screen_width
402
+ line[l, left_size] = left if left_size != 0
403
+ line[r, right_size] = right if right_size != 0
404
+
405
+ line = style.inject(line){ |s, c| ansize(s, c) }
406
+
407
+ puts line + ansize('', :clear)
408
+ end
409
+
410
+ #
411
+ def ansize(text, code)
412
+ #return text unless text.color
413
+ if RUBY_PLATFORM =~ /win/
414
+ text.to_s
415
+ else
416
+ ANSI::Code.send(code.to_sym) + text
417
+ end
418
+ end
419
+
420
+ #
421
+ def screen_width
422
+ ANSI::Terminal.terminal_width
423
+ end
424
+
425
+ end
426
+
427
+ end #module Detroit