ratch 0.4.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +17 -669
- data/HISTORY +6 -0
- data/MANIFEST +36 -0
- data/METADATA +14 -0
- data/NEWS +7 -0
- data/README +67 -17
- data/bin/ratch +5 -78
- data/demo/tryme-task.ratch +12 -0
- data/demo/tryme1.ratch +6 -0
- data/lib/ratch/core_ext.rb +6 -0
- data/lib/ratch/core_ext/facets.rb +1 -0
- data/lib/ratch/core_ext/filetest.rb +52 -0
- data/lib/ratch/core_ext/object.rb +8 -0
- data/lib/ratch/core_ext/pathname.rb +38 -0
- data/lib/ratch/core_ext/string.rb +44 -0
- data/lib/ratch/{dsl/console.rb → core_ext/to_console.rb} +2 -76
- data/lib/ratch/core_ext/to_list.rb +29 -0
- data/lib/ratch/dsl.rb +494 -49
- data/lib/ratch/index.rb +4 -0
- data/lib/ratch/io.rb +116 -0
- data/lib/ratch/pathglob.rb +73 -0
- data/lib/ratch/plugin.rb +55 -0
- data/lib/ratch/runmode.rb +69 -0
- data/lib/ratch/script.rb +52 -0
- data/lib/ratch/service.rb +33 -0
- data/lib/ratch/task.rb +249 -0
- data/lib/ratch/task2.rb +298 -0
- data/test/README +1 -0
- data/test/test_helper.rb +4 -0
- data/test/test_task.rb +46 -0
- metadata +90 -150
- data/CHANGES +0 -22
- data/TODO +0 -2
- data/bin/lt +0 -56
- data/bin/ludo +0 -14
- data/bin/manifest +0 -451
- data/bin/ratch-find +0 -21
- data/demo/WILMA +0 -1
- data/demo/XR +0 -9
- data/demo/lib/foo/foo.rb +0 -7
- data/demo/p.rb +0 -9
- data/demo/r.rb +0 -6
- data/demo/t.rb +0 -3
- data/demo/task/config.yaml +0 -4
- data/demo/task/one +0 -6
- data/demo/task/simplebuild +0 -15
- data/demo/task/stats +0 -4
- data/demo/task/task +0 -6
- data/demo/task/tryme +0 -10
- data/lib/ratch/dsl/argv.rb +0 -112
- data/lib/ratch/dsl/batch.rb +0 -232
- data/lib/ratch/dsl/build.rb +0 -174
- data/lib/ratch/dsl/email.rb +0 -108
- data/lib/ratch/dsl/file.rb +0 -205
- data/lib/ratch/dsl/meta.rb +0 -125
- data/lib/ratch/dsl/options.rb +0 -98
- data/lib/ratch/dsl/setup.rb +0 -124
- data/lib/ratch/dsl/sign.rb +0 -243
- data/lib/ratch/dsl/stage.rb +0 -147
- data/lib/ratch/dsl/task.rb +0 -139
- data/lib/ratch/dsl/upload.rb +0 -436
- data/lib/ratch/dsl/zip.rb +0 -59
- data/lib/ratch/extra/email.rb +0 -5
- data/lib/ratch/extra/stage.rb +0 -5
- data/lib/ratch/extra/zip.rb +0 -5
- data/lib/ratch/manager.rb +0 -53
- data/lib/ratch/manifest.rb +0 -540
- data/lib/ratch/metadata/information.rb +0 -258
- data/lib/ratch/metadata/package.rb +0 -108
- data/lib/ratch/metadata/project.rb +0 -523
- data/lib/ratch/metadata/release.rb +0 -108
- data/lib/ratch/support/errors.rb +0 -4
- data/lib/ratch/support/filename.rb +0 -18
- data/lib/ratch/support/filetest.rb +0 -29
- data/lib/ratch/toolset/ruby/announce +0 -224
- data/lib/ratch/toolset/ruby/compile +0 -49
- data/lib/ratch/toolset/ruby/install +0 -77
- data/lib/ratch/toolset/ruby/notes +0 -185
- data/lib/ratch/toolset/ruby/pack/gem +0 -93
- data/lib/ratch/toolset/ruby/pack/tgz +0 -46
- data/lib/ratch/toolset/ruby/pack/zip +0 -46
- data/lib/ratch/toolset/ruby/publish +0 -57
- data/lib/ratch/toolset/ruby/release +0 -8
- data/lib/ratch/toolset/ruby/setup +0 -1616
- data/lib/ratch/toolset/ruby/stamp +0 -33
- data/lib/ratch/toolset/ruby/stats +0 -138
- data/lib/ratch/toolset/ruby/test/crosstest +0 -305
- data/lib/ratch/toolset/ruby/test/extest +0 -129
- data/lib/ratch/toolset/ruby/test/isotest +0 -293
- data/lib/ratch/toolset/ruby/test/load +0 -39
- data/lib/ratch/toolset/ruby/test/loadtest +0 -28
- data/lib/ratch/toolset/ruby/test/syntax +0 -29
- data/lib/ratch/toolset/ruby/test/test +0 -26
- data/lib/ratch/toolset/sandbox/query +0 -11
- data/man/ratch.man +0 -73
- data/meta/MANIFEST +0 -130
- data/meta/config.yaml +0 -9
- data/meta/icli.yaml +0 -16
- data/meta/project.yaml +0 -20
- data/meta/ratch.roll +0 -2
- data/meta/xProjectInfo +0 -41
- data/task/clobber/package +0 -10
- data/task/man +0 -14
- data/task/publish +0 -57
- data/task/release +0 -9
- data/task/setup +0 -1616
- data/task/stats +0 -138
@@ -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
|
+
|
data/lib/ratch/dsl.rb
CHANGED
@@ -1,52 +1,497 @@
|
|
1
|
-
|
2
|
-
#
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
1
|
+
require 'yaml'
|
2
|
+
require 'rbconfig' # replace with facets/rbsystem?
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
require 'ratch/core_ext'
|
6
|
+
require 'ratch/index'
|
7
|
+
require 'ratch/io'
|
8
|
+
require 'ratch/runmode'
|
9
|
+
|
10
|
+
require 'ratch/task'
|
11
|
+
|
12
|
+
require 'facets/platform'
|
13
|
+
require 'facets/arguments'
|
14
|
+
require 'facets/ziputils'
|
15
|
+
|
16
|
+
#require 'annotatable'
|
17
|
+
#require 'facets/openhash'
|
18
|
+
#require 'facets/argvector'
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'facets/net/smtp_tls'
|
22
|
+
rescue LoadError
|
23
|
+
require 'net/smtp'
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
module Ratch
|
28
|
+
|
29
|
+
# = Ratch DSL
|
30
|
+
#
|
31
|
+
# The DSL class is the heart of Ratch, it provides all the convenece methods
|
32
|
+
# that make Ratch so convenient for writing Ruby-based batch script.
|
33
|
+
#
|
34
|
+
class DSL < Module
|
35
|
+
|
36
|
+
#
|
37
|
+
def initialize(ioc={})
|
38
|
+
include Taskable
|
39
|
+
include Taskable::Dsl
|
40
|
+
|
41
|
+
extend self
|
42
|
+
|
43
|
+
@runmode = ioc[:mode] || Runmode.load_argv!
|
44
|
+
@io = ioc[:io] || IO.new(@runmode)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Delgate run mode settings to Ratch::RunMode object.
|
48
|
+
def runmode
|
49
|
+
@runmode
|
50
|
+
end
|
51
|
+
|
52
|
+
# Delgate input/output routines to Ratch::IO object.
|
53
|
+
def io
|
54
|
+
@io
|
55
|
+
end
|
56
|
+
|
57
|
+
# Delegate file system routines to FileUtils or FileUtils::DryRun,
|
58
|
+
# depending on dryrun mode.
|
59
|
+
def fileutils
|
60
|
+
dryrun? ? ::FileUtils::DryRun : ::FileUtils
|
61
|
+
end
|
62
|
+
|
63
|
+
# Add FileUtils Features
|
64
|
+
::FileUtils.private_instance_methods(false).each do |meth|
|
65
|
+
next if meth =~ /^fu_/
|
66
|
+
module_eval %{
|
67
|
+
def #{meth}(*a,&b)
|
68
|
+
fileutils.#{meth}(*a,&b)
|
69
|
+
end
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
# Add FileTest Features
|
74
|
+
::FileTest.private_instance_methods(false).each do |meth|
|
75
|
+
next if meth =~ /^fu_/
|
76
|
+
module_eval %{
|
77
|
+
def #{meth}(*a,&b)
|
78
|
+
FileTest.#{meth}(*a,&b)
|
79
|
+
end
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
#attr_writer :noharm
|
84
|
+
#attr_writer :force
|
85
|
+
#attr_writer :trace
|
86
|
+
#attr_writer :debug
|
87
|
+
#attr_writer :quiet
|
88
|
+
#alias_method :dryrun=, :noharm=
|
89
|
+
|
90
|
+
def force? ; runmode.force? ; end
|
91
|
+
def trace? ; runmode.trace? ; end
|
92
|
+
def debug? ; runmode.debug? ; end
|
93
|
+
def noharm? ; runmode.noharm? ; end
|
94
|
+
def dryrun? ; runmode.dryrun? ; end
|
95
|
+
def quiet? ; runmode.quiet? ; end
|
96
|
+
def verbose? ; runmode.verbose? ; end
|
97
|
+
|
98
|
+
# Current platform.
|
99
|
+
def current_platform
|
100
|
+
Platform.local.to_s
|
101
|
+
end
|
102
|
+
|
103
|
+
# Load configuration data from a file.
|
104
|
+
# Reesults are cached and and empty Hash is
|
105
|
+
# returned if the file is not found.
|
106
|
+
#
|
107
|
+
# Since they are YAML files, they can optionally
|
108
|
+
# end with '.yaml' or '.yml'.
|
109
|
+
def configuration(file)
|
110
|
+
@configuration ||= {}
|
111
|
+
@configuration[file] ||= (
|
112
|
+
begin
|
113
|
+
configuration!(file)
|
114
|
+
rescue LoadError
|
115
|
+
Hash.new{ |h,k| h[k] = {} }
|
116
|
+
end
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Load configuration data from a file.
|
121
|
+
# The "bang" version will raise an error
|
122
|
+
# if file is not found. It also does not
|
123
|
+
# cache the results.
|
124
|
+
#
|
125
|
+
# Since they are YAML files, they can optionally
|
126
|
+
# end with '.yaml' or '.yml'.
|
127
|
+
def configuration!(file)
|
128
|
+
@configuration ||= {}
|
129
|
+
patt = file + "{.yml,.yaml,}"
|
130
|
+
path = Dir.glob(patt, File::FNM_CASEFOLD).find{ |f| File.file?(f) }
|
131
|
+
if path
|
132
|
+
# The || {} is in case the file is empty.
|
133
|
+
data = YAML::load(File.open(path)) || {}
|
134
|
+
@configuration[file] = data
|
135
|
+
else
|
136
|
+
raise LoadError, "Missing file -- #{path}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Shell runner.
|
141
|
+
def shell(cmd)
|
142
|
+
if dryrun?
|
143
|
+
puts cmd
|
144
|
+
true
|
145
|
+
else
|
146
|
+
puts "--> system call: #{cmd}" if trace?
|
147
|
+
if quiet?
|
148
|
+
silently{ system(cmd) }
|
149
|
+
else
|
150
|
+
system(cmd)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# TODO: DEPRECATE #sh in favor of #shell.
|
156
|
+
alias_method :sh, :shell
|
157
|
+
|
158
|
+
#
|
159
|
+
def commandline
|
160
|
+
#@commandline ||= ArgVector.new(ARGV)
|
161
|
+
@commandline ||= CLI::Arguments.new #(ARGV)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Duplicate of ARGV.
|
165
|
+
#def argv
|
166
|
+
# @argv ||= ARGV.dup
|
167
|
+
#end
|
168
|
+
|
169
|
+
|
170
|
+
# Convert command line argv to args.
|
171
|
+
#
|
172
|
+
# TODO Is this implmented as expected?
|
173
|
+
#def command_parameters
|
174
|
+
# ARGV.to_params
|
175
|
+
#end
|
176
|
+
|
177
|
+
# Internal status report.
|
178
|
+
# Only output if dryrun or trace mode.
|
179
|
+
def status(message)
|
180
|
+
io.status(message)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Convenient method to get simple console reply.
|
184
|
+
def ask(question, answers=nil)
|
185
|
+
io.ask(question, answers)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Ask for a password. (FIXME: only for unix so far)
|
189
|
+
def password(prompt=nil)
|
190
|
+
io.password(prompt)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Provides convenient starting points in the file system.
|
194
|
+
#
|
195
|
+
# root #=> #<Pathname:/>
|
196
|
+
# home #=> #<Pathname:/home/jimmy>
|
197
|
+
# work #=> #<Pathname:/home/jimmy/Documents>
|
198
|
+
#
|
199
|
+
|
200
|
+
# Current root path.
|
201
|
+
def root(*args)
|
202
|
+
Pathname['/', *args]
|
203
|
+
end
|
204
|
+
|
205
|
+
# Current home path.
|
206
|
+
def home(*args)
|
207
|
+
Pathname['~', *args].expand_path
|
208
|
+
end
|
209
|
+
|
210
|
+
# Current working path.
|
211
|
+
def work(*args)
|
212
|
+
Pathname['.', *args]
|
213
|
+
end
|
214
|
+
|
215
|
+
alias_method :pwd, :work
|
216
|
+
|
217
|
+
# Bonus FileUtils features.
|
218
|
+
def cd(*a,&b)
|
219
|
+
puts "cd #{a}" if dryrun? or trace?
|
220
|
+
fileutils.chdir(*a,&b)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Read file.
|
224
|
+
def file_read(path)
|
225
|
+
File.read(path)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Write file.
|
229
|
+
def file_write(path, text)
|
230
|
+
if dryrun?
|
231
|
+
puts "write #{path}"
|
232
|
+
else
|
233
|
+
File.open(path, 'w'){ |f| f << text }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
# Assert that a path exists.
|
238
|
+
def exists?(path)
|
239
|
+
paths = Dir.glob(path)
|
240
|
+
paths.not_empty?
|
241
|
+
end
|
242
|
+
alias_method :exist?, :exists? #; module_function :exist?
|
243
|
+
alias_method :path?, :exists? #; module_function :path?
|
244
|
+
|
245
|
+
# Assert that a path exists.
|
246
|
+
def exists!(*paths)
|
247
|
+
abort "path not found #{path}" unless paths.any?{|path| exists?(path)}
|
248
|
+
end
|
249
|
+
alias_method :exist!, :exists! #; module_function :exist!
|
250
|
+
alias_method :path!, :exists! #; module_function :path!
|
251
|
+
|
252
|
+
# Is a given path a regular file? If +path+ is a glob
|
253
|
+
# then checks to see if all matches are refular files.
|
254
|
+
def file?(path)
|
255
|
+
paths = Dir.glob(path)
|
256
|
+
paths.not_empty? && paths.all?{ |f| FileTest.file?(f) }
|
257
|
+
end
|
258
|
+
|
259
|
+
# Assert that a given path is a file.
|
260
|
+
def file!(*paths)
|
261
|
+
abort "file not found #{path}" unless paths.any?{|path| file?(path)}
|
262
|
+
end
|
263
|
+
|
264
|
+
# Is a given path a directory? If +path+ is a glob
|
265
|
+
# checks to see if all matches are directories.
|
266
|
+
def dir?(path)
|
267
|
+
paths = Dir.glob(path)
|
268
|
+
paths.not_empty? && paths.all?{ |f| FileTest.directory?(f) }
|
269
|
+
end
|
270
|
+
alias_method :directory?, :dir? #; module_function :directory?
|
271
|
+
|
272
|
+
# Assert that a given path is a directory.
|
273
|
+
def dir!(*paths)
|
274
|
+
paths.each do |path|
|
275
|
+
abort "Directory not found: '#{path}'." unless dir?(path)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
alias_method :directory!, :dir! #; module_function :directory!
|
279
|
+
|
280
|
+
# # Is a file a task?
|
20
281
|
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
282
|
+
# def task?(path)
|
283
|
+
# task = File.dirname($0) + "/#{path}"
|
284
|
+
# task.chomp!('!')
|
285
|
+
# task if FileTest.file?(task) && FileTest.executable?(task)
|
286
|
+
# end
|
287
|
+
|
288
|
+
=begin
|
289
|
+
# Does a path need updating, based on given +sources+?
|
290
|
+
# This compares mtimes of give paths. Returns false
|
291
|
+
# if the path needs to be updated.
|
292
|
+
#
|
293
|
+
# TODO: Put this in FileTest instead?
|
294
|
+
|
295
|
+
def out_of_date?(path, *sources)
|
296
|
+
return true unless File.exist?(path)
|
297
|
+
|
298
|
+
sources = sources.collect{ |source| Dir.glob(source) }.flatten
|
299
|
+
mtimes = sources.collect{ |file| File.mtime(file) }
|
300
|
+
|
301
|
+
return true if mtimes.empty? # TODO: This the way to go here?
|
302
|
+
|
303
|
+
File.mtime(path) < mtimes.max
|
304
|
+
end
|
305
|
+
=end
|
306
|
+
|
307
|
+
# Glob files.
|
308
|
+
def glob(*args, &blk)
|
309
|
+
Dir.glob(*args, &blk)
|
310
|
+
end
|
311
|
+
|
312
|
+
# Multiglob files.
|
313
|
+
def multiglob(*args, &blk)
|
314
|
+
Dir.multiglob(*args, &blk)
|
315
|
+
end
|
316
|
+
|
317
|
+
# Multiglob recursive.
|
318
|
+
def multiglob_r(*args, &blk)
|
319
|
+
Dir.multiglob_r(*args, &blk)
|
320
|
+
end
|
321
|
+
|
322
|
+
# Stage by hard linking included files to a stage directory.
|
323
|
+
#
|
324
|
+
# stage_directory Stage directory.
|
325
|
+
# files Files to link to stage.
|
326
|
+
#
|
327
|
+
# TODO: Rename to linkstage or something less likely to name clash?
|
328
|
+
|
329
|
+
def stage(stage_directory, files)
|
330
|
+
return stage_directory if dryrun? # Don't link to stage if dryrun.
|
331
|
+
|
332
|
+
if File.directory?(stage_directory) # Ensure existance of staging area
|
333
|
+
#raise(OverwriteError, stage_directory) unless force?
|
334
|
+
rm_r(stage_directory)
|
335
|
+
end
|
336
|
+
|
337
|
+
mkdir_p(stage_directory) #dir = File.expand_path(stage)
|
338
|
+
|
339
|
+
#files = package.filelist #+ [package.manifest_file]
|
340
|
+
|
341
|
+
# TODO Dryrun test here or before folder creation?
|
342
|
+
files.each do |f| # Link files into staging area.
|
343
|
+
file = File.join(stage_directory, f)
|
344
|
+
if File.directory?(f)
|
345
|
+
mkdir_p(file)
|
346
|
+
else
|
347
|
+
unless File.exist?(file) and File.mtime(file) >= File.mtime(f)
|
348
|
+
ln(f, file) #safe_ln ?
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
return stage_directory
|
354
|
+
end
|
355
|
+
|
356
|
+
# Delegate access to ZipUtils.
|
357
|
+
#
|
358
|
+
def ziputils
|
359
|
+
dryrun? ? ::ZipUtils::DryRun : ::ZipUtils
|
360
|
+
end
|
361
|
+
|
362
|
+
# Compress directory.
|
363
|
+
|
364
|
+
def compress(format, folder, file=nil, options={})
|
365
|
+
case format.to_s.downcase
|
366
|
+
when 'zip'
|
367
|
+
ziputils.zip(folder, file, options)
|
368
|
+
when 'tgz'
|
369
|
+
ziputils.tgz(folder, file, options)
|
370
|
+
when 'tbz', 'bzip'
|
371
|
+
ziputils.tar_bzip(folder, file, options)
|
372
|
+
else
|
373
|
+
raise ArguementError, "unsupported compression format -- #{format}"
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Create a zip file of a directory.
|
378
|
+
#
|
379
|
+
def zip(folder, file=nil, options={})
|
380
|
+
ziputils.zip(folder, file, options)
|
381
|
+
end
|
382
|
+
|
383
|
+
# Create a tar.bz2 file of a directory.
|
384
|
+
#
|
385
|
+
def tar_bzip(folder, file=nil, options={})
|
386
|
+
ziputils.tar_bzip(folder, file, options)
|
387
|
+
end
|
388
|
+
|
389
|
+
# Create a tgz file of a directory.
|
390
|
+
#
|
391
|
+
def tar_gzip(folder, file=nil, options={})
|
392
|
+
ziputils.tar_gzip(folder, file, options)
|
393
|
+
end
|
394
|
+
alias_method :tgz, :tar_gzip
|
395
|
+
|
396
|
+
#
|
397
|
+
#
|
398
|
+
def naming_policy(*policies)
|
399
|
+
if policies.empty?
|
400
|
+
@naming_policy ||= ['down', 'ext']
|
401
|
+
else
|
402
|
+
@naming_policy = policies
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
#
|
407
|
+
#
|
408
|
+
def apply_naming_policy(name, ext)
|
409
|
+
naming_policy.each do |policy|
|
410
|
+
case policy
|
411
|
+
when /^low/, /^down/
|
412
|
+
name = name.downcase
|
413
|
+
when /^up/
|
414
|
+
name = name.upcase
|
415
|
+
when /^cap/
|
416
|
+
name = name.capitalize
|
417
|
+
when /^ext/
|
418
|
+
name = name + ".#{ext}"
|
419
|
+
end
|
420
|
+
end
|
421
|
+
name
|
422
|
+
end
|
423
|
+
|
424
|
+
# Email function to easily send out an email.
|
425
|
+
#
|
426
|
+
# Settings:
|
427
|
+
#
|
428
|
+
# subject Subject of email message.
|
429
|
+
# from Message FROM address [email].
|
430
|
+
# to Email address to send announcemnt.
|
431
|
+
# server Email server to route message.
|
432
|
+
# port Email server's port.
|
433
|
+
# domain Email server's domain name.
|
434
|
+
# account Email account name if needed.
|
435
|
+
# password Password for login..
|
436
|
+
# login Login type: plain, cram_md5 or login [plain].
|
437
|
+
# secure Uses TLS security, true or false? [false]
|
438
|
+
# message Mesage to send -or-
|
439
|
+
# file File that contains message.
|
440
|
+
#
|
441
|
+
def email(message, settings)
|
442
|
+
settings ||= {}
|
443
|
+
settings.rekey
|
444
|
+
|
445
|
+
server = settings[:server]
|
446
|
+
account = settings[:account] || ENV['EMAIL_ACCOUNT']
|
447
|
+
passwd = settings[:password] || ENV['EMAIL_PASSWORD']
|
448
|
+
login = settings[:login].to_sym
|
449
|
+
subject = settings[:subject]
|
450
|
+
mail_to = settings[:to] || settings[:mail_to]
|
451
|
+
mail_from = settings[:from] || settings[:mail_from]
|
452
|
+
secure = settings[:secure]
|
453
|
+
domain = settings[:domain] || server
|
454
|
+
|
455
|
+
port ||= (secure ? 465 : 25)
|
456
|
+
account ||= mail_from
|
457
|
+
login ||= :plain
|
458
|
+
|
459
|
+
#mail_to = nil if mail_to.empty?
|
460
|
+
|
461
|
+
raise ArgumentError, "missing email field -- server" unless server
|
462
|
+
raise ArgumentError, "missing email field -- account" unless account
|
463
|
+
raise ArgumentError, "missing email field -- subject" unless subject
|
464
|
+
raise ArgumentError, "missing email field -- to" unless mail_to
|
465
|
+
raise ArgumentError, "missing email field -- from" unless mail_from
|
466
|
+
|
467
|
+
passwd ||= password(account)
|
468
|
+
|
469
|
+
mail_to = [mail_to].flatten.compact
|
470
|
+
|
471
|
+
msg = ""
|
472
|
+
msg << "From: #{mail_from}\n"
|
473
|
+
msg << "To: #{mail_to.join(';')}\n"
|
474
|
+
msg << "Subject: #{subject}\n"
|
475
|
+
msg << ""
|
476
|
+
msg << message
|
477
|
+
|
478
|
+
begin
|
479
|
+
Net::SMTP.enable_tls if Net::SMTP.respond_to?(:enable_tls) and secure
|
480
|
+
Net::SMTP.start(server, port, domain, account, passwd, login) do |s|
|
481
|
+
s.send_message( msg, mail_from, mail_to )
|
482
|
+
end
|
483
|
+
puts "Email sent successfully to #{mail_to.join(';')}."
|
484
|
+
return true
|
485
|
+
rescue => e
|
486
|
+
if trace?
|
487
|
+
raise e
|
488
|
+
else
|
489
|
+
abort "Email delivery failed."
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
end
|
495
|
+
|
49
496
|
end
|
50
497
|
|
51
|
-
# run main task
|
52
|
-
END { run_main }
|