detroit 0.3.0 → 0.4.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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/.index +59 -0
  3. data/EXAMPLE.md +66 -64
  4. data/{HISTORY.rdoc → HISTORY.md} +32 -5
  5. data/{COPYING.rdoc → LICENSE.txt} +0 -0
  6. data/README.md +142 -0
  7. data/bin/detroit +1 -1
  8. data/lib/detroit.rb +112 -40
  9. data/lib/detroit.yml +44 -29
  10. data/lib/detroit/assembly.rb +49 -193
  11. data/lib/detroit/basic_tool.rb +200 -0
  12. data/lib/detroit/basic_utils.rb +66 -0
  13. data/lib/detroit/core_ext.rb +2 -136
  14. data/lib/detroit/{tool/core_ext → core_ext}/facets.rb +3 -0
  15. data/lib/detroit/{tool/core_ext → core_ext}/filetest.rb +0 -0
  16. data/lib/detroit/{tool/core_ext → core_ext}/shell_extensions.rb +0 -0
  17. data/lib/detroit/{tool/core_ext → core_ext}/to_actual_filename.rb +0 -0
  18. data/lib/detroit/{tool/core_ext → core_ext}/to_console.rb +1 -0
  19. data/lib/detroit/{tool/core_ext → core_ext}/to_list.rb +0 -0
  20. data/lib/detroit/{tool/core_ext → core_ext}/to_yamlfrag.rb +0 -0
  21. data/lib/detroit/{tool/core_ext → core_ext}/unfold_paragraphs.rb +0 -0
  22. data/lib/detroit/{tool/email_utils.rb → email_utils.rb} +3 -1
  23. data/lib/detroit/exec.rb +55 -0
  24. data/lib/detroit/project.rb +134 -0
  25. data/lib/detroit/ruby_utils.rb +29 -0
  26. data/lib/detroit/{tool/shell_utils.rb → shell_utils.rb} +10 -5
  27. data/lib/detroit/toolchain.rb +6 -0
  28. data/lib/detroit/toolchain/cli.rb +320 -0
  29. data/lib/detroit/toolchain/config.rb +223 -0
  30. data/lib/detroit/toolchain/runner.rb +678 -0
  31. data/lib/detroit/toolchain/script.rb +248 -0
  32. data/lib/detroit/toolchain/worker.rb +84 -0
  33. data/man/detroit.1 +116 -0
  34. data/man/detroit.1.html +171 -0
  35. data/man/detroit.1.ronn +99 -0
  36. metadata +90 -51
  37. data/.ruby +0 -44
  38. data/README.rdoc +0 -132
  39. data/lib/detroit/application.rb +0 -463
  40. data/lib/detroit/assembly_system.rb +0 -80
  41. data/lib/detroit/config.rb +0 -203
  42. data/lib/detroit/control.rb +0 -129
  43. data/lib/detroit/custom.rb +0 -102
  44. data/lib/detroit/dsl.rb +0 -55
  45. data/lib/detroit/service.rb +0 -78
  46. data/lib/detroit/standard_assembly.rb +0 -51
  47. data/lib/detroit/tool.rb +0 -295
  48. data/lib/detroit/tool/core_ext.rb +0 -3
  49. data/lib/detroit/tool/project_utils.rb +0 -41
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'detroit'
3
3
  begin
4
- Detroit.cli(*ARGV)
4
+ Detroit::Toolchain.cli(ARGV)
5
5
  rescue => err
6
6
  raise err #if $DEBUG
7
7
  $stderr.puts err
@@ -11,54 +11,126 @@ module Detroit
11
11
  def self.const_missing(name)
12
12
  metadata[name.to_s.downcase] || super(name)
13
13
  end
14
-
15
- # TODO: Only here b/c of bug in Ruby 1.8.x
16
- #VERSION = "0.3.0"
17
14
  end
18
15
 
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'
16
+ require 'pathname'
17
+ require 'erb' # Erb is used to to script YAML-based schedule files.
18
+ require 'optparse' # OptionParser is used for command line parsing.
19
+ require 'yaml' # Yea like we don't all ride a YAML.
24
20
 
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'
21
+ require 'indexer' # Indexer is used to provide project metadata.
22
+ require 'ansi/terminal' # The ANSI gem is used to colorize terminal output.
30
23
  require 'ansi/code'
31
24
 
32
- # The parallel gem is used to (optionally) multitask services.
25
+ # The optional parallel gem is used to multitask services.
33
26
  begin
34
27
  require 'parallel'
35
28
  rescue LoadError
36
29
  end
37
30
 
38
- # POM is used to access project metadata.
39
- require 'pom'
40
-
41
- # And all the rest is Detroit, baby.
42
- if RUBY_VERSION > '1.9'
43
- require_relative 'detroit/core_ext'
44
- require_relative 'detroit/config'
45
- require_relative 'detroit/service'
46
- require_relative 'detroit/tool'
47
- require_relative 'detroit/assembly_system'
48
- require_relative 'detroit/standard_assembly'
49
- require_relative 'detroit/control'
50
- require_relative 'detroit/application'
51
- require_relative 'detroit/assembly'
52
- require_relative 'detroit/custom'
53
- else
54
- require 'detroit/core_ext'
55
- require 'detroit/config'
56
- require 'detroit/service'
57
- require 'detroit/tool'
58
- require 'detroit/assembly_system'
59
- require 'detroit/standard_assembly'
60
- require 'detroit/control'
61
- require 'detroit/application'
62
- require 'detroit/assembly'
63
- require 'detroit/custom'
31
+ require_relative 'detroit/core_ext'
32
+ require_relative 'detroit/project'
33
+ require_relative 'detroit/toolchain' #runner
34
+ require_relative 'detroit/exec'
35
+
36
+ require_relative 'detroit/basic_utils'
37
+ require_relative 'detroit/shell_utils'
38
+ require_relative 'detroit/email_utils'
39
+ require_relative 'detroit/ruby_utils'
40
+
41
+ require_relative 'detroit/basic_tool'
42
+
43
+
44
+ module Detroit
45
+
46
+ #
47
+ # Tool registry.
48
+ #
49
+ def self.tools
50
+ @tools ||= {}
51
+ end
52
+
53
+ #
54
+ # Define tool method.
55
+ #
56
+ def self.define_tool_method(name, tool_class)
57
+ (class << self; self; end).class_eval do
58
+ # raise or skip if method_defined?(name)
59
+ define_method(name) do |*a, &b|
60
+ tool_class.new(*a, &b)
61
+ end
62
+ end
63
+ end
64
+
65
+ #
66
+ # Add tool class to registry. If class name ends in `Tool` or `Base`
67
+ # it will be considered a reusable base class and not be added.
68
+ #
69
+ def self.register_tool(tool_class)
70
+ name = tool_class.basename
71
+ return if name.nil?
72
+ return if name.empty?
73
+ return if name =~ /Tool$/
74
+ return if name =~ /Base$/
75
+ tools[name.downcase] = tool_class
76
+ Tools.const_set(name, tool_class)
77
+ Detroit.define_tool_method(name, tool_class)
78
+ return tool_class
79
+ end
80
+
81
+ =begin
82
+ ##
83
+ # Per-project configuration for detroit.
84
+ #
85
+ # TODO: Do we really need this?
86
+ class Config < BasicObject
87
+ FILE = ".detroit"
88
+
89
+ def initialize(root)
90
+ @file = Dir.glob(root + FILE).first
91
+
92
+ if @file
93
+ @data = YAML.load_file(@file)
94
+ else
95
+ @data = {}
96
+ end
97
+ end
98
+
99
+ def method_missing(s, *a, &b)
100
+ @data[s.to_s]
101
+ end
102
+ end
103
+ =end
104
+
105
+ ##
106
+ # The Tools module provides an isolated namespace for Detoit's tools.
107
+ # This allows for general use of these tools by other applications,
108
+ # simply by including the Detroit::Tools module into their own namespace.
109
+ #
110
+ module Tools
111
+ end
112
+
113
+ ##
114
+ # The common base class for tools. Tool is a subclass of BasicTool that
115
+ # adds additional utility methods, in particular it adds {ShellUtils}.
116
+ # Unless there is a specific reason not to do so, this is the class
117
+ # that specific tool classes should subclass.
118
+ #
119
+ # A good tool will check to see if the state of the project is *current*
120
+ # or not to know if some stage of the tool needs to be used or not.
121
+ # For example a documentation# tool can look to see if any the files
122
+ # it would document are newer that the previous generated set of document
123
+ # file. In this case it can output a message explaining that the action
124
+ # was not needed. For example, the RDoc tool outputs the message:
125
+ # "RDocs are current (path/to/rdocs)". The tool can also support the
126
+ # `$FORCE` global to force the procedure regardless.
127
+ #
128
+ class Tool < BasicTool
129
+ include ShellUtils
130
+ end
131
+
64
132
  end
133
+
134
+ require_relative 'detroit/assembly'
135
+ #require_relative 'detroit/standard'
136
+
@@ -1,44 +1,59 @@
1
1
  ---
2
- source:
3
- - PROFILE
4
- - meta
2
+ revision: 2013
3
+ type: ruby
4
+ sources:
5
+ - var
5
6
  authors:
6
7
  - name: Trans
7
8
  email: transfire@gmail.com
8
- copyrights:
9
- - holder: Thomas Sawyer
10
- year: '2007'
11
- license: GPL3
9
+ organizations: []
12
10
  requirements:
13
11
  - name: facets
14
- - name: pom
15
- - name: qed
16
- groups:
12
+ - name: indexer
13
+ - groups:
17
14
  - test
18
15
  development: true
19
- dependencies: []
20
- alternatives: []
16
+ name: qed
17
+ - groups:
18
+ - build
19
+ development: true
20
+ name: detroit-yard
21
+ - groups:
22
+ - build
23
+ development: true
24
+ name: detroit-gem
21
25
  conflicts: []
26
+ alternatives: []
27
+ resources:
28
+ - type: home
29
+ uri: http://rubyworks.github.com/detroit
30
+ label: Homepage
31
+ - type: code
32
+ uri: http://github.com/rubyworks/detroit
33
+ label: Source Code
34
+ - type: mail
35
+ uri: http://groups.google.com/rubyworks-mailinglist
36
+ label: Mailing List
22
37
  repositories:
23
- - uri: http://github.com/proutils/detroit.git
38
+ - name: upstream
24
39
  scm: git
25
- name: upstream
26
- resources:
27
- home: http://rubyworks.github.com/detroit
28
- code: http://github.com/rubyworks/detroit
29
- mail: http://groups.google.com/rubyworks-mailinglist
30
- extra: {}
31
- load_path:
32
- - lib
33
- revision: 0
34
- created: '2007-10-10'
35
- summary: Software Production Mangement
36
- title: Detroit
37
- version: 0.3.0
40
+ uri: http://github.com/proutils/detroit.git
41
+ categories: []
42
+ copyrights:
43
+ - holder: Rubyworks
44
+ year: '2007'
45
+ license: GPL-3.0
46
+ customs: []
47
+ paths:
48
+ lib:
49
+ - lib
38
50
  name: detroit
39
- suite: detroit
51
+ title: Detroit
52
+ summary: Software Production Mangement
53
+ created: '2007-10-10'
40
54
  description: Detroit is an advanced lifecycle build system. With Detroit, build tasks
41
55
  are user defined service instances tied to stops along a track. Whenever the detroit
42
56
  console command is run, a track is followed from beginning to designated destination.
43
- organization: rubyworks
44
- date: '2012-04-01'
57
+ suite: detroit
58
+ version: 0.4.0
59
+ date: '2014-01-13'
@@ -1,219 +1,75 @@
1
1
  module Detroit
2
2
 
3
- # Assembly encapsulates a `Assembly` file and it's service instance
4
- # configurations.
5
- class Assembly
6
-
7
- # Load Scedule file.
8
- def self.load(input)
9
- new(input)
10
- end
11
-
12
- # Hash table of services.
13
- attr :services
14
-
15
- private
16
-
17
- # Initialize new Assembly instance.
18
- def initialize(file, options={})
19
- @project = options[:project]
20
-
21
- @services = {}
3
+ # Define an assembly.
4
+ #
5
+ # @return nothing.
6
+ def self.assembly(name, &block)
7
+ ass = Assembly.new(name, &block)
8
+ const_set(name, ass)
9
+ end
22
10
 
23
- @file = (String === file ? File.new(file) : file)
11
+ # Map of toolchain names to classes.
12
+ #
13
+ # @return [Hash<Symbol,Class>] All defined assemblies.
14
+ def self.assemblies
15
+ @assemblies ||= {}
16
+ end
24
17
 
25
- case File.extname(@file.path)
26
- when '.rb'
27
- instance_eval(@file.read, @file.path)
28
- when '.yml', '.yaml'
29
- @services = YAML.load(erb(@file.read))
30
- else
31
- text = @file.read
32
- if /^---/ =~ text
33
- @services = YAML.load(erb(text))
34
- else
35
- instance_eval(text, @file.path)
36
- end
37
- end
38
- end
18
+ ##
19
+ # An *assembly* is a set of production lines where each line is a list
20
+ # of named work stations.
21
+ #
22
+ class Assembly < Module
39
23
 
40
- # Define a service.
41
- def service(name, settings={}, &block)
42
- if block
43
- block_context = BlockContext.new(&block)
44
- settings.update(block_context.settings)
45
- end
46
- @services[name.to_s] = settings.rekey(&:to_s)
47
- end
24
+ def initialize(name, &block)
25
+ Detroit.assemblies[name.to_s.downcase.to_sym] = self
48
26
 
49
- alias_method :tool, :service
27
+ @lines = []
28
+ @tools = []
50
29
 
51
- #
52
- #
53
- #
54
- #
55
- def custom(name, &block)
56
- context = CustomContext.new(&block)
57
- settings = context.settings
58
- @services[name.to_s] = settings.rekey(&:to_s)
30
+ super(&block) #module_eval(&block)
59
31
  end
60
32
 
61
- # Access to project data.
62
- #
63
- # NOTE: Thinking that the project should be relative
64
- # to the Routine file itself, unless a `project` is passed
65
- # in manually through the initializer. In the mean time,
66
- # the project is just relative to the current working directory.
33
+ # Returns a list of lists of stops.
67
34
  #
68
- # TODO: Make configurable and use .ruby by default ?
69
- def project
70
- @project ||= POM::Project.find #(file_directory)
71
- end
72
-
73
- # Capitalized service names called as methods
74
- # can also define a service.
75
- def method_missing(sym, *args, &block)
76
- service_class = sym.to_s
77
- case service_class
78
- when /^[A-Z]/
79
- if Hash === args.last
80
- args.last[:service] = service_class
81
- else
82
- args << {:service=>service_class}
83
- end
84
- case args.first
85
- when String, Symbol
86
- name = args.first
87
- else
88
- name = service_class.to_s.downcase
89
- end
90
- service(name, *args, &block)
91
- else
92
- super(sym, *args, &block)
93
- end
35
+ # @return [Array<Array<Symbol>>] lines.
36
+ def lines
37
+ @lines
94
38
  end
95
39
 
96
- private
97
-
98
- # Process Routine document via ERB.
99
- def erb(text)
100
- context = ERBContext.new(project)
101
- ERB.new(text).result(context.__binding__)
40
+ # Define a chain of named links.
41
+ def line(*stations)
42
+ # TODO: raise error if stage already used ?
43
+ self.lines << stations.map{ |s| s.to_sym }
102
44
  end
103
45
 
104
- # ERBContext provides the clean context to process a Routine
105
- # as an ERB template.
106
- class ERBContext
107
- #
108
- def initialize(project)
109
- @project = project
110
- end
111
-
112
- # Access to a clean binding.
113
- def __binding__
114
- binding
115
- end
116
-
117
- # Provide access to project data.
118
- def project
119
- @project
120
- end
46
+ # Lookup a chain by a given stage name.
47
+ #
48
+ # @return nothing.
49
+ def find(station)
50
+ station = station.to_sym
121
51
 
122
- #
123
- def method_missing(name, *args)
124
- if project.respond_to?(name)
125
- project.__send__(name, *args)
126
- elsif project.metadata.respond_to?(name)
127
- project.metadata.__send__(name, *args)
128
- else
129
- super(name, *args)
130
- end
52
+ lines.find do |line|
53
+ line.include?(station)
131
54
  end
132
55
  end
133
56
 
57
+ # Add tool to toolchain.
134
58
  #
135
- class BlockContext
136
- #
137
- attr :settings
138
-
139
- #
140
- def initialize(&b)
141
- @settings = {}
142
- b.arity == 1 ? b.call(self) : instance_eval(&b)
143
- end
144
-
145
- #
146
- def set(name, value=nil, &block)
147
- if block
148
- block_context = BlockContext.new
149
- block.call(block_context)
150
- @settings[name.to_s] = block_context.settings
151
- else
152
- @settings[name.to_s] = value
153
- end
154
- end
155
-
156
- #
157
- def method_missing(symbol, value=nil, *args)
158
- case name = symbol.to_s
159
- when /=$/
160
- @settings[name.chomp('=')] = value
161
- else
162
- super(symbol, value=nil, *args)
163
- end
164
- end
59
+ # @return [Class] The tool class.
60
+ def register_tool(tool_class)
61
+ tool_class.assembly = self
62
+ @tools << tool_class
63
+ Detroit.register_tool(tool_class)
165
64
  end
166
65
 
66
+ # When the tool chain is included into a class, register
67
+ # that class as a tool.
167
68
  #
168
- class CustomContext
169
- #
170
- attr :settings
171
- #
172
- def initialize(&b)
173
- @settings = {}
174
- b.arity == 0 ? instance_eval(&b) : b.call(self)
175
- end
176
- #
177
- def method_missing(s,a=nil,*x,&b)
178
- case s.to_s
179
- when /=$/
180
- @settings[s.to_s.chomp('=').to_sym] = b ? b : a
181
- else
182
- return @settings[s] unless a
183
- @settings[s] = b ? b : a
184
- end
185
- end
186
- def respond_to?(s)
187
- @settings.key?(s.to_sym)
188
- end
69
+ # @return [void] The tool class.
70
+ def included(tool_class)
71
+ register_tool(tool_class) unless @tools.include?(tool_class)
189
72
  end
190
-
191
73
  end
192
74
 
193
- # NOTE: This is problematic, because a Scheudle file should really know from
194
- # what file it was derived.
195
-
196
- #
197
- DOMAIN = "rubyworks.github.com/detroit,2011-05-27"
198
-
199
- # TODO: If using Psych rather than Syck, then define a domain type.
200
-
201
- #if defined?(Psych) #RUBY_VERSION >= '1.9'
202
- # YAML::add_domain_type(DOMAIN, "assembly") do |type, hash|
203
- # Assembly.load(hash)
204
- # end
205
- #else
206
- YAML::add_builtin_type("assembly") do |type, value|
207
- value
208
- #case value
209
- #when String
210
- # Assembly.eval(value)
211
- #when Hash
212
- # Assembly.new(value)
213
- #else
214
- # raise "ERROR: Invalid Assembly"
215
- #end
216
- end
217
- #end
218
-
219
75
  end