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,80 +0,0 @@
1
- module Detroit
2
-
3
- # All assemblies and tracks have a maintenance sub-track.
4
- # For this reason stop names `reset`, `clean` and `purge`
5
- # are reserved names and MUST not be used as stop names
6
- # in defining custom lines.
7
- MAINTENANCE_TRACK = [:reset, :clean, :purge]
8
-
9
- # Returns Hash of name and Circuit instance pairs.
10
- def self.assembly_systems
11
- @assembly_system ||= {}
12
- end
13
-
14
- # Define a new assembly system.
15
- def self.assembly_system(name, &block)
16
- assembly_systems[name.to_sym] = AssemblySystem.new(name, &block)
17
- end
18
-
19
- # The AssemblySystem class encapsulates a set of interrelated
20
- # assembly lines, or _tracks_.
21
- class AssemblySystem
22
-
23
- # Name of the assembly system.
24
- attr :name
25
-
26
- # Returns a Hash of track names mapped to list of stops.
27
- attr :lines
28
-
29
- # Lines are also called `tracks`.
30
- alias_method :tracks, :lines
31
-
32
- # Create a new instance.
33
- def initialize(name, &block)
34
- @name = name.to_sym
35
- @lines = {:maintenance => MAINTENANCE_TRACK}
36
- instance_eval(&block) if block
37
- end
38
-
39
- # Define an assembly line.
40
- def line(name, *stops)
41
- if stops.empty?
42
- @lines[name.to_sym]
43
- else
44
- @lines[name.to_sym] = stops.map{ |s| s.to_sym }
45
- end
46
- end
47
-
48
- # Lines are also called tracks.
49
- alias_method :track, :line
50
-
51
- # Lookup track by name and (optional) stop. If the stop belongs
52
- # to the maintenance sub-track then the maintenance sub-track will
53
- # be returned instead of the track itself.
54
- #
55
- # The Application class uses this to simplify track lookup.
56
- def get_track(name, stop=nil)
57
- name = name.to_sym
58
- if stop
59
- stop = stop.to_sym
60
- if MAINTENANCE_TRACK.include?(stop.to_sym)
61
- track = MAINTENANCE_TRACK
62
- else
63
- track = tracks[name]
64
- raise "Unknown track `#{name}'." unless track
65
- unless track.include?(stop)
66
- raise "Unknown stop `#{stop}` for track `#{name}'."
67
- end
68
- end
69
- else
70
- track = tracks[name]
71
- end
72
- track
73
- end
74
-
75
- # Did I mention that `line` and `track` are synonyms?
76
- alias_method :get_line, :get_track
77
-
78
- end
79
-
80
- end
@@ -1,203 +0,0 @@
1
- module Detroit
2
-
3
- # Detroit configuration. Configuration comes from a main +Routine+
4
- # and/or +.routine+ files.
5
- class Config
6
- #instance_methods.each{ |m| private m unless /^__/ =~ m.to_s }
7
-
8
- # Configuration directory name (most likely a hidden "dot" directory).
9
- DIRECTORY = "detroit"
10
-
11
- # File identifier used to find a project's Assembly(s).
12
- FILE_EXTENSION = "assembly"
13
-
14
- # Current POM::Project object.
15
- #attr :project
16
-
17
- # The list of a project's assembly files.
18
- #
19
- # @return [Array<String>] routine files
20
- attr :assemblies
21
-
22
- # Service configurations from Assembly or *.assembly files.
23
- #
24
- # @return [Hash] service settings
25
- attr :services
26
-
27
- # Service defaults. This is a mapping of service names to
28
- # default settings. Very useful for when using the same
29
- # service more than once.
30
- #
31
- # @return [Hash] default settings
32
- attr :defaults
33
-
34
- #
35
- def initialize(assembly_files=nil)
36
- if assembly_files && !assembly_files.empty?
37
- @assembly_filenames = assembly_files
38
- else
39
- @assembly_filenames = nil
40
- end
41
-
42
- @assemblies = {}
43
- @services = {}
44
- @defaults = {}
45
-
46
- @loaded_plugins = {}
47
-
48
- load_plugins
49
- load_defaults
50
- load_assemblies
51
- end
52
-
53
- #--
54
- # TODO: Use this, or pass in via initialize?
55
- #++
56
- def project
57
- Detroit.project
58
- end
59
-
60
- # Load a plugin.
61
- def load_plugin(name)
62
- @loaded_plugins[name] ||= (
63
- begin
64
- require "detroit-#{name}"
65
- rescue LoadError => e
66
- $stderr.puts "ERROR: #{e.message.capitalize}"
67
- $stderr.puts " Perhaps `gem install detroit-#{name}`?"
68
- exit -1
69
- end
70
- name # true ?
71
- )
72
- end
73
-
74
- # Pre-load plugins using `.detroit/plugins.rb`.
75
- def load_plugins
76
- if file = project.root.glob('{.,}#{DIRECTORY}/plugins{,.rb}').first
77
- require file
78
- else
79
- self.defaults = {}
80
- end
81
- end
82
-
83
- # Load defaults from `.detroit/defaults.yml`.
84
- def load_defaults
85
- if file = project.root.glob('{.,}#{DIRECTORY}/defaults{,.yml,.yaml}').first
86
- self.defaults = YAML.load(File.new(file))
87
- else
88
- self.defaults = {}
89
- end
90
- end
91
-
92
- #
93
- def load_assemblies
94
- assembly_filenames.each do |file|
95
- load_assembly_file(file)
96
- end
97
- end
98
-
99
- #
100
- def load_assembly_file(file)
101
- @assemblies[file] = Assembly.load(File.new(file))
102
- @services.merge!(assemblies[file].services)
103
- end
104
-
105
- # Set defaults.
106
- def defaults=(hash)
107
- @defaults = hash.to_h
108
- end
109
-
110
- # If a `Assembly` or `.assembly` file exists, then it is returned. Otherwise
111
- # all `*.assembly` files are loaded. To load `*.assembly` files from another
112
- # directory add the directory to config options file.
113
- def assembly_filenames
114
- @assembly_filenames ||= (
115
- files = []
116
- ## match 'Assembly' or '.assembly' file
117
- files = project.root.glob("{,.,*.}#{FILE_EXTENSION}{,.rb,.yml,.yaml}", :casefold)
118
- ## only files
119
- files = files.select{ |f| File.file?(f) }
120
- ##
121
- if files.empty?
122
- ## match '.detroit/*.assembly' or 'detroit/*.assembly'
123
- files += project.root.glob("{,.}#{DIRECTORY}/*.#{FILE_EXTENSION}", :casefold)
124
- ## match 'task/*.assembly' (OLD SCHOOL)
125
- files += project.root.glob("{task,tasks}/*.#{FILE_EXTENSION}", :casefold)
126
- ## only files
127
- files = files.select{ |f| File.file?(f) }
128
- end
129
- files
130
- )
131
- end
132
-
133
- #
134
- def each(&block)
135
- services.each(&block)
136
- end
137
-
138
- #
139
- def size
140
- services.size
141
- end
142
-
143
- =begin
144
- # If using a `Routine` file and want to import antoher file then use
145
- # `import:` entry.
146
- def load_detroit_file(file)
147
- #@dir = File.dirname(file)
148
-
149
- assemblies[file] =
150
-
151
- # TODO: can we just read the first line of the file and go from there?
152
- #text = File.read(file).strip
153
-
154
- ## if yaml vs. ruby file
155
- #if (/\A---/ =~ text || /\.(yml|yaml)$/ =~ File.extname(file))
156
- # #data = parse_detroit_file_yaml(text, file)
157
- # YAML.load(text)
158
- #else
159
- # data = parse_detroit_file_ruby(text, file)
160
- #end
161
-
162
- ## extract defaults
163
- #if defaults = data.delete('defaults')
164
- # @defaults.merge!(defaults)
165
- #end
166
-
167
- ## import other files
168
- #if import = data.delete('import')
169
- # [import].flatten.each do |glob|
170
- # routine(glob)
171
- # end
172
- #end
173
-
174
- ## require plugins
175
- #if plugins = data.delete('plugins')
176
- # [plugins].flatten.each do |file|
177
- # require file
178
- # end
179
- #end
180
-
181
- #@services.update(data)
182
- end
183
- =end
184
-
185
- ## Parse a YAML-based routine.
186
- #def parse_detroit_file_yaml(text, file)
187
- # YAMLParser.parse(self, text, file)
188
- #end
189
-
190
- ## Parse a Ruby-based routine.
191
- #def parse_detroit_file_ruby(text, file)
192
- # RubyParser.parse(self, text, file)
193
- #end
194
-
195
- ## TODO: Should the +dir+ be relative to the file or project.root?
196
- #def routine(glob)
197
- # pattern = File.join(@dir, glob)
198
- # Dir[pattern].each{ |f| load_detroit_file(f) }
199
- #end
200
-
201
- end
202
-
203
- end
@@ -1,129 +0,0 @@
1
- module Detroit
2
-
3
- # The control module is a function module that extends
4
- # the toplevel Detroit namespace module.
5
- module Control
6
-
7
- # Location of standard plugins.
8
- #PLUGIN_DIRECTORY = File.dirname(__FILE__) + '/plugins'
9
-
10
- # Returns Array of standard plugin file names.
11
- #def standard_plugins
12
- # Dir[PLUGIN_DIRECTORY + '/*.rb']
13
- #end
14
-
15
- # Universal acccess to the current project.
16
- #
17
- # TODO: Is Control#project being used?
18
- def project
19
- @project ||= POM::Project.find
20
- end
21
-
22
- # Returns Application given options.
23
- def application(options={})
24
- Application.new(options)
25
- end
26
-
27
- # Run the command line interface.
28
- def cli(*argv)
29
- cli_options = {
30
- :system => nil, :assemblies => [],
31
- :trace=>nil, :trial=>nil, :debug=>nil, :quiet=>nil, :verbose=>nil,
32
- :force=>nil, :multitask=>nil, :skip=>[]
33
- }
34
-
35
- usage = cli_usage(cli_options)
36
- usage.parse!(argv)
37
-
38
- #if /\.assembly$/ =~ argv[0]
39
- # job = argv[1]
40
- # begin
41
- # application(cli_options).runscript(argv[0], job)
42
- # rescue => error
43
- # $stderr.puts error.message
44
- # exit -1
45
- # end
46
- #else
47
- begin
48
- application(cli_options).start(*argv)
49
- rescue => error
50
- if $DEBUG
51
- raise error
52
- else
53
- $stderr.puts error.message
54
- exit -1
55
- end
56
- end
57
- #end
58
- end
59
-
60
- # Returns an instance of OptionParser.
61
- def cli_usage(options)
62
- @usage ||= (
63
- OptionParser.new do |usage|
64
- usage.banner = "Usage: detroit [<track>:]<stop> [options]"
65
- usage.on('-m', '--multitask', "Run work elements in parallel.") do
66
- options[:multitask] = true
67
- end
68
- usage.on('-S', '--skip [SERVICE]', 'Skip a service.') do |skip|
69
- options[:skip] << skip
70
- end
71
-
72
- usage.on('-s', '--system=NAME', "Select assembly system. Default is `standard'.") do |system|
73
- options[:system] = system
74
- end
75
- usage.on('-a', '--assembly [FILE]', 'Use specific assembly file(s).') do |file|
76
- options[:assemblies] << file
77
- end
78
-
79
- usage.on('-F', '--force', "Force operations.") do
80
- options[:force] = true
81
- end
82
- usage.on('--trace', "Run in TRACE mode.") do
83
- #$TRACE = true
84
- options[:trace] = true
85
- end
86
- usage.on('--trial', "Run in TRIAL mode (no disk writes).") do
87
- #$TRIAL = true
88
- options[:trial] = true
89
- end
90
- # TODO: do we really need verbose?
91
- usage.on('--verbose', "Provide extra output.") do
92
- options[:verbose] = true
93
- end
94
- usage.on('-q', '--quiet', "Run silently.") do
95
- options[:quiet] = true
96
- end
97
-
98
- usage.on('-I=PATH', "Add directory to $LOAD_PATH") do |dirs|
99
- dirs.to_list.each do |dir|
100
- $LOAD_PATH.unshift(dir)
101
- end
102
- end
103
- usage.on('--debug', "Run with $DEBUG set to true.") do
104
- $DEBUG = true
105
- options[:debug] = true # DEPRECATE?
106
- end
107
- usage.on('--warn', "Run with $VERBOSE set to true.") do
108
- $VERBOSE = true # wish this were called $WARN
109
- end
110
- usage.on_tail('--help [TOOL]', "Display this help message.") do |tool|
111
- if tool
112
- application.display_help(tool)
113
- else
114
- puts usage
115
- end
116
- exit
117
- end
118
- usage.on_tail('-c', '--config TOOL', "Produce a configuration template.") do |tool|
119
- puts application.config_template(tool).to_yaml
120
- exit
121
- end
122
- end
123
- )
124
- end
125
-
126
- end
127
-
128
- extend Control
129
- end
@@ -1,102 +0,0 @@
1
- module Detroit
2
-
3
- # Custom tool is used to create "quicky" services.
4
- #
5
- # This is a useful alternative to writing a full-blown plugin
6
- # when the need is simple.
7
- #
8
- class Custom < Tool
9
-
10
- # Default track(s) in which this plugin operates.
11
- DEFAULT_TRACK = "main"
12
-
13
- # Which track(s) to run this custom plugin.
14
- attr_accessor :track
15
-
16
- # Special writer to allow single track or a list of tracks.
17
- def track=(val)
18
- @track = val.to_list #[val].flatten
19
- end
20
-
21
- # Plural alias for #track.
22
- alias_accessor :tracks, :track
23
-
24
- alias_accessor :on, :track
25
-
26
- private
27
-
28
- SPECIAL_OPTIONS = %w{
29
- service track tracks on active priority project
30
- trial trace verbose force quiet
31
- }
32
-
33
- # Instantiate new custom plugin.
34
- #
35
- # FIXME: Custom#initialize seems to be running twice at startup. Why?
36
- #
37
- # This works by interpreting the service configuration as a hash of
38
- # stop names to ruby code.
39
- #
40
- def initialize(options)
41
- super(options)
42
- options.each do |stop, script|
43
- # skip specific names used for configuration
44
- next if SPECIAL_OPTIONS.include? stop
45
- # remaining options are names of track stops
46
- #tracks.each do |t|
47
- src = %{
48
- def station_#{stop}
49
- #{script}
50
- end
51
- }
52
- (class << self; self; end).module_eval(src)
53
- #end
54
- end
55
- end
56
-
57
- # Set initial attribute defaults.
58
- def initialize_defaults
59
- @track = [DEFAULT_TRACK]
60
- end
61
-
62
- #
63
- def method_missing(s, *a, &b)
64
- if s.to_s.end_with?('=')
65
- # stop = s.to_s.chomp('=')
66
- # if !SPECIAL_OPTIONS.include?(stop)
67
- # (class << self; self; end).module_eval %{
68
- # def station_#{stop}
69
- # #{a.first}
70
- # end
71
- # }
72
- # end
73
- else
74
- if @context.respond_to?(s)
75
- @context.__send__(s,*a,&b)
76
- else
77
- super(s, *a, &b)
78
- end
79
- end
80
- end
81
-
82
- # @todo should only respond to stop names and special options.
83
- #def respond_to?(s)
84
- # return true if SPECIAL_OPTIONS.include?(s.to_s)
85
- # return true
86
- #end
87
-
88
- # RUBY 1.9
89
- def respond_to_missing?(name, privy)
90
- #return true if name.to_s.start_with?('station_')
91
- return true if name.to_s.end_with?('=')
92
- return true if @context.respond_to?(name)
93
- false
94
- end
95
-
96
- def inspect
97
- "#<Custom @on=#{track.join(',')}>"
98
- end
99
-
100
- end
101
-
102
- end