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.
- data/.ruby +45 -0
- data/COPYING.rdoc +19 -0
- data/EXAMPLE.md +188 -0
- data/GPL3.txt +675 -0
- data/HISTORY.rdoc +14 -0
- data/README.rdoc +139 -0
- data/bin/detroit +9 -0
- data/lib/detroit.rb +67 -0
- data/lib/detroit.yml +45 -0
- data/lib/detroit/application.rb +427 -0
- data/lib/detroit/assembly.rb +80 -0
- data/lib/detroit/config.rb +197 -0
- data/lib/detroit/control.rb +124 -0
- data/lib/detroit/core_ext.rb +139 -0
- data/lib/detroit/custom.rb +65 -0
- data/lib/detroit/dsl.rb +55 -0
- data/lib/detroit/schedule.rb +187 -0
- data/lib/detroit/service.rb +188 -0
- data/lib/detroit/standard_assembly.rb +52 -0
- data/lib/detroit/tool.rb +216 -0
- data/lib/detroit/tool/core_ext.rb +3 -0
- data/lib/detroit/tool/core_ext/facets.rb +11 -0
- data/lib/detroit/tool/core_ext/filetest.rb +29 -0
- data/lib/detroit/tool/core_ext/shell_extensions.rb +7 -0
- data/lib/detroit/tool/core_ext/to_actual_filename.rb +19 -0
- data/lib/detroit/tool/core_ext/to_console.rb +97 -0
- data/lib/detroit/tool/core_ext/to_list.rb +29 -0
- data/lib/detroit/tool/core_ext/to_yamlfrag.rb +9 -0
- data/lib/detroit/tool/core_ext/unfold_paragraphs.rb +27 -0
- data/lib/detroit/tool/email_utils.rb +288 -0
- data/lib/detroit/tool/project_utils.rb +41 -0
- data/lib/detroit/tool/shell_utils.rb +235 -0
- data/qed/01_schedule/02_initialize.md +57 -0
- data/qed/99_plugins/rdoc/rdoc-plugin.rdoc +22 -0
- data/qed/99_plugins/rdoc/sample/Syckfile +6 -0
- data/qed/99_plugins/rdoc/sample/lib/sandbox/.xxx +1 -0
- data/qed/99_plugins/rdoc/sample/lib/sandbox/hello.rb +5 -0
- data/qed/99_plugins/rdoc/sample/lib/sandbox/xxx.rb +6 -0
- data/qed/99_plugins/rdoc/sample/lib/xxx/bye.rb +4 -0
- data/qed/99_plugins/rdoc/sample/meta/name +1 -0
- data/qed/99_plugins/rdoc/sample/meta/version +1 -0
- data/qed/samples/example_project/.ruby +0 -0
- data/qed/samples/example_project/Schedule +9 -0
- data/qed/samples/example_project/lib/foo/.xxx +1 -0
- data/qed/samples/example_project/lib/foo/hello.rb +7 -0
- data/qed/samples/example_project/lib/foo/xxx.rb +6 -0
- data/qed/samples/example_project/lib/foo/xxx/bye.rb +4 -0
- data/qed/samples/example_project/meta/name +1 -0
- data/qed/samples/example_project/meta/version +1 -0
- data/qed/samples/example_schedule.rb +57 -0
- metadata +139 -0
data/HISTORY.rdoc
ADDED
@@ -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
|
+
|
data/README.rdoc
ADDED
@@ -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.
|
data/bin/detroit
ADDED
data/lib/detroit.rb
ADDED
@@ -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
|
data/lib/detroit.yml
ADDED
@@ -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
|