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
@@ -0,0 +1,52 @@
|
|
1
|
+
module Detroit
|
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
|
6
|
+
|
7
|
+
# Main track.
|
8
|
+
#
|
9
|
+
# TODO: Should :install comes before :verify b/c verfication might
|
10
|
+
# require a local installation?
|
11
|
+
track :main,
|
12
|
+
:prepare, # prepare services / ensure service requirements
|
13
|
+
:generate, # code generation
|
14
|
+
:compile, # compile source code
|
15
|
+
:test, # run tests and specifications
|
16
|
+
:analyze, # perform code analysis
|
17
|
+
:document, # generate documentation
|
18
|
+
:package, # create packages
|
19
|
+
:verify, # post package verification / integration tests
|
20
|
+
:install, # install the package locally (if need be)
|
21
|
+
:publish, # publish website/documentation
|
22
|
+
:release, # release packages
|
23
|
+
:deploy, # deploy system to servers
|
24
|
+
:promote # tell the world about your awesome work
|
25
|
+
|
26
|
+
# The site track is a subset of the main track used to
|
27
|
+
# isolate the distribution of documentation and uploading
|
28
|
+
# a project's website.
|
29
|
+
#
|
30
|
+
# prepare -> generate -> analyze -> document -> publish
|
31
|
+
#
|
32
|
+
track :site,
|
33
|
+
:prepare,
|
34
|
+
:generate,
|
35
|
+
:analyze,
|
36
|
+
:document,
|
37
|
+
:publish
|
38
|
+
|
39
|
+
# The attention track is a small subset of main track, used to
|
40
|
+
# isolate the sending of promotional materials, mainly release
|
41
|
+
# announcements.
|
42
|
+
#
|
43
|
+
# prepare -> generate -> promote
|
44
|
+
#
|
45
|
+
track :attn,
|
46
|
+
:prepare,
|
47
|
+
:generate,
|
48
|
+
:promote
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
data/lib/detroit/tool.rb
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
module Detroit
|
2
|
+
|
3
|
+
require 'detroit/tool/core_ext'
|
4
|
+
require 'detroit/tool/shell_utils'
|
5
|
+
require 'detroit/tool/project_utils'
|
6
|
+
require 'detroit/tool/email_utils'
|
7
|
+
|
8
|
+
# The Toold module provide an isolated namespace for
|
9
|
+
# Detoit's tools. This allows for general use of these
|
10
|
+
# tools by other applications, by including them into
|
11
|
+
# their own namespace.
|
12
|
+
module Tools
|
13
|
+
end
|
14
|
+
|
15
|
+
# Tool registry.
|
16
|
+
def self.tools
|
17
|
+
@tools ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
def self.services
|
22
|
+
tools
|
23
|
+
end
|
24
|
+
|
25
|
+
# Add tool class to registry. If class name ends in `Tool`
|
26
|
+
# it will be considered a reusable base class and not be added.
|
27
|
+
def self.register_tool(tool_class)
|
28
|
+
name = tool_class.basename
|
29
|
+
return if name.empty?
|
30
|
+
return if name =~ /(Tool|Service)$/
|
31
|
+
tools[name.downcase] = tool_class
|
32
|
+
Tools.const_set(name, tool_class)
|
33
|
+
# TODO: Should we auto-create convenience method?
|
34
|
+
return tool_class
|
35
|
+
end
|
36
|
+
|
37
|
+
# This base class can be used for tools that do not need
|
38
|
+
# all of the utility methods provided by the regular Tool
|
39
|
+
# class.
|
40
|
+
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!
|
48
|
+
end
|
49
|
+
@assembly
|
50
|
+
end
|
51
|
+
|
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
|
60
|
+
|
61
|
+
# Override this method if the tools availability is conditional.
|
62
|
+
def self.available?
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
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
|
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
|
77
|
+
|
78
|
+
# When inherited, add class to tool registry.
|
79
|
+
def self.inherited(base)
|
80
|
+
Detroit.register_tool(base)
|
81
|
+
end
|
82
|
+
|
83
|
+
# TODO: Needed? Rename?
|
84
|
+
def service_title
|
85
|
+
self.class.name
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Tool is the base class for all Detroit tools.
|
90
|
+
#
|
91
|
+
# Tool class is essentially the same as a Service class except that it is
|
92
|
+
# a subclass of RedTools::Tool. Use this class to build Detroit services
|
93
|
+
# with all the conveniences of a RedTools::Tool.
|
94
|
+
class Tool < BasicTool
|
95
|
+
include ShellUtils
|
96
|
+
include ProjectUtils
|
97
|
+
include EmailUtils
|
98
|
+
|
99
|
+
public
|
100
|
+
|
101
|
+
#
|
102
|
+
attr :options
|
103
|
+
|
104
|
+
# If applicable tools should override #current to allow tool users
|
105
|
+
# to know if the tool needs to be used. For example the RDoc tool
|
106
|
+
# can look to see if any the files it would document are newer that
|
107
|
+
# the previous generated set of docs.
|
108
|
+
#
|
109
|
+
# The method can return a String instead of `true`, to convey a
|
110
|
+
# custom message explaining that the tool need not be run. For example,
|
111
|
+
# the RDoc tool returns "RDocs are current (path/to/rdocs)".
|
112
|
+
def current?
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
# Create a new tool object.
|
119
|
+
#
|
120
|
+
# This sets up utility extensions and assigns options to setter attributes
|
121
|
+
# if they exist and values are not nil. That last point is important.
|
122
|
+
# You must use 'false' to purposely negate an option, as +nil+ will instead
|
123
|
+
# allow any default setting to be used.
|
124
|
+
#
|
125
|
+
def initialize(options={})
|
126
|
+
initialize_extension_defaults
|
127
|
+
|
128
|
+
initialize_requires
|
129
|
+
initialize_defaults
|
130
|
+
|
131
|
+
initialize_options(options)
|
132
|
+
|
133
|
+
initialize_extensions
|
134
|
+
end
|
135
|
+
|
136
|
+
# 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
|
138
|
+
# subclassing makes things more complicated.
|
139
|
+
def initialize_options(options)
|
140
|
+
@options = options
|
141
|
+
|
142
|
+
options.each do |k, v|
|
143
|
+
#send("#{k}=", v) unless v.nil? #if respond_to?("#{k}=") && !v.nil?
|
144
|
+
if respond_to?("#{k}=")
|
145
|
+
send("#{k}=", v) unless v.nil? #if respond_to?("#{k}=") && !v.nil?
|
146
|
+
else
|
147
|
+
warn "#{self.class.name} does not respond to `#{k}`."
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
#
|
153
|
+
def initialize_extension_defaults
|
154
|
+
super if defined?(super)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Require support libraries needed by this service.
|
158
|
+
#
|
159
|
+
# def initialize_requires
|
160
|
+
# require 'ostruct'
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
def initialize_requires
|
164
|
+
end
|
165
|
+
|
166
|
+
# When subclassing, put default instance variable settngs here.
|
167
|
+
#
|
168
|
+
# Examples
|
169
|
+
#
|
170
|
+
# def initialize_defaults
|
171
|
+
# @gravy = true
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
def initialize_defaults
|
175
|
+
end
|
176
|
+
|
177
|
+
# --- Odd Utilities -------------------------------------------------------
|
178
|
+
|
179
|
+
require 'facets/platform'
|
180
|
+
|
181
|
+
# Current platform.
|
182
|
+
def current_platform
|
183
|
+
Platform.local.to_s
|
184
|
+
end
|
185
|
+
|
186
|
+
# TODO: Is naming_policy really useful?
|
187
|
+
# TODO: How to set this in a more universal manner?
|
188
|
+
#
|
189
|
+
def naming_policy(*policies)
|
190
|
+
if policies.empty?
|
191
|
+
@naming_policy ||= ['down', 'ext']
|
192
|
+
else
|
193
|
+
@naming_policy = policies
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
#
|
199
|
+
def apply_naming_policy(name, ext)
|
200
|
+
naming_policy.each do |policy|
|
201
|
+
case policy.to_s
|
202
|
+
when /^low/, /^down/
|
203
|
+
name = name.downcase
|
204
|
+
when /^up/
|
205
|
+
name = name.upcase
|
206
|
+
when /^cap/
|
207
|
+
name = name.capitalize
|
208
|
+
when /^ext/
|
209
|
+
name = name + ".#{ext}"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
name
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# I know some people will be deterred by the dependency on Facets b/c they
|
2
|
+
# see it as a "heavy" dependency. But really that is far from true, consider
|
3
|
+
# the facet that the following libs are all that it used.
|
4
|
+
|
5
|
+
require 'facets/array/not_empty'
|
6
|
+
require 'facets/module/basename'
|
7
|
+
require 'facets/module/alias_accessor'
|
8
|
+
require 'facets/kernel/yes' # pulls in #ask and #no? too.
|
9
|
+
require 'facets/kernel/silence' # FIXME ???
|
10
|
+
require 'facets/kernel/disable_warnings'
|
11
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FileTest
|
2
|
+
|
3
|
+
# Return a cached list of the PATH environment variable.
|
4
|
+
# This is a support method used by #bin?
|
5
|
+
def command_paths
|
6
|
+
@command_paths ||= ENV['PATH'].split(/[:;]/)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Is a file a bin/ executable?
|
10
|
+
#
|
11
|
+
# TODO: Make more robust. Probably needs to be fixed for Windows.
|
12
|
+
def bin?(fname)
|
13
|
+
is_bin = command_paths.any? do |f|
|
14
|
+
FileTest.exist?(File.join(f, fname))
|
15
|
+
end
|
16
|
+
#is_bin ? File.basename(fname) : false
|
17
|
+
is_bin ? fname : false
|
18
|
+
end
|
19
|
+
|
20
|
+
## Is a file a task?
|
21
|
+
#
|
22
|
+
#def task?(path)
|
23
|
+
# task = File.dirname($0) + "/#{path}"
|
24
|
+
# task.chomp!('!')
|
25
|
+
# task if FileTest.file?(task) && FileTest.executable?(task)
|
26
|
+
#end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
# Find actual filename (casefolding) and returns it.
|
4
|
+
# Returns nil if no file is found.
|
5
|
+
|
6
|
+
def to_actual_filename
|
7
|
+
Dir.glob(self, File::FNM_CASEFOLD).first
|
8
|
+
end
|
9
|
+
|
10
|
+
# Find actual filename (casefolding) and replace string with it.
|
11
|
+
# If file not found, string remains the same and method returns nil.
|
12
|
+
|
13
|
+
def to_actual_filename!
|
14
|
+
filename = to_actual_filename
|
15
|
+
replace(filename) if filename
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# TODO: Improve the naming scheme of these methods.
|
2
|
+
|
3
|
+
#
|
4
|
+
class Array #:nodoc:
|
5
|
+
|
6
|
+
# Convert an array into commandline parameters.
|
7
|
+
# The array is accepted in the format of Ruby
|
8
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
9
|
+
|
10
|
+
def to_console
|
11
|
+
#flags = (Hash===last ? pop : {})
|
12
|
+
#flags = flags.to_console
|
13
|
+
#flags + ' ' + join(" ")
|
14
|
+
to_argv.join(' ')
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: DEPRECATE
|
18
|
+
alias_method :to_params, :to_console
|
19
|
+
|
20
|
+
#
|
21
|
+
def to_argv
|
22
|
+
flags = (Hash===last ? pop : {})
|
23
|
+
flags = flags.to_argv
|
24
|
+
flags + self
|
25
|
+
end
|
26
|
+
|
27
|
+
# def to_console
|
28
|
+
# flags = (Hash===last ? pop : {})
|
29
|
+
# flags = flags.collect do |f,v|
|
30
|
+
# m = f.to_s.size == 1 ? '-' : '--'
|
31
|
+
# case v
|
32
|
+
# when Array
|
33
|
+
# v.collect{ |e| "#{m}#{f} '#{e}'" }.join(' ')
|
34
|
+
# when true
|
35
|
+
# "#{m}#{f}"
|
36
|
+
# when false, nil
|
37
|
+
# ''
|
38
|
+
# else
|
39
|
+
# "#{m}#{f} '#{v}'"
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# return (flags + self).join(" ")
|
43
|
+
# end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Hash
|
48
|
+
|
49
|
+
# Convert a Hash into command line arguments.
|
50
|
+
# The array is accepted in the format of Ruby
|
51
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
52
|
+
def to_console
|
53
|
+
to_argv.join(' ')
|
54
|
+
end
|
55
|
+
|
56
|
+
# Convert a Hash into command line parameters.
|
57
|
+
# The array is accepted in the format of Ruby
|
58
|
+
# method arguments --ie. [arg1, arg2, ..., hash]
|
59
|
+
def to_argv
|
60
|
+
flags = []
|
61
|
+
each do |f,v|
|
62
|
+
m = f.to_s.size == 1 ? '-' : '--'
|
63
|
+
case v
|
64
|
+
when Array
|
65
|
+
v.each{ |e| flags << "#{m}#{f}='#{e}'" }
|
66
|
+
when true
|
67
|
+
flags << "#{m}#{f}"
|
68
|
+
when false, nil
|
69
|
+
# nothing
|
70
|
+
else
|
71
|
+
flags << "#{m}#{f}='#{v}'"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
flags
|
75
|
+
end
|
76
|
+
|
77
|
+
# Turn a hash into arguments.
|
78
|
+
#
|
79
|
+
# h = { :list => [1,2], :base => "HI" }
|
80
|
+
# h.argumentize #=> [ [], { :list => [1,2], :base => "HI" } ]
|
81
|
+
# h.argumentize(:list) #=> [ [1,2], { :base => "HI" } ]
|
82
|
+
#
|
83
|
+
def argumentize(args_field=nil)
|
84
|
+
config = dup
|
85
|
+
if args_field
|
86
|
+
args = [config.delete(args_field)].flatten.compact
|
87
|
+
else
|
88
|
+
args = []
|
89
|
+
end
|
90
|
+
args << config
|
91
|
+
return args
|
92
|
+
end
|
93
|
+
|
94
|
+
alias_method :command_vector, :argumentize
|
95
|
+
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
def to_list
|
4
|
+
self
|
5
|
+
end
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
class NilClass
|
10
|
+
|
11
|
+
def to_list
|
12
|
+
[]
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class String
|
18
|
+
|
19
|
+
# Helper method for cleaning list options.
|
20
|
+
# This will split the option on ':' or ';'
|
21
|
+
# if it is a string, rather than an array.
|
22
|
+
# And it will make sure there are no nil elements.
|
23
|
+
|
24
|
+
def to_list
|
25
|
+
split(/[:;,\n]/)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|