creating a temporary directory

W

Wybo Dekker

I would like to create a temporary directory that disappears
after exit (analogous to Tempfile). But ruby doesn't seem to have a
Tempdir class?
(Dir.tmpdir only points to a system tempdir, that should not
disappear of course.)
 
N

nobu.nokada

Hi,

At Sat, 2 Apr 2005 18:26:51 +0900,
Wybo Dekker wrote in [ruby-talk:136465]:
I would like to create a temporary directory that disappears
after exit (analogous to Tempfile). But ruby doesn't seem to have a
Tempdir class?

Once I had proposed it at [ruby-dev:21336], and this is the
patch for latest version.


Index: lib/tempfile.rb
===================================================================
RCS file: /cvs/ruby/src/ruby/lib/tempfile.rb,v
retrieving revision 1.27
diff -U2 -p -r1.27 tempfile.rb
--- lib/tempfile.rb 15 Nov 2004 16:45:02 -0000 1.27
+++ lib/tempfile.rb 16 Nov 2004 01:31:27 -0000
@@ -8,19 +8,16 @@ require 'delegate'
require 'tmpdir'

-# A class for managing temporary files. This library is written to be
-# thread safe.
-class Tempfile < DelegateClass(File)
+module AutoRemoval
MAX_TRY = 10
@@cleanlist = []

- # Creates a temporary file of mode 0600 in the temporary directory
- # whose name is basename.pid.n and opens with mode "w+". A Tempfile
- # object works just like a File object.
- #
- # If tmpdir is omitted, the temporary directory is determined by
- # Dir::tmpdir provided by 'tmpdir.rb'.
- # When $SAFE > 0 and the given tmpdir is tainted, it uses
- # /tmp. (Note that ENV values are tainted by default)
- def initialize(basename, tmpdir=Dir::tmpdir)
+ private
+
+ def make_tmpname(basename, n)
+ sprintf('%s%d.%d', basename, $$, n)
+ end
+ private :make_tmpname
+
+ def createtmp(basename, tmpdir=Dir::tmpdir) # :nodoc:
if $SAFE > 0 and tmpdir.tainted?
tmpdir = '/tmp'
@@ -29,17 +26,13 @@ class Tempfile < DelegateClass(File)
lock = nil
n = failure = 0
-
+
begin
Thread.critical = true
-
begin
- tmpname = File.join(tmpdir, make_tmpname(basename, n))
- lock = tmpname + '.lock'
- n += 1
- end while @@cleanlist.include?(tmpname) or
- File.exist?(lock) or File.exist?(tmpname)
-
- Dir.mkdir(lock)
+ tmpname = File.join(tmpdir, make_tmpname(basename, n))
+ n += 1
+ end until !@@cleanlist.include?(tmpname) and yield(tmpname)
rescue
+ p $!
failure += 1
retry if failure < MAX_TRY
@@ -49,13 +42,63 @@ class Tempfile < DelegateClass(File)
end

- @data = [tmpname]
- @clean_proc = Tempfile.callback(@data)
+ tmpname
+ end
+
+ def self.callback(path, clear) # :nodoc:
+ @@cleanlist << path
+ data = [path]
+ pid = $$
+ return Proc.new {
+ if pid == $$
+ path, tmpfile = *data
+
+ print "removing ", path, "..." if $DEBUG
+
+ tmpfile.close if tmpfile
+
+ # keep this order for thread safeness
+ if File.exist?(path)
+ clear.call(path)
+ end
+ @@cleanlist.delete(path)
+
+ print "done\n" if $DEBUG
+ end
+ }, data
+ end
+
+ def self.unregister(path)
+ @@cleanlist.delete(path)
+ end
+end
+
+# A class for managing temporary files. This library is written to be
+# thread safe.
+class Tempfile < DelegateClass(File)
+ include AutoRemoval
+
+ # Creates a temporary file of mode 0600 in the temporary directory
+ # whose name is basename.pid.n and opens with mode "w+". A Tempfile
+ # object works just like a File object.
+ #
+ # If tmpdir is omitted, the temporary directory is determined by
+ # Dir::tmpdir provided by 'tmpdir.rb'.
+ # When $SAFE > 0 and the given tmpdir is tainted, it uses
+ # /tmp. (Note that ENV values are tainted by default)
+ def initialize(*args)
+ lock = nil
+ tmpname = createtmp(*args) do |tmpname|
+ lock = tmpname + '.lock'
+ unless File.exist?(lock) or File.exist?(tmpname)
+ Dir.mkdir(lock)
+ end
+ end
+
+ @clean_proc, @data = AutoRemoval.callback(tmpname, File.method:)unlink))
ObjectSpace.define_finalizer(self, @clean_proc)

@tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
@tmpname = tmpname
- @@cleanlist << @tmpname
@data[1] = @tmpfile
- @data[2] = @@cleanlist

super(@tmpfile)
@@ -67,9 +110,4 @@ class Tempfile < DelegateClass(File)
end

- def make_tmpname(basename, n)
- sprintf('%s%d.%d', basename, $$, n)
- end
- private :make_tmpname
-
# Opens or reopens the file with mode "r+".
def open
@@ -87,5 +125,5 @@ class Tempfile < DelegateClass(File)
protected :_close

- #Closes the file. If the optional flag is true, unlinks the file
+ # Closes the file. If the optional flag is true, unlinks the file
# after closing.
#
@@ -116,5 +154,5 @@ class Tempfile < DelegateClass(File)
begin
File.unlink(@tmpname) if File.exist?(@tmpname)
- @@cleanlist.delete(@tmpname)
+ AutoRemoval.unregister(@tmpname)
@data = @tmpname = nil
ObjectSpace.undefine_finalizer(self)
@@ -143,23 +181,4 @@ class Tempfile < DelegateClass(File)

class << self
- def callback(data) # :nodoc:
- pid = $$
- Proc.new {
- if pid == $$
- path, tmpfile, cleanlist = *data
-
- print "removing ", path, "..." if $DEBUG
-
- tmpfile.close if tmpfile
-
- # keep this order for thread safeness
- File.unlink(path) if File.exist?(path)
- cleanlist.delete(path) if cleanlist
-
- print "done\n" if $DEBUG
- end
- }
- end
-
# If no block is given, this is a synonym for new().
#
@@ -185,4 +204,33 @@ class Tempfile < DelegateClass(File)
end

+require 'pathname'
+class Tempdir < Pathname
+ include AutoRemoval
+
+ def initialize(*args)
+ require 'fileutils'
+
+ tmpname = createtmp(*args) do |tmpname|
+ unless File.exist?(tmpname)
+ Dir.mkdir(tmpname, 0700)
+ end
+ end
+
+ super(tmpname)
+ @clean_proc, = AutoRemoval.callback(tmpname, FileUtils.method:)rm_rf))
+ ObjectSpace.define_finalizer(self, @clean_proc)
+ end
+
+ def open(basename, *modes, &block)
+ File.open(self+basename, *modes, &block)
+ end
+
+ def clear
+ FileUtils.rm_rf(@tmpname)
+ @clean_proc.call
+ ObjectSpace.undefine_finalizer(self)
+ end
+end
+
if __FILE__ == $0
# $DEBUG = true
@@ -193,3 +241,6 @@ if __FILE__ == $0
p f.gets # => "foo\n"
f.close!
+ d = Tempdir.new("hoge")
+ system("ls", "-dl", d.to_s)
+ p d
end
 
W

Wybo Dekker

Hi,

At Sat, 2 Apr 2005 18:26:51 +0900,
Wybo Dekker wrote in [ruby-talk:136465]:
I would like to create a temporary directory that disappears
after exit (analogous to Tempfile). But ruby doesn't seem to have a
Tempdir class?

Once I had proposed it at [ruby-dev:21336], and this is the
patch for latest version.

Thanks, that worked! But one question still:

I took the tempfile.rb from the cvs, patched it, then moved it into the
1.8.2 library. The original tempfile there had "lambda {", where the new
file has "Proc.new {". No problems to be expected?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top