ratch 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/MANIFEST CHANGED
@@ -1,23 +1,37 @@
1
1
  doc
2
+ doc/log
3
+ doc/log/basic_stats
4
+ doc/log/basic_stats/index.html
5
+ doc/log/stats.log
6
+ doc/log/notes.xml
7
+ doc/log/syntax.log
8
+ doc/log/testunit.log
9
+ MANIFEST
2
10
  test
3
11
  test/README
4
12
  test/test_helper.rb
5
13
  test/test_task.rb
6
14
  README
7
15
  HISTORY
8
- METADATA
16
+ meta
17
+ meta/homepage
18
+ meta/summary
19
+ meta/abstract
20
+ meta/name
21
+ meta/requires
22
+ meta/author
23
+ meta/contact
9
24
  demo
10
25
  demo/tryme1.ratch
11
26
  demo/tryme-task.ratch
12
27
  lib
13
28
  lib/ratch
14
- lib/ratch/runmode.rb
15
- lib/ratch/pathglob.rb
29
+ lib/ratch/commandline.rb
30
+ lib/ratch/emailer.rb
16
31
  lib/ratch/core_ext
17
32
  lib/ratch/core_ext/pathname.rb
18
33
  lib/ratch/core_ext/object.rb
19
34
  lib/ratch/core_ext/facets.rb
20
- lib/ratch/core_ext/filetest.rb
21
35
  lib/ratch/core_ext/to_list.rb
22
36
  lib/ratch/core_ext/to_console.rb
23
37
  lib/ratch/core_ext/string.rb
@@ -30,7 +44,10 @@ lib/ratch/plugin.rb
30
44
  lib/ratch/task.rb
31
45
  lib/ratch/task2.rb
32
46
  lib/ratch/script.rb
47
+ VERSION
33
48
  NEWS
34
49
  bin
35
50
  bin/ratch
51
+ man
52
+ man/ratch.1
36
53
  COPYING
data/NEWS CHANGED
@@ -1,7 +1,12 @@
1
- = Release Notices
1
+ This is the second public release of Ratch.
2
2
 
3
- == 1.0.0 // 2008.08.16
3
+ Folio is now used a Ratch's backend. Folio handles
4
+ a great deal of what Ratch requires, so much of Ratch
5
+ is now just a thin wrapper around Folio.
4
6
 
5
- This is the initial public release of Ratch.
7
+ ### 1.1.0 / 2008-11-21
6
8
 
9
+ * 1 Major Change
10
+
11
+ * Overhauled system to use Folio on the backend.
7
12
 
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ ratch 1.1.0 stable (2008-11-22)
@@ -0,0 +1,39 @@
1
+
2
+ <html>
3
+ <head>
4
+ <title>Ratch Code Statistics</title>
5
+ <style>
6
+ h2{margin: 5px 0;}
7
+ table{width: 95%;}
8
+ th{background: #dcc;}
9
+ td{padding: 5px;}
10
+ .basic_stats{margin: 0 auto; width: 800px;}
11
+ </style>
12
+ <link rel="stylesheet" type="text/css" href="stats.css"/>
13
+ </head>
14
+ <body>
15
+ <div class="basic_stats">
16
+ <h1>Ratch -- Basic Code Statistics</h1>
17
+ <table class="counts" border="1">
18
+ <tr><th colspan="9"><h2>Counts</h2></th></tr>
19
+ <tr><th>TYPE</th><th>Total</th><th>Code</th><th>-%-</th><th>Docs</th><th>-%-</th><th>Blank</th><th>-%-</th><th>Files</th></tr>
20
+ <tr><th>Source</th><td>1669</td><td>731</td><td>43%</td><td>635</td><td>38%</td><td>303</td><td>18%</td><td>17</td></tr>
21
+ <tr><th>Test</th><td>50</td><td>30</td><td>1%</td><td>3</td><td>0%</td><td>17</td><td>1%</td><td>2</td></tr>
22
+ <tr><th>Total</th><td>1719</td><td>761</td><td>44%</td><td>638</td><td>37%</td><td>320</td><td>18%</td><td>19</td></tr>
23
+ </table>
24
+ <br/>
25
+ <table class="ratios" border="1">
26
+ <tr><th colspan="6"><h2>Ratios</h2></th></tr>
27
+ <tr><th>x:1</th><th>Code</th><th>Docs</th><th>Blank</th><th>Test</th><th>Total</th></tr>
28
+ <tr><th>Code</th><td> 1.0</td><td> 1.2</td><td> 2.4</td><td> 14.6</td><td> 0.4</td></tr>
29
+ <tr><th>Docs</th><td> 0.9</td><td> 1.0</td><td> 2.1</td><td> 12.7</td><td> 0.4</td></tr>
30
+ <tr><th>Blank</th><td> 0.4</td><td> 0.5</td><td> 1.0</td><td> 6.1</td><td> 0.2</td></tr>
31
+ <tr><th>Test</th><td> 0.1</td><td> 0.1</td><td> 0.2</td><td> 1.0</td><td> 0.0</td></tr>
32
+ <tr><th>Total</th><td> 2.3</td><td> 2.6</td><td> 5.5</td><td> 33.4</td><td> 1.0</td></tr>
33
+ </table>
34
+ <br/>
35
+ <div class="date">Sun Nov 23 14:09:41 -0500 2008</div>
36
+ </div>
37
+ </body>
38
+ </html>
39
+
@@ -0,0 +1,18 @@
1
+ <notes>
2
+ <set label="FIXME">
3
+ <file src="lib/ratch/emailer.rb">
4
+ <note line="154" type="FIXME">FIXME: Does not hide password.</note>
5
+ </file>
6
+ </set>
7
+ <set label="TODO">
8
+ <file src="lib/ratch/dsl.rb">
9
+ <note line="97" type="TODO">TODO: DEPRECATE #sh in favor of #shell (?)</note>
10
+ <note line="115" type="TODO">TODO: Replace these with Folio when Folio&apos;s is as capable.</note>
11
+ <note line="178" type="TODO">TODO: Deprecate these?</note>
12
+ <note line="406" type="TODO">TODO: Put this in FileTest instead?</note>
13
+ </file>
14
+ <file src="lib/ratch/plugin.rb">
15
+ <note line="57" type="TODO">TODO: Allow this to be optional? How?</note>
16
+ </file>
17
+ </set>
18
+ </notes>
@@ -0,0 +1,14 @@
1
+ Ratch Statistics
2
+ Mon Aug 18 15:10:07 -0400 2008
3
+
4
+ TYPE Total Code -%- Docs -%- Blank -%- Files
5
+ Source 1703 820 48% 572 33% 311 18% 18
6
+ Test 50 30 1% 3 0% 17 0% 2
7
+ Total 1753 850 48% 575 32% 328 18% 20
8
+
9
+ RATIO Code Docs Blank Test Total
10
+ Code 1.0 1.4 2.6 16.4 -
11
+ Docs - 1.0 1.8 11.4 -
12
+ Blank - - 1.0 6.2 -
13
+ Test - - - 1.0 -
14
+ Total 2.1 3.0 5.5 34.1 1.0
File without changes
@@ -0,0 +1,156 @@
1
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
2
+ Started
3
+ ..
4
+ Finished in 0.001091 seconds.
5
+
6
+ 2 tests, 2 assertions, 0 failures, 0 errors
7
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
8
+ Started
9
+ ..
10
+ Finished in 0.000625 seconds.
11
+
12
+ 2 tests, 2 assertions, 0 failures, 0 errors
13
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
14
+ Started
15
+ ..
16
+ Finished in 0.001007 seconds.
17
+
18
+ 2 tests, 2 assertions, 0 failures, 0 errors
19
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
20
+ Started
21
+ ..
22
+ Finished in 0.000613 seconds.
23
+
24
+ 2 tests, 2 assertions, 0 failures, 0 errors
25
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
26
+ Started
27
+ ..
28
+ Finished in 0.000791 seconds.
29
+
30
+ 2 tests, 2 assertions, 0 failures, 0 errors
31
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
32
+ Started
33
+ ..
34
+ Finished in 0.000624 seconds.
35
+
36
+ 2 tests, 2 assertions, 0 failures, 0 errors
37
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
38
+ Started
39
+ ..
40
+ Finished in 0.000694 seconds.
41
+
42
+ 2 tests, 2 assertions, 0 failures, 0 errors
43
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
44
+ Started
45
+ ..
46
+ Finished in 0.00107 seconds.
47
+
48
+ 2 tests, 2 assertions, 0 failures, 0 errors
49
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
50
+ Started
51
+ ..
52
+ Finished in 0.00084 seconds.
53
+
54
+ 2 tests, 2 assertions, 0 failures, 0 errors
55
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
56
+ Started
57
+ ..
58
+ Finished in 0.000842 seconds.
59
+
60
+ 2 tests, 2 assertions, 0 failures, 0 errors
61
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
62
+ Started
63
+ ..
64
+ Finished in 0.000838 seconds.
65
+
66
+ 2 tests, 2 assertions, 0 failures, 0 errors
67
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
68
+ Started
69
+ ..
70
+ Finished in 0.000672 seconds.
71
+
72
+ 2 tests, 2 assertions, 0 failures, 0 errors
73
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
74
+ Started
75
+ ..
76
+ Finished in 0.000864 seconds.
77
+
78
+ 2 tests, 2 assertions, 0 failures, 0 errors
79
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
80
+ Started
81
+ ..
82
+ Finished in 0.001295 seconds.
83
+
84
+ 2 tests, 2 assertions, 0 failures, 0 errors
85
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
86
+ Started
87
+ ..
88
+ Finished in 0.000868 seconds.
89
+
90
+ 2 tests, 2 assertions, 0 failures, 0 errors
91
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
92
+ Started
93
+ ..
94
+ Finished in 0.000871 seconds.
95
+
96
+ 2 tests, 2 assertions, 0 failures, 0 errors
97
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
98
+ Started
99
+ ..
100
+ Finished in 0.000838 seconds.
101
+
102
+ 2 tests, 2 assertions, 0 failures, 0 errors
103
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
104
+ Started
105
+ ..
106
+ Finished in 0.000866 seconds.
107
+
108
+ 2 tests, 2 assertions, 0 failures, 0 errors
109
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
110
+ Started
111
+ ..
112
+ Finished in 0.001105 seconds.
113
+
114
+ 2 tests, 2 assertions, 0 failures, 0 errors
115
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
116
+ Started
117
+ ..
118
+ Finished in 0.00067 seconds.
119
+
120
+ 2 tests, 2 assertions, 0 failures, 0 errors
121
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
122
+ Started
123
+ ..
124
+ Finished in 0.000891 seconds.
125
+
126
+ 2 tests, 2 assertions, 0 failures, 0 errors
127
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
128
+ Started
129
+ ..
130
+ Finished in 0.000872 seconds.
131
+
132
+ 2 tests, 2 assertions, 0 failures, 0 errors
133
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
134
+ Started
135
+ ..
136
+ Finished in 0.000836 seconds.
137
+
138
+ 2 tests, 2 assertions, 0 failures, 0 errors
139
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
140
+ Started
141
+ ..
142
+ Finished in 0.000735 seconds.
143
+
144
+ 2 tests, 2 assertions, 0 failures, 0 errors
145
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
146
+ Started
147
+ ..
148
+ Finished in 0.000644 seconds.
149
+
150
+ 2 tests, 2 assertions, 0 failures, 0 errors
151
+ Loaded suite [test/test_helper.rb, test/test_task.rb]
152
+ Started
153
+ ..
154
+ Finished in 0.000666 seconds.
155
+
156
+ 2 tests, 2 assertions, 0 failures, 0 errors
@@ -0,0 +1,16 @@
1
+ require 'clio/commandline'
2
+
3
+ module Ratch
4
+
5
+ class Commandline < Clio::Commandline
6
+ opt('--help' , "display help")
7
+ opt('--trace' , "trace execution")
8
+ opt('--debug' , "debug mode")
9
+ opt('--pretend -p' , "no disk writes")
10
+ opt('--quiet -q' , "run silently")
11
+ opt('--verbose' , "extra output")
12
+ opt('--force' , "force operations")
13
+ end
14
+
15
+ end
16
+
@@ -1,8 +1,5 @@
1
1
  class String
2
2
 
3
- # okay this is a bit much --we should subclass string.
4
- # but it will do for now and we will work this out
5
- # when CLIO is up and running.
6
3
  attr_accessor :color
7
4
 
8
5
  # Find actual filename (casefolding) and returns it.
@@ -37,6 +34,7 @@ class String
37
34
  blank = false
38
35
  end
39
36
  end
37
+ text = text.gsub("\n\n\n","\n\n")
40
38
  return text
41
39
  end
42
40
 
@@ -1,7 +1,7 @@
1
1
  #
2
2
  class Array
3
3
 
4
- # Convert an array into command line parameters.
4
+ # Convert an array into commandline parameters.
5
5
  # The array is accepted in the format of Ruby
6
6
  # method arguments --ie. [arg1, arg2, ..., hash]
7
7
 
@@ -5,24 +5,18 @@ require 'fileutils'
5
5
  require 'ratch/core_ext'
6
6
  require 'ratch/index'
7
7
  require 'ratch/io'
8
- require 'ratch/runmode'
8
+ require 'ratch/commandline'
9
+ require 'ratch/emailer'
9
10
 
10
11
  require 'ratch/task'
11
12
 
12
13
  require 'facets/platform'
13
- require 'facets/arguments'
14
- require 'facets/ziputils'
15
14
 
16
- #require 'annotatable'
15
+ require 'folio'
16
+
17
17
  #require 'facets/openhash'
18
18
  #require 'facets/argvector'
19
19
 
20
- begin
21
- require 'facets/net/smtp_tls'
22
- rescue LoadError
23
- require 'net/smtp'
24
- end
25
-
26
20
 
27
21
  module Ratch
28
22
 
@@ -40,101 +34,49 @@ module Ratch
40
34
 
41
35
  extend self
42
36
 
43
- @runmode = ioc[:mode] || Runmode.load_argv!
44
- @io = ioc[:io] || IO.new(@runmode)
45
- end
37
+ @cli = ioc[:cli] || Commandline.new
38
+ @io = ioc[:io] || IO.new(@cli)
46
39
 
47
- # Delgate run mode settings to Ratch::RunMode object.
48
- def runmode
49
- @runmode
50
- end
40
+ mode = {
41
+ :dryrun => @cli.dryrun?,
42
+ :verbose => @cli.verbose?
43
+ #:noop => ?
44
+ }
51
45
 
52
- # Delgate input/output routines to Ratch::IO object.
53
- def io
54
- @io
46
+ @fio = ioc[:fio] || Folio::Shell.new(mode)
55
47
  end
56
48
 
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
49
+ # Delagate input/output routines to Ratch::IO object.
50
+ attr :io
62
51
 
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
52
+ # Delagate file operations to Folio::Shell.
53
+ attr :fio
72
54
 
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
55
+ # Delagate commandline settings to Ratch::Commandline object.
56
+ attr :cli
82
57
 
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
58
+ alias_method :commandline, :cli
97
59
 
98
- # Current platform.
99
- def current_platform
100
- Platform.local.to_s
101
- end
60
+ # DEPRECATE!
61
+ alias_method :command, :cli
102
62
 
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
63
  #
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
64
+ #def commandline
65
+ # #@commandline ||= ArgVector.new(ARGV)
66
+ # @commandline
67
+ #end
119
68
 
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
69
+ def force? ; cli.force? ; end
70
+ def trace? ; cli.trace? ; end
71
+ def debug? ; cli.debug? ; end
72
+ def pretend? ; cli.pretend? ; end
73
+ def dryrun? ; cli.pretend? ; end
74
+ def quiet? ; cli.quiet? ; end
75
+ def verbose? ; cli.verbose? ; end
76
+
77
+ # Current platform.
78
+ def current_platform
79
+ Platform.local.to_s
138
80
  end
139
81
 
140
82
  # Shell runner.
@@ -152,42 +94,16 @@ module Ratch
152
94
  end
153
95
  end
154
96
 
155
- # TODO: DEPRECATE #sh in favor of #shell.
97
+ # TODO: DEPRECATE #sh in favor of #shell (?)
156
98
  alias_method :sh, :shell
157
99
 
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)
100
+ # Delegate to Filio::Shell.
101
+ def method_missing(s, *a, &b)
102
+ if @fio.respond_to?(s)
103
+ @fio.__send__(s, *a, &b)
104
+ else
105
+ super
106
+ end
191
107
  end
192
108
 
193
109
  # Provides convenient starting points in the file system.
@@ -196,6 +112,7 @@ module Ratch
196
112
  # home #=> #<Pathname:/home/jimmy>
197
113
  # work #=> #<Pathname:/home/jimmy/Documents>
198
114
  #
115
+ # TODO: Replace these with Folio when Folio's is as capable.
199
116
 
200
117
  # Current root path.
201
118
  def root(*args)
@@ -215,10 +132,10 @@ module Ratch
215
132
  alias_method :pwd, :work
216
133
 
217
134
  # Bonus FileUtils features.
218
- def cd(*a,&b)
219
- puts "cd #{a}" if dryrun? or trace?
220
- fileutils.chdir(*a,&b)
221
- end
135
+ #def cd(*a,&b)
136
+ # puts "cd #{a}" if dryrun? or trace?
137
+ # fileutils.chdir(*a,&b)
138
+ #end
222
139
 
223
140
  # Read file.
224
141
  def file_read(path)
@@ -242,13 +159,6 @@ module Ratch
242
159
  alias_method :exist?, :exists? #; module_function :exist?
243
160
  alias_method :path?, :exists? #; module_function :path?
244
161
 
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
162
  # Is a given path a regular file? If +path+ is a glob
253
163
  # then checks to see if all matches are refular files.
254
164
  def file?(path)
@@ -256,11 +166,6 @@ module Ratch
256
166
  paths.not_empty? && paths.all?{ |f| FileTest.file?(f) }
257
167
  end
258
168
 
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
169
  # Is a given path a directory? If +path+ is a glob
265
170
  # checks to see if all matches are directories.
266
171
  def dir?(path)
@@ -269,130 +174,67 @@ module Ratch
269
174
  end
270
175
  alias_method :directory?, :dir? #; module_function :directory?
271
176
 
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?
281
- #
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
177
 
301
- return true if mtimes.empty? # TODO: This the way to go here?
178
+ # TODO: Deprecate these?
302
179
 
303
- File.mtime(path) < mtimes.max
180
+ # Assert that a path exists.
181
+ def exists!(*paths)
182
+ abort "path not found #{path}" unless paths.any?{|path| exists?(path)}
304
183
  end
305
- =end
184
+ alias_method :exist!, :exists! #; module_function :exist!
185
+ alias_method :path!, :exists! #; module_function :path!
306
186
 
307
- # Glob files.
308
- def glob(*args, &blk)
309
- Dir.glob(*args, &blk)
187
+ # Assert that a given path is a file.
188
+ def file!(*paths)
189
+ abort "file not found #{path}" unless paths.any?{|path| file?(path)}
310
190
  end
311
191
 
312
- # Multiglob files.
313
- def multiglob(*args, &blk)
314
- Dir.multiglob(*args, &blk)
192
+ # Assert that a given path is a directory.
193
+ def dir!(*paths)
194
+ paths.each do |path|
195
+ abort "Directory not found: '#{path}'." unless dir?(path)
196
+ end
315
197
  end
198
+ alias_method :directory!, :dir! #; module_function :directory!
316
199
 
317
- # Multiglob recursive.
318
- def multiglob_r(*args, &blk)
319
- Dir.multiglob_r(*args, &blk)
320
- end
321
200
 
322
- # Stage by hard linking included files to a stage directory.
323
- #
324
- # stage_directory Stage directory.
325
- # files Files to link to stage.
201
+ # Load configuration data from a file.
202
+ # Results are cached and and empty Hash is
203
+ # returned if the file is not found.
326
204
  #
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
205
+ # Since they are YAML files, they can optionally
206
+ # end with '.yaml' or '.yml'.
207
+ def configuration(file)
208
+ @configuration ||= {}
209
+ @configuration[file] ||= (
210
+ begin
211
+ configuration!(file)
212
+ rescue LoadError
213
+ Hash.new{ |h,k| h[k] = {} }
350
214
  end
351
- end
352
-
353
- return stage_directory
215
+ )
354
216
  end
355
217
 
356
- # Delegate access to ZipUtils.
218
+ # Load configuration data from a file.
219
+ # The "bang" version will raise an error
220
+ # if file is not found. It also does not
221
+ # cache the results.
357
222
  #
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)
223
+ # Since they are YAML files, they can optionally
224
+ # end with '.yaml' or '.yml'.
225
+ def configuration!(file)
226
+ @configuration ||= {}
227
+ patt = file + "{.yml,.yaml,}"
228
+ path = Dir.glob(patt, File::FNM_CASEFOLD).find{ |f| File.file?(f) }
229
+ if path
230
+ # The || {} is in case the file is empty.
231
+ data = YAML::load(File.open(path)) || {}
232
+ @configuration[file] = data
372
233
  else
373
- raise ArguementError, "unsupported compression format -- #{format}"
234
+ raise LoadError, "Missing file -- #{path}"
374
235
  end
375
236
  end
376
237
 
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
238
  #
397
239
  #
398
240
  def naming_policy(*policies)
@@ -407,7 +249,7 @@ module Ratch
407
249
  #
408
250
  def apply_naming_policy(name, ext)
409
251
  naming_policy.each do |policy|
410
- case policy
252
+ case policy.to_s
411
253
  when /^low/, /^down/
412
254
  name = name.downcase
413
255
  when /^up/
@@ -438,60 +280,141 @@ module Ratch
438
280
  # message Mesage to send -or-
439
281
  # file File that contains message.
440
282
  #
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
283
+ def email(options)
284
+ emailer = Emailer.new(options.rekey)
285
+ success = emailer.email
286
+ if Exception === success
287
+ puts "Email failed: #{success.message}."
288
+ else
289
+ puts "Email sent successfully to #{success.join(';')}."
491
290
  end
492
291
  end
493
292
 
293
+
294
+ # Internal status report.
295
+ # Only output if dryrun or trace mode.
296
+ def status(message)
297
+ io.status(message)
298
+ end
299
+
300
+ # Convenient method to get simple console reply.
301
+ def ask(question, answers=nil)
302
+ io.ask(question, answers)
303
+ end
304
+
305
+ # Ask for a password. (FIXME: only for unix so far)
306
+ def password(prompt=nil)
307
+ io.password(prompt)
308
+ end
309
+
494
310
  end
495
311
 
496
312
  end
497
313
 
314
+
315
+
316
+
317
+
318
+
319
+
320
+ # Delegate file system routines to FileUtils or FileUtils::DryRun,
321
+ # depending on dryrun mode.
322
+ #def fileutils
323
+ # dryrun? ? ::FileUtils::DryRun : ::FileUtils
324
+ #end
325
+
326
+ # Add FileUtils Features
327
+ #::FileUtils.private_instance_methods(false).each do |meth|
328
+ # next if meth =~ /^fu_/
329
+ # module_eval %{
330
+ # def #{meth}(*a,&b)
331
+ # fileutils.#{meth}(*a,&b)
332
+ # end
333
+ # }
334
+ #end
335
+
336
+ # Add FileTest Features
337
+ #::FileTest.private_instance_methods(false).each do |meth|
338
+ # next if meth =~ /^fu_/
339
+ # module_eval %{
340
+ # def #{meth}(*a,&b)
341
+ # FileTest.#{meth}(*a,&b)
342
+ # end
343
+ # }
344
+ #end
345
+
346
+ # # Delegate access to ZipUtils.
347
+ # #
348
+ # def ziputils
349
+ # dryrun? ? ::ZipUtils::DryRun : ::ZipUtils
350
+ # end
351
+
352
+ # # Compress directory.
353
+ # #
354
+ # def compress(format, folder, file=nil, options={})
355
+ # case format.to_s.downcase
356
+ # when 'zip'
357
+ # ziputils.zip(folder, file, options)
358
+ # when 'tgz'
359
+ # ziputils.tgz(folder, file, options)
360
+ # when 'tbz', 'bzip'
361
+ # ziputils.tar_bzip(folder, file, options)
362
+ # else
363
+ # raise ArguementError, "unsupported compression format -- #{format}"
364
+ # end
365
+ # end
366
+
367
+ # # Create a zip file of a directory.
368
+ # #
369
+ # def zip(folder, file=nil, options={})
370
+ # ziputils.zip(folder, file, options)
371
+ # end
372
+
373
+ # # Create a tar.bz2 file of a directory.
374
+ # #
375
+ # def tar_bzip(folder, file=nil, options={})
376
+ # ziputils.tar_bzip(folder, file, options)
377
+ # end
378
+
379
+ # # Create a tgz file of a directory.
380
+ # #
381
+ # def tar_gzip(folder, file=nil, options={})
382
+ # ziputils.tar_gzip(folder, file, options)
383
+ # end
384
+ # alias_method :tgz, :tar_gzip
385
+
386
+ # Glob files.
387
+ #def glob(*args, &blk)
388
+ # Dir.glob(*args, &blk)
389
+ #end
390
+
391
+ # Multiglob files.
392
+ #def multiglob(*args, &blk)
393
+ # Dir.multiglob(*args, &blk)
394
+ #end
395
+
396
+ # Multiglob recursive.
397
+ #def multiglob_r(*args, &blk)
398
+ # Dir.multiglob_r(*args, &blk)
399
+ #end
400
+
401
+ =begin
402
+ # Does a path need updating, based on given +sources+?
403
+ # This compares mtimes of give paths. Returns false
404
+ # if the path needs to be updated.
405
+ #
406
+ # TODO: Put this in FileTest instead?
407
+
408
+ def out_of_date?(path, *sources)
409
+ return true unless File.exist?(path)
410
+
411
+ sources = sources.collect{ |source| Dir.glob(source) }.flatten
412
+ mtimes = sources.collect{ |file| File.mtime(file) }
413
+
414
+ return true if mtimes.empty? # TODO: This the way to go here?
415
+
416
+ File.mtime(path) < mtimes.max
417
+ end
418
+ =end
419
+
420
+