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,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
@@ -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,3 @@
1
+ Dir[File.dirname(__FILE__) + '/core_ext/**/*.rb'].each do |file|
2
+ require file
3
+ 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,7 @@
1
+ require 'facets/pathname'
2
+ require 'facets/filetest'
3
+ require 'facets/fileutils'
4
+
5
+ # DEPRECATE: when new #glob is working.
6
+ require 'facets/dir/multiglob'
7
+
@@ -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
+