detroit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,9 @@
1
+ class Object
2
+
3
+ #
4
+ def to_yamlfrag
5
+ to_yaml.sub("---",'').rstrip
6
+ end
7
+
8
+ end
9
+
@@ -0,0 +1,27 @@
1
+ # TODO: Replace with facets/string/unfold
2
+
3
+ class String
4
+
5
+ #
6
+ def unfold_paragraphs
7
+ blank = false
8
+ text = ''
9
+ split(/\n/).each do |line|
10
+ if /\S/ !~ line
11
+ text << "\n\n"
12
+ blank = true
13
+ else
14
+ if /^(\s+|[*])/ =~ line
15
+ text << (line.rstrip + "\n")
16
+ else
17
+ text << (line.rstrip + " ")
18
+ end
19
+ blank = false
20
+ end
21
+ end
22
+ text = text.gsub("\n\n\n","\n\n")
23
+ return text
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,288 @@
1
+ module Detroit
2
+
3
+ # The Mail utility module provides an easy to use +email+ method.
4
+ module EmailUtils
5
+
6
+ # Email function to easily send out an email.
7
+ #
8
+ # Settings:
9
+ #
10
+ # subject Subject of email message.
11
+ # from Message FROM address [email].
12
+ # to Email address to send announcemnt.
13
+ # server Email server to route message.
14
+ # port Email server's port.
15
+ # domain Email server's domain name.
16
+ # account Email account name if needed.
17
+ # password Password for login..
18
+ # login Login type: plain, cram_md5 or login [plain].
19
+ # secure Uses TLS security, true or false? [false]
20
+ # message Mesage to send -or-
21
+ # file File that contains message.
22
+ #
23
+ def email(options)
24
+ #options[:file] = localize(options[:file]) if options[:file]
25
+ emailer = Emailer.new(options.rekey)
26
+ success = emailer.email
27
+ if Exception === success
28
+ puts "Email failed: #{success.message}."
29
+ else
30
+ puts "Email sent successfully to #{success.join(';')}."
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ # Emailer class makes it easy send out an email.
37
+ #
38
+ # Settings:
39
+ #
40
+ # subject Subject of email message.
41
+ # from Message FROM address [email].
42
+ # to Email address to send announcemnt.
43
+ # server Email server to route message.
44
+ # port Email server's port.
45
+ # port_secure Email server's port.
46
+ # domain Email server's domain name.
47
+ # account Email account name if needed.
48
+ # password Password for login..
49
+ # login Login type: plain, cram_md5 or login [plain].
50
+ # secure Uses TLS security, true or false? [false]
51
+ # message Mesage to send -or-
52
+ # file File that contains message.
53
+ #
54
+ class Emailer
55
+
56
+ class << self
57
+ # Used for caching password between usages.
58
+ attr_accessor :password
59
+
60
+ #
61
+ def environment_options
62
+ options = {}
63
+ options[:server] = ENV['EMAIL_SERVER']
64
+ options[:from] = ENV['EMAIL_FROM']
65
+ options[:account] = ENV['EMAIL_ACCOUNT'] || ENV['EMAIL_FROM']
66
+ options[:password] = ENV['EMAIL_PASSWORD']
67
+ options[:port] = ENV['EMAIL_PORT']
68
+ options[:domain] = ENV['EMAIL_DOMAIN']
69
+ options[:login] = ENV['EMAIL_LOGIN']
70
+ options[:secure] = ENV['EMAIL_SECURE']
71
+ options
72
+ end
73
+
74
+ def new_with_environment(options={})
75
+ environment_options.merge(options.rekey)
76
+ new(options)
77
+ end
78
+ end
79
+
80
+ attr_accessor :server
81
+ attr_accessor :port
82
+ attr_accessor :account
83
+ attr_accessor :passwd
84
+ attr_accessor :login
85
+ attr_accessor :secure
86
+ attr_accessor :domain
87
+ attr_accessor :from
88
+ attr_accessor :mailto
89
+ attr_accessor :subject
90
+ attr_accessor :message
91
+
92
+ #
93
+
94
+ #
95
+ def initialize(options={})
96
+ require_smtp
97
+
98
+ options = options.rekey
99
+
100
+ if not options[:server]
101
+ options = self.class.environment_options.merge(options)
102
+ end
103
+
104
+ @mailto = options[:to] || options[:mailto]
105
+
106
+ @from = options[:from]
107
+ @message = options[:message]
108
+ @subject = options[:subject]
109
+ @server = options[:server]
110
+ @account = options[:account]
111
+ @passwd = options[:password]
112
+ @login = options[:login]
113
+ @secure = options[:secure] #.to_b
114
+ @domain = options[:domain]
115
+ @port = options[:port]
116
+
117
+ @port ||= secure ? 465 : 25
118
+ @port = @port.to_i
119
+
120
+ @account ||= @from
121
+
122
+ @login ||= :plain
123
+ @login = @login.to_sym
124
+
125
+ @passwd ||= self.class.password
126
+
127
+ @domain ||= @server
128
+
129
+ # save the password for later use
130
+ self.class.password = @passwd
131
+ end
132
+
133
+ #
134
+
135
+ def email(options={})
136
+ options.rekey
137
+
138
+ message = options[:message] || self.message
139
+ subject = options[:subject] || self.subject
140
+ from = options[:from] || self.from
141
+ mailto = options[:mailto] || options[:to] || self.mailto
142
+
143
+ raise ArgumentError, "missing email field -- server" unless server
144
+ raise ArgumentError, "missing email field -- account" unless account
145
+
146
+ raise ArgumentError, "missing email field -- from" unless from
147
+ raise ArgumentError, "missing email field -- mailto" unless mailto
148
+ raise ArgumentError, "missing email field -- subject" unless subject
149
+
150
+ passwd ||= password("#{account} password:")
151
+
152
+ mailto = [mailto].flatten.compact
153
+
154
+ msg = ""
155
+ msg << "From: #{from}\n"
156
+ msg << "To: #{mailto.join(';')}\n"
157
+ msg << "Subject: #{subject}\n"
158
+ msg << ""
159
+ msg << message
160
+
161
+ #p server, port, domain, account, passwd, login, secure if verbose?
162
+
163
+ begin
164
+ if Net::SMTP.respond_to?(:enable_tls) && secure
165
+ Net::SMTP.enable_tls
166
+ Net::SMTP.start(server, port, domain, account, passwd, login, secure) do |smtp|
167
+ smtp.send_message(msg, from, mailto)
168
+ end
169
+ else
170
+ Net::SMTP.start(server, port, domain, account, passwd, login) do |smtp|
171
+ smtp.send_message(msg, from, mailto)
172
+ end
173
+ end
174
+ return mailto
175
+ rescue Exception => e
176
+ return e
177
+ end
178
+ end
179
+
180
+ # Ask for a password.
181
+ #
182
+ # FIXME: Does not hide password.
183
+
184
+ def password(msg=nil)
185
+ msg ||= "Enter Password: "
186
+ inp = ''
187
+
188
+ $stdout << msg
189
+
190
+ inp = STDIN.gets.chomp
191
+
192
+ #begin
193
+ # system "stty -echo"
194
+ # inp = gets.chomp
195
+ #ensure
196
+ # system "stty echo"
197
+ #end
198
+
199
+ return inp
200
+ end
201
+
202
+ #
203
+ def require_smtp
204
+ begin
205
+ require 'facets/net/smtp_tls'
206
+ rescue LoadError
207
+ require 'net/smtp'
208
+ end
209
+ end
210
+
211
+ end
212
+
213
+ end
214
+
215
+
216
+
217
+ =begin
218
+ # Email function to easily send out an email.
219
+ #
220
+ # Settings:
221
+ #
222
+ # subject Subject of email message.
223
+ # from Message FROM address [email].
224
+ # to Email address to send announcemnt.
225
+ # server Email server to route message.
226
+ # port Email server's port.
227
+ # domain Email server's domain name.
228
+ # account Email account name if needed.
229
+ # password Password for login..
230
+ # login Login type: plain, cram_md5 or login [plain].
231
+ # secure Uses TLS security, true or false? [false]
232
+ # message Mesage to send -or-
233
+ # file File that contains message.
234
+ #
235
+ def email(message, settings)
236
+ settings ||= {}
237
+ settings.rekey!
238
+
239
+ server = settings[:server]
240
+ account = settings[:account] || ENV['EMAIL_ACCOUNT']
241
+ passwd = settings[:password] || ENV['EMAIL_PASSWORD']
242
+ login = settings[:login].to_sym
243
+ subject = settings[:subject]
244
+ mail_to = settings[:to] || settings[:mail_to]
245
+ mail_from = settings[:from] || settings[:mail_from]
246
+ secure = settings[:secure]
247
+ domain = settings[:domain] || server
248
+
249
+ port ||= (secure ? 465 : 25)
250
+ account ||= mail_from
251
+ login ||= :plain
252
+
253
+ #mail_to = nil if mail_to.empty?
254
+
255
+ raise ArgumentError, "missing email field -- server" unless server
256
+ raise ArgumentError, "missing email field -- account" unless account
257
+ raise ArgumentError, "missing email field -- subject" unless subject
258
+ raise ArgumentError, "missing email field -- to" unless mail_to
259
+ raise ArgumentError, "missing email field -- from" unless mail_from
260
+
261
+ passwd ||= password(account)
262
+
263
+ mail_to = [mail_to].flatten.compact
264
+
265
+ msg = ""
266
+ msg << "From: #{mail_from}\n"
267
+ msg << "To: #{mail_to.join(';')}\n"
268
+ msg << "Subject: #{subject}\n"
269
+ msg << ""
270
+ msg << message
271
+
272
+ begin
273
+ Net::SMTP.enable_tls if Net::SMTP.respond_to?(:enable_tls) and secure
274
+ Net::SMTP.start(server, port, domain, account, passwd, login) do |s|
275
+ s.send_message( msg, mail_from, mail_to )
276
+ end
277
+ puts "Email sent successfully to #{mail_to.join(';')}."
278
+ return true
279
+ rescue => e
280
+ if trace?
281
+ raise e
282
+ else
283
+ abort "Email delivery failed."
284
+ end
285
+ end
286
+ end
287
+ =end
288
+
@@ -0,0 +1,41 @@
1
+ module Detroit
2
+
3
+ #
4
+ require 'pom'
5
+
6
+ #
7
+ module ProjectUtils
8
+
9
+ # Common access to project.
10
+ def self.project(path=Dir.pwd)
11
+ if root = ::POM::Project.root(path)
12
+ @@projects ||= {}
13
+ @@projects[root] ||= ::POM::Project.new(root)
14
+ else
15
+ nil # ?
16
+ end
17
+ end
18
+
19
+ #
20
+ def project(path=Dir.pwd)
21
+ @project ||= ProjectUtils.project(path)
22
+ end
23
+
24
+ # Set project manutally.
25
+ def project=(proj)
26
+ @project = proj
27
+ end
28
+
29
+ #
30
+ def metadata
31
+ project.metadata
32
+ end
33
+
34
+ #
35
+ def root
36
+ project.root
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,235 @@
1
+ require 'detroit/tool/core_ext/shell_extensions'
2
+ require 'rbconfig'
3
+
4
+ module Detroit
5
+
6
+ # ShellUtils provides the whole slew of FileUtils,
7
+ # FileTest and File class methods in a single module
8
+ # and modifies methods according to noop? and verbose?
9
+ # options.
10
+ module ShellUtils
11
+
12
+ #
13
+ def initialize_extension_defaults
14
+ @quiet = false
15
+ @trial = false
16
+ @noop = false
17
+ @force = false
18
+ super() if defined?(super)
19
+ end
20
+
21
+ #
22
+ def initialize_extensions
23
+ extend(fileutils)
24
+ super() if defined?(super)
25
+ end
26
+
27
+ # A path is required for shell methods to operate.
28
+ # If no path is set than the current working path is used.
29
+ def path
30
+ @path ||= Dir.pwd
31
+ end
32
+
33
+ # Set shell path.
34
+ def path=(dir)
35
+ @path = dir
36
+ end
37
+
38
+ attr_writer :stdout
39
+ attr_writer :stdin
40
+ attr_writer :stderr
41
+
42
+ def stdout
43
+ @stdout ||= $stdout
44
+ end
45
+
46
+ def stdin
47
+ @stdin ||= $stdin
48
+ end
49
+
50
+ def stderr
51
+ @stdout ||= $stderr
52
+ end
53
+
54
+ attr_writer :force
55
+ attr_writer :quiet
56
+ attr_writer :trace
57
+ attr_writer :trial
58
+ attr_writer :debug
59
+ attr_writer :verbose
60
+
61
+ def force? ; @force ; end
62
+
63
+ def quiet? ; @quiet ; end
64
+ def trial? ; @trial ; end
65
+
66
+ def trace? ; @trace ; end
67
+ def debug? ; @debug ; end
68
+
69
+ def verbose? ; @verbose ; end
70
+ def noop? ; @trial ; end
71
+ def dryrun? ; verbose? && noop? ; end
72
+
73
+ #
74
+ def print(str=nil)
75
+ stdout.print(str.to_s) unless quiet?
76
+ end
77
+
78
+ #
79
+ def puts(str=nil)
80
+ stdout.puts(str.to_s) unless quiet?
81
+ end
82
+
83
+ # TODO: deprecate in favor of #report ?
84
+ def report(message)
85
+ stderr.puts message unless quiet?
86
+ end
87
+
88
+ alias_method :status, :report
89
+
90
+ # Internal trace report. Only output if in trace mode.
91
+ def trace(message)
92
+ stderr.puts message if trace?
93
+ end
94
+
95
+ # Convenient method to get simple console reply.
96
+ def ask(question)
97
+ stdout.print "#{question} "
98
+ stdout.flush
99
+ input = stdin.gets #until inp = stdin.gets ; sleep 1 ; end
100
+ input.strip
101
+ end
102
+
103
+ # TODO: Until we have better support for getting input across
104
+ # platforms, we are using #ask for passwords too.
105
+ def password(prompt=nil)
106
+ prompt ||= "Enter Password: "
107
+ ask(prompt)
108
+ end
109
+
110
+ # Delegate to Ratch::Shell instance.
111
+ #def shell(path=Dir.pwd)
112
+ # @shell ||= {}
113
+ # @shell[path] ||= (
114
+ # mode = {
115
+ # :noop => trial?,
116
+ # :verbose => trace? || (trial? && !quiet?),
117
+ # :quiet => quiet?
118
+ # }
119
+ # Ratch::Shell.new(path, mode)
120
+ # )
121
+ #end
122
+
123
+ # Shell runner.
124
+ def sh(cmd)
125
+ trace cmd
126
+ return true if noop?
127
+
128
+ if quiet?
129
+ silently{ system(cmd) }
130
+ else
131
+ system(cmd)
132
+ end
133
+ end
134
+
135
+ # Current ruby binary.
136
+ RUBY = File.join(::Config::CONFIG['bindir'], ::Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
137
+
138
+ # Shell-out to ruby.
139
+ def ruby(cmd)
140
+ sh RUBY + " " + cmd
141
+ end
142
+
143
+
144
+ # TODO: Ultimately merge #glob and #multiglob.
145
+ def multiglob(*args, &blk)
146
+ Dir.multiglob(*args, &blk)
147
+ end
148
+
149
+ #
150
+ def multiglob_r(*args, &blk)
151
+ Dir.multiglob_r(*args, &blk)
152
+ end
153
+
154
+ # -- File IO Shortcuts ----------------------------------------------------
155
+
156
+ # Read file.
157
+ def read(path)
158
+ File.read(path)
159
+ end
160
+
161
+ # Write file.
162
+ def write(path, text)
163
+ $stderr.puts "write #{path}" if trace?
164
+ File.open(path, 'w'){ |f| f << text } unless noop?
165
+ end
166
+
167
+ # Append to file.
168
+ def append(path, text)
169
+ $stderr.puts "append #{path}" if trace?
170
+ File.open(path, 'a'){ |f| f << text } unless noop?
171
+ end
172
+
173
+ # -- File Testing ---------------------------------------------------------
174
+
175
+ def size(path) ; FileTest.size(path) ; end
176
+ def size?(path) ; FileTest.size?(path) ; end
177
+ def directory?(path) ; FileTest.directory?(path) ; end
178
+ def symlink?(path) ; FileTest.symlink?(path) ; end
179
+ def readable?(path) ; FileTest.readable?(path) ; end
180
+ def chardev?(path) ; FileTest.chardev?(path) ; end
181
+ def exist?(path) ; FileTest.exist?(path) ; end
182
+ def exists?(path) ; FileTest.exists?(path) ; end
183
+ def zero?(path) ; FileTest.zero?(path) ; end
184
+ def pipe?(path) ; FileTest.pipe?(path) ; end
185
+ def file?(path) ; FileTest.file?(path) ; end
186
+ def sticky?(path) ; FileTest.sticky?(path) ; end
187
+ def blockdev?(path) ; FileTest.blockdev?(path) ; end
188
+ def grpowned?(path) ; FileTest.grpowned?(path) ; end
189
+ def setgid?(path) ; FileTest.setgid?(path) ; end
190
+ def setuid?(path) ; FileTest.setuid?(path) ; end
191
+ def socket?(path) ; FileTest.socket?(path) ; end
192
+ def owned?(path) ; FileTest.owned?(path) ; end
193
+ def writable?(path) ; FileTest.writable?(path) ; end
194
+ def executable?(path) ; FileTest.executable?(path) ; end
195
+
196
+ def safe?(path) ; FileTest.safe?(path) ; end
197
+
198
+ def relative?(path) ; FileTest.relative?(path) ; end
199
+ def absolute?(path) ; FileTest.absolute?(path) ; end
200
+
201
+ def writable_real?(path) ; FileTest.writable_real?(path) ; end
202
+ def executable_real?(path) ; FileTest.executable_real?(path) ; end
203
+ def readable_real?(path) ; FileTest.readable_real?(path) ; end
204
+
205
+ def identical?(path, other)
206
+ FileTest.identical?(path, other)
207
+ end
208
+ alias_method :compare_file, :identical?
209
+
210
+ # -- File Methods ---------------------------------------------------------
211
+
212
+ def atime(*args) ; File.ctime(*args) ; end
213
+ def ctime(*args) ; File.ctime(*args) ; end
214
+ def mtime(*args) ; File.mtime(*args) ; end
215
+
216
+ def utime(*args) ; File.utime(*args) unless noop? ; end
217
+
218
+ private # -----------------------------------------------------------------
219
+
220
+ # Returns FileUtils module based on mode.
221
+ def fileutils
222
+ if dryrun?
223
+ ::FileUtils::DryRun
224
+ elsif noop? or trial?
225
+ ::FileUtils::Noop
226
+ elsif trace?
227
+ ::FileUtils::Verbose
228
+ else
229
+ ::FileUtils
230
+ end
231
+ end
232
+
233
+ end
234
+
235
+ end