ratch 0.1

Sign up to get free protection for your applications and to get access to all the features.
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