ratch 0.1

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 (47) hide show
  1. data/LICENSE.txt +344 -0
  2. data/README.txt +10 -0
  3. data/bin/lt +4 -0
  4. data/bin/ludo +4 -0
  5. data/bin/ratch +8 -0
  6. data/data/mint/ratch/announce +224 -0
  7. data/data/mint/ratch/install +49 -0
  8. data/data/mint/ratch/notes +183 -0
  9. data/data/mint/ratch/publish +44 -0
  10. data/data/mint/ratch/rdoc +40 -0
  11. data/data/mint/ratch/setup +1616 -0
  12. data/data/mint/ratch/stats +138 -0
  13. data/demo/README +8 -0
  14. data/demo/doc/rdoc/created.rid +1 -0
  15. data/demo/doc/rdoc/files/README.html +112 -0
  16. data/demo/doc/rdoc/files/lib/foo/foo_rb.html +145 -0
  17. data/demo/doc/rdoc/fr_class_index.html +26 -0
  18. data/demo/doc/rdoc/fr_file_index.html +28 -0
  19. data/demo/doc/rdoc/fr_method_index.html +27 -0
  20. data/demo/doc/rdoc/index.html +24 -0
  21. data/demo/doc/rdoc/rdoc-style.css +208 -0
  22. data/demo/lib/foo/foo.rb +7 -0
  23. data/demo/util/conf/rdoc +4 -0
  24. data/demo/util/one +6 -0
  25. data/demo/util/rdoc +39 -0
  26. data/demo/util/tryme +10 -0
  27. data/dev/taskable-simple.rb +42 -0
  28. data/dev/taskable.rb +573 -0
  29. data/lib/ratch/batch.rb +43 -0
  30. data/lib/ratch/cli/lt.rb +56 -0
  31. data/lib/ratch/cli/ludo.rb +14 -0
  32. data/lib/ratch/cli/ratch.rb +47 -0
  33. data/lib/ratch/configutils.rb +100 -0
  34. data/lib/ratch/consoleutils.rb +88 -0
  35. data/lib/ratch/emailutils.rb +88 -0
  36. data/lib/ratch/fileutils.rb +173 -0
  37. data/lib/ratch/options.rb +57 -0
  38. data/lib/ratch/runnable.rb +117 -0
  39. data/lib/ratch/taskable.rb +105 -0
  40. data/lib/ratch/taskutils.rb +44 -0
  41. data/lib/ratch/uploadutils.rb +413 -0
  42. data/meta/manifest.txt +70 -0
  43. data/meta/project.yaml +24 -0
  44. data/misc/original.rb +308 -0
  45. data/task/setup +1616 -0
  46. data/task/stats +138 -0
  47. metadata +114 -0
@@ -0,0 +1,57 @@
1
+
2
+ module Ratch
3
+
4
+ # General Options
5
+
6
+ module GeneralOptions
7
+
8
+ #
9
+
10
+ def argv
11
+ @argv ||= ARGV.dup
12
+ end
13
+
14
+ # Convert command line argv to args.
15
+ #
16
+ # TODO Is this implmented as expected?
17
+
18
+ def command_parameters
19
+ argv.to_params
20
+ end
21
+
22
+ # Debug mode.
23
+
24
+ def debug?
25
+ @debug
26
+ end
27
+
28
+ #
29
+
30
+ def trace?
31
+ @trace ||= %w{--trace}.any?{|a| argv.delete(a)}
32
+ end
33
+
34
+ #
35
+
36
+ def trace!
37
+ @trace = true
38
+ end
39
+
40
+ #
41
+
42
+ def noharm?
43
+ @noharm ||= %w{--dryrun --dry-run --noharm}.any?{|a| argv.delete(a)}
44
+ end
45
+
46
+ alias_method :dryrun?, :noharm? ; module_function :dryrun?
47
+
48
+ #
49
+
50
+ def noharm!
51
+ @noharm = true
52
+ end
53
+ alias_method :dryrun!, :noharm! ; module_function :dryrun!
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,117 @@
1
+ module Ratch
2
+
3
+ #
4
+
5
+ module Runnable
6
+
7
+ # TODO How to handle arguments?
8
+
9
+ def run(batchfile, arguments=nil)
10
+ BatchFile.new(batchfile).call
11
+ # # TODO probably should raise error instead
12
+ # abort "missing batch file -- #{batchfile}" unless File.file?(batchfile)
13
+ # script = File.read($0 = batchfile)
14
+ # #instance_eval(script)
15
+ # eval(script, binding, $0)
16
+ end
17
+
18
+ # Batch run, ie. run and cache.
19
+ # Usually this can be take care of by method_missing.
20
+ # But, in some cases, built in method names block task
21
+ # calls, so you have to use #batch to invoke those.
22
+
23
+ def batch(batchfile, arguments=nil)
24
+ task_cache[task] ||= run(batchfile, arguments)
25
+ end
26
+
27
+ # Task cache, which prevents batch runs from re-executing.
28
+
29
+ def task_cache
30
+ @@task_cache ||= {}
31
+ end
32
+
33
+ # Is a task complete or in the process of being completed?
34
+
35
+ def done?(task)
36
+ task == $0 or task_cache.key?(task)
37
+ end
38
+
39
+ # Shell runner.
40
+
41
+ def sh(cmd)
42
+ if noharm?
43
+ puts cmd
44
+ true
45
+ else
46
+ puts "--> system call: #{cmd}" if trace?
47
+ system(cmd)
48
+ end
49
+ end
50
+
51
+ # Abort running.
52
+
53
+ def abort(msg=nil)
54
+ puts msg if msg
55
+ exit 0
56
+ end
57
+
58
+ end
59
+
60
+ #
61
+ module OpenRunnable
62
+
63
+ # If method is missing try to run an external task
64
+ # or binary by that name. If it is a binary, arguments
65
+ # translate into commandline parameters. For example:
66
+ #
67
+ # tar 'foo/', :x=>true, :v=>true, :z=>true, :f=>'foo.tar.gz'
68
+ #
69
+ # or
70
+ #
71
+ # tar '-xvzf', "foo.tar.gz", "foo/"
72
+ #
73
+ # becomes
74
+ #
75
+ # tar -x -v -z -f foo.tar.gz foo/
76
+ #
77
+ # If it is a task, it will be cached. Tasks only ever run once.
78
+ # To run them more than once you can manually execute them with #run.
79
+ # Likewise you can manually run and cache by calling #batch.
80
+ # This is good to know, b/c in some cases built in method names
81
+ # block task calls, so you have to #batch to invoke them.
82
+
83
+ def method_missing(sym,*args)
84
+ puts "method_missing: #{sym}" if debug?
85
+
86
+ name = sym.to_s
87
+
88
+ task = task?(name)
89
+ done = task && done?(task)
90
+ cache = task && !done && name[1,-1] != '!'
91
+ bin = bin?(name) if (!task || done)
92
+ none = task && done && !bin
93
+ #task = name if bin
94
+
95
+ return super unless task || bin
96
+
97
+ return if none # nothing to do
98
+
99
+ params = args.to_params
100
+
101
+ if bin
102
+ cmd = "#{File.basename(bin)} #{params}"
103
+ res = sh(cmd)
104
+ elsif task
105
+ cmd = "./#{task} #{params}"
106
+ puts "--> #{cache ? '' : 'not-'}cached execution: #{cmd}" if trace?
107
+ res = run(task, args)
108
+ if cache
109
+ #@task_cache[task] ||= (system(cmd); true)
110
+ task_cache[task] ||= res
111
+ end
112
+ end
113
+
114
+ return res
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,105 @@
1
+ module Ratch
2
+
3
+ module Taskable
4
+
5
+ #def main
6
+ # @main
7
+ #end
8
+
9
+ def tasks
10
+ @tasks ||= {}
11
+ end
12
+
13
+ # Define a main task.
14
+
15
+ def main(name, &block)
16
+ @main = Task.register(name, &block)
17
+ tasks[@main.name] = @main
18
+ end
19
+
20
+ # Define a task.
21
+
22
+ def task(name, &block)
23
+ tsk = Task.register(name, &block)
24
+ tasks[tsk.name] = tsk
25
+ end
26
+
27
+ # Define a file target.
28
+
29
+ def file(name, &block)
30
+ tasks[name.to_s] = FileTask.register(name, &block)
31
+ end
32
+
33
+ end
34
+
35
+ #
36
+ #
37
+ #
38
+
39
+ class Task
40
+
41
+ def self.tasks
42
+ @@tasks ||= {}
43
+ end
44
+
45
+ def self.register(name_deps, &block)
46
+ if Hash===name_deps
47
+ name = name_deps.keys[0]
48
+ deps = name_deps.values[0]
49
+ else
50
+ name = name_deps
51
+ deps = []
52
+ end
53
+ tasks[name.to_s] = new(name, *deps, &block)
54
+ end
55
+
56
+ attr :name
57
+ attr :preqs
58
+ attr :action
59
+
60
+ #
61
+
62
+ def initialize(name, *preqs, &action)
63
+ @name = name.to_s
64
+ @preqs = preqs
65
+ @action = action
66
+ end
67
+
68
+ def call
69
+ #p plan
70
+ plan.each{ |name| @@tasks[name].action_call }
71
+ #action_call
72
+ end
73
+
74
+ #
75
+
76
+ def action_call
77
+ @action.call if @action
78
+ end
79
+
80
+ # TODO Check for circular dependencies.
81
+
82
+ def plan(list=[])
83
+ if list.include?(name)
84
+ raise "Circular dependency #{name}."
85
+ end
86
+
87
+ @preqs.each do |need|
88
+ need = need.to_s
89
+ next if list.include?(need)
90
+ @@tasks[need].plan(list)
91
+ end
92
+ list << name
93
+ return list
94
+ end
95
+
96
+ end
97
+
98
+ #
99
+ #
100
+ #
101
+
102
+ class FileTask < Task
103
+ end
104
+
105
+ end
@@ -0,0 +1,44 @@
1
+ # TITLE:
2
+ #
3
+ # TaskUtils
4
+ #
5
+ # SUMMARY:
6
+ #
7
+ # All the task methods used by BatchRunner.
8
+ #
9
+ # COPYRIGHT:
10
+ #
11
+ # Copyright (c) 2007 7rans
12
+
13
+ require 'yaml'
14
+
15
+ #require 'facets/hash/merge' # for reverse_merge
16
+
17
+ require 'ratch/options'
18
+ require 'ratch/consoleutils'
19
+ require 'ratch/configutils'
20
+ require 'ratch/emailutils'
21
+ require 'ratch/fileutils'
22
+ require 'ratch/taskable'
23
+ require 'ratch/runnable'
24
+
25
+
26
+
27
+ module Ratch
28
+
29
+ # = TaskUtils
30
+
31
+ module TaskUtils
32
+ include GeneralOptions
33
+
34
+ include ConsoleUtils
35
+ include FileUtils
36
+ include ConfigUtils
37
+ include EmailUtils
38
+
39
+ include Taskable
40
+ include Runnable
41
+ include OpenRunnable
42
+ end
43
+
44
+ end
@@ -0,0 +1,413 @@
1
+ # = uploadutils.rb
2
+ #
3
+ # CREDIT Thomas Sawyer
4
+ #
5
+ # TODO Incorporate password into scp and ftp ?
6
+ # TODO rsync needs --delete option
7
+
8
+ require 'openssl'
9
+ require 'shellwords'
10
+ require 'tmpdir'
11
+
12
+ require 'facets/openobject'
13
+
14
+ module Ratch
15
+
16
+ # Upload files to host. These means of uploading are current
17
+ # supported: ftp, sftp, scp and rsync.
18
+ #
19
+ # user Username for host.
20
+ # host Host server's domain name.
21
+ # root Document root path on host.
22
+ # copy Directory of files to publish, or
23
+ # Files to publish using from and to.
24
+ #
25
+ # dryrun If true only pretend to upload.
26
+ # quiet Supress all output.
27
+ # verbose Provide extra details.
28
+ #
29
+ # The copy parameter allows you to simply specify a file
30
+ # or directory which will be published to host's document
31
+ # root location.
32
+ #
33
+ # If you need more control over which files to publish
34
+ # where, you can use the copy parameter instead. Provide
35
+ # an array of pattern strings in the form of "{from} {to}".
36
+ # If the desitination is the host's document root you do
37
+ # not need to specify the {to} part. For example:
38
+ #
39
+ # copy = [ 'web/*', 'doc/api/* doc/api' ]
40
+ #
41
+ # The first copies the files under your project's web directory
42
+ # to the host's document root. The second copies your projects
43
+ # doc/api files to the doc/api location on the host.
44
+ #
45
+ # The internal template used for the outbound destination
46
+ # is 'username@host:root/'.
47
+
48
+ module UploadUtils
49
+
50
+ module_function
51
+
52
+ #
53
+ # Upload via given protocol.
54
+ #
55
+
56
+ def upload( protocol, opts )
57
+ send(protocol.to_s.downcase,opts)
58
+ end
59
+
60
+ #
61
+ # Use ftp to upload files.
62
+ #
63
+
64
+ def ftp( keys )
65
+ keys = upload_parameters(keys)
66
+
67
+ # set transfer rules
68
+ if keys.stage
69
+ trans = stage_transfer(keys.stage)
70
+ else
71
+ files(keys.dir, keys.copy).each do |from|
72
+ trans << [from,from]
73
+ end
74
+ end
75
+
76
+ # append location of publication dir to from
77
+ dir = keys.dir
78
+ trans.collect!{ |from,to| [File.join(dir,from), to] }
79
+
80
+ if keys.dryrun
81
+ puts "ftp open #{keys.user}@#{keys.host}:#{keys.root}/"
82
+ keys.trans.each do |f, t|
83
+ puts "ftp put #{f} #{t}"
84
+ end
85
+ else
86
+ require 'net/ftp'
87
+ Net::FTP.open(keys.host) do |ftp|
88
+ ftp.login(keys.user) #password?
89
+ ftp.chdir(keys.root)
90
+ keys.trans.each do |f, t|
91
+ puts "ftp #{f} #{t}" unless keys.quiet
92
+ ftp.putbinaryfile( f, t, 1024 )
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ #
99
+ # Use sftp to upload files.
100
+ #
101
+
102
+ def sftp( keys )
103
+ keys = upload_parameters(keys)
104
+
105
+ # set transfer rules
106
+ if keys.stage
107
+ trans = stage_transfer(keys.stage)
108
+ else
109
+ files(keys.dir, keys.copy).each do |from|
110
+ trans << [from,from]
111
+ end
112
+ end
113
+
114
+ # append location of publication dir to from
115
+ dir = keys.dir
116
+ trans.collect!{ |from,to| [File.join(dir,from), to] }
117
+
118
+ if keys.dryrun
119
+ puts "sftp open #{keys.user}@#{keys.host}:#{keys.root}/"
120
+ keys.trans.each do |f,t|
121
+ puts "sftp put #{f} #{t}"
122
+ end
123
+ else
124
+ require 'net/sftp'
125
+ Net::SFTP.start(keys.host, keys.user, keys.pass) do |sftp|
126
+ #sftp.login( user )
127
+ sftp.chdir(keys.root)
128
+ keys.trans.each do |f,t|
129
+ puts "sftp #{f} #{t}" unless keys.quiet
130
+ sftp.put_file(f,t) #, 1024 )
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ #
137
+ # Use rsync to upload files.
138
+ #
139
+
140
+ def rsync( keys )
141
+ keys = upload_parameters(keys)
142
+
143
+ flags = []
144
+ flags << "-n" if keys.dryrun
145
+ flags << "-q" if keys.quiet
146
+ flags << "-v" if keys.verbose
147
+ flags << "--progress" unless keys.quiet
148
+ flags = flags.join(' ').strip
149
+ flags = ' ' + flags unless flags.empty?
150
+
151
+ manfile = 'Publish.txt'
152
+
153
+ if keys.stage
154
+ dir = stage_linkdir(keys.dir, keys.stage)
155
+ Dir.chdir(dir) do
156
+ cpy = files(keys.copy)
157
+ end
158
+ manifest = File.join(dir,manfile)
159
+ cmd = %{rsync#{flags} -L -arz --files-from='#{manifest}' #{dir} #{keys.user}@#{keys.host}:/#{keys.root}}
160
+ else
161
+ dir = keys.dir
162
+ cpy = files(dir, keys.copy)
163
+ manifest = File.join(dir,manfile)
164
+ cmd = %{rsync#{flags} -arz --files-from='#{manifest}' #{dir} #{keys.user}@#{keys.host}:/#{keys.root}}
165
+ end
166
+
167
+ #Dir.chdir(keys.dir) do
168
+ begin
169
+ File.open(manifest, 'w'){ |f| f << cpy.join("\n") }
170
+ ENV['RSYNC_PASSWORD'] = keys.pass if keys.pass
171
+ puts cmd unless keys.quiet
172
+ system cmd
173
+ ensure
174
+ ENV.delete('RSYNC_PASSWORD') if keys.pass
175
+ end
176
+ #end
177
+
178
+ end
179
+
180
+ # private (can't do b/c of module_function)
181
+
182
+ # parse publishing options.
183
+
184
+ def upload_parameters( keys )
185
+ keys = OpenObject.new(keys)
186
+
187
+ keys.copy = keys.copy || '**/*'
188
+ keys.host = keys.host || keys.domain
189
+ keys.user = keys.user || keys.username
190
+ keys.root = keys.root || '/'
191
+ #keys.pass = keys.pass || keys.password
192
+
193
+ # validate
194
+ raise ArgumentError, "missing publish parameter -- dir" unless keys.dir
195
+ raise ArgumentError, "missing publish parameter -- host" unless keys.host
196
+ raise ArgumentError, "missing publish parameter -- user" unless keys.user
197
+ #raise ArgumentError, "missing publish parameter -- copy" unless keys.copy
198
+ #raise ArgumentError, "missing publish parameter -- root" unless keys.root
199
+
200
+ keys.root = '' if keys.root.nil?
201
+ keys.root.sub!(/^\//,'')
202
+
203
+ if String===keys.copy and File.directory?(keys.copy)
204
+ copy = File.join(keys.copy, '*')
205
+ end
206
+ keys.copy = [keys.copy].flatten.compact
207
+
208
+ # trans = []
209
+ # keys.copy.each do |from|
210
+ # #from, to = *Shellwords.shellwords(c)
211
+ # #to = from if to.nil?
212
+ # #to = to[1..-1] if to[0,1] == '/'
213
+ # from.sub('*','**/*') unless from =~ /\*\*/
214
+ # files = Dir.glob(from)
215
+ # files.each do |f|
216
+ # #t = File.join(to,File.basename(f))
217
+ # #t = t[1..-1] if t[0,1] == '/'
218
+ # trans << [f,f]
219
+ # end
220
+ # end
221
+ # keys.trans = trans
222
+
223
+ return keys
224
+ end
225
+
226
+ # Put together the list of files to copy.
227
+
228
+ def files( dir, copy )
229
+ Dir.chdir(dir) do
230
+ del, add = copy.partition{ |f| /^[-]/ =~ f }
231
+
232
+ # remove - and + prefixes
233
+ del.collect!{ |f| f.sub(/^[-]/,'') }
234
+ add.collect!{ |f| f.sub(/^[+]/,'') }
235
+
236
+ #del.concat(must_exclude)
237
+
238
+ files = []
239
+ add.each{ |g| files += Dir.multiglob(g) }
240
+ del.each{ |g| files -= Dir.multiglob(g) }
241
+
242
+ files.collect!{ |f| f.sub(/^\//,'') }
243
+
244
+ return files
245
+ end
246
+ end
247
+
248
+ # Combine three part stage list into a two part from->to list.
249
+ #
250
+ # Using the stage list of three space separated fields.
251
+ #
252
+ # fromdir file todir
253
+ #
254
+ # This is used to generate a from -> to list of the form:
255
+ #
256
+ # fromdir/file todir/file
257
+ #
258
+
259
+ def stage_transfer( list )
260
+ trans = []
261
+ list.each do |line|
262
+ trans << Shellwords.shellwords(line)
263
+ end
264
+
265
+ trans.collect! do |from, base, to|
266
+ file = File.join(from,base)
267
+ to = File.join(to,base)
268
+ [from, to]
269
+ end
270
+ end
271
+
272
+ # When using stage options this will create temporary linked location.
273
+
274
+ def stage_linkdir( dir, list )
275
+ folder = File.join(Dir.tmpdir, 'ratchets', 'project', object_id.abs.to_s)
276
+ FileUtils.mkdir_p(folder)
277
+
278
+ Dir.chdir(dir) do
279
+ stage_transfer(list).each do |file, to|
280
+ link = File.join(folder,to)
281
+ FileUtils.ln_s(link,file)
282
+ end
283
+ end
284
+
285
+ return folder
286
+ end
287
+
288
+ end
289
+
290
+ end
291
+
292
+
293
+ =begin
294
+
295
+
296
+ #--
297
+ # SHELLS OUT! Need net/scp library to fix.
298
+ #++
299
+
300
+ # Use scp to upload files.
301
+
302
+ def scp( keys )
303
+ keys = upload_parameters(keys)
304
+
305
+ flags = []
306
+ flags << "-v" if keys.verbose
307
+ flags << "-q" if keys.quiet
308
+ flags = flags.join(' ').strip
309
+ flags = ' ' + flags unless flags.empty?
310
+
311
+ upload_stage(keys) do #|tmpdir|
312
+ cmd = "scp -r#{flags} * #{keys.user}@#{keys.host}:/#{keys.root}"
313
+ puts cmd unless keys.quiet
314
+ system cmd unless keys.dryrun
315
+ end
316
+ end
317
+
318
+ # Use rsync to upload files.
319
+
320
+ def rsync( keys )
321
+ keys = upload_parameters(keys)
322
+
323
+ flags = []
324
+ flags << "-n" if keys.dryrun
325
+ flags << "-v" if keys.verbose
326
+ flags << "-q" if keys.quiet
327
+ flags = flags.join(' ').strip
328
+ flags = ' ' + flags unless flags.empty?
329
+
330
+ upload_stage(keys) do #|tmpdir|
331
+ begin
332
+ ENV['RSYNC_PASSWORD'] = keys.pass if keys.pass
333
+ cmd = "rsync -R#{flags} -arz * #{keys.user}@#{keys.host} /#{keys.root}"
334
+ ensure
335
+ ENV.delete('RSYNC_PASSWORD') if keys.pass
336
+ end
337
+ end
338
+ end
339
+
340
+ # Use ftp to upload files.
341
+
342
+ def ftp( keys )
343
+ keys = upload_parameters(keys)
344
+
345
+ if keys.dryrun
346
+ puts "ftp open #{keys.user}@#{keys.host}:#{keys.root}/"
347
+ keys.trans.each do |f, t|
348
+ puts "ftp put #{f} #{t}"
349
+ end
350
+ else
351
+ require 'net/ftp'
352
+ Net::FTP.open(keys.host) do |ftp|
353
+ ftp.login(keys.user) #password?
354
+ ftp.chdir(keys.root)
355
+ keys.trans.each do |f, t|
356
+ puts "ftp #{f} #{t}" unless keys.quiet
357
+ ftp.putbinaryfile( f, t, 1024 )
358
+ end
359
+ end
360
+ end
361
+ end
362
+
363
+ # Use sftp to upload files.
364
+
365
+ def sftp( keys )
366
+ keys = upload_parameters(keys)
367
+
368
+ if keys.dryrun
369
+ puts "sftp open #{keys.user}@#{keys.host}:#{keys.root}/"
370
+ keys.trans.each do |f,t|
371
+ puts "sftp put #{f} #{t}"
372
+ end
373
+ else
374
+ require 'net/sftp'
375
+ Net::SFTP.start(keys.host, keys.user, keys.pass) do |sftp|
376
+ #sftp.login( user )
377
+ sftp.chdir(keys.root)
378
+ keys.trans.each do |f,t|
379
+ puts "sftp #{f} #{t}" unless keys.quiet
380
+ sftp.put_file(f,t) #, 1024 )
381
+ end
382
+ end
383
+ end
384
+ end
385
+
386
+
387
+ # Creates a stage from which the whole directory can be uploaded.
388
+ # This is needed for scp and rsync which have to shelled out,
389
+ # and can't conveniently copy one file at a time.
390
+
391
+ def upload_stage(keys) #:yield:
392
+ tmp = "scp_#{object_id.abs}_#{ Time.now.strftime("%Y%m%d%H%M%S")}"
393
+ tmpdir = File.join(Dir.tmpdir,tmp)
394
+
395
+ puts "mkdir -p #{tmpdir}" unless keys.quiet
396
+ FileUtils.mkdir_p(tmpdir) # go ahead and do this even if dryrun
397
+
398
+ fu = keys.dryrun ? FileUtils::DryRun : FileUtils
399
+ keys.trans.each do |f, t|
400
+ to = File.join(tmpdir, t)
401
+ fu.mv(f,to)
402
+ end
403
+
404
+ puts "cd #{tmpdir}" unless keys.quiet
405
+ Dir.chdir(tmpdir) do
406
+ yield #(tmpdir)
407
+ end
408
+
409
+ puts "rm -r #{tmpdir}" unless keys.quiet
410
+ FileUtils.rm_r(tmpdir) # now remove the temp dir
411
+ end
412
+
413
+ =end