Class: Tempster
Overview
Tempster
Tempster is a pure-Ruby library for creating temporary files and directories. Unlike other tools, it can create both temporary files and directories, and is designed to be secure, thread-safe, easy-to-use, powerful thanks to user-configurable options, and user-friendly thanks to good defaults so you don’t need to provide any arguments.
Why write another library for this? The Tempfile standard library provides no way to create temporary directories and always deletes the files it creates, even if you want to keep them. The MkTemp gem is insecure and fails on collisions. Linux “mktemp” works fine but is platform-specific. Therefore, I had to write something.
WARNING: Using ‘cd’ and :noop together can be dangerous!
Tempster will only pretend to make directories in :noop (no-operation) mode. In :noop mode, it will also only pretend to change into the directory when using :cd or mktempdircd
.
This can be disastrous if you’re executing non-AutomateIt commands (e.g. system
) that use relative paths and expect to be run inside the newly-created temporary directory because the chdir
didn’t actually happen.
Read previews.txt for instructions on how to write code that can be safely previewed.
Credits
-
Random string generator taken from pleac.sourceforge.net/pleac_ruby/numbers.html
Defined Under Namespace
Classes: Messager
Constant Summary collapse
- DEFAULT_PREFIX =
"tempster"
- DEFAULT_FILE_MODE =
0600
- DEFAULT_DIRECTORY_MODE =
0700
- DEFAULT_ARMOR_LENGTH =
10
- ARMOR_CHARACTERS =
["A".."Z","a".."z","0".."9"].collect{|r| r.to_a}.join
Class Method Summary collapse
-
._armor_string(length = DEFAULT_ARMOR_LENGTH) ⇒ Object
Returns a string of random characters.
-
._tempster(opts = {}, &block) ⇒ Object
Alias for ::tempster.
-
.mktemp(opts = {}, &block) ⇒ Object
Creates a temporary file.
-
.mktempdir(opts = {}, &block) ⇒ Object
Creates a temporary directory.
-
.mktempdircd(opts = {}, &block) ⇒ Object
Creates a temporary directory and changes into it using
chdir
. -
.tempster(opts = {}, &block) ⇒ Object
Options: * :kind – Create a :file or :directory, required.
Class Method Details
._armor_string(length = DEFAULT_ARMOR_LENGTH) ⇒ Object
Returns a string of random characters.
146 147 148 |
# File 'lib/tempster.rb', line 146 def self._armor_string(length=DEFAULT_ARMOR_LENGTH) (1..length).collect{ARMOR_CHARACTERS[rand(ARMOR_CHARACTERS.size)]}.pack("C*") end |
._tempster(opts = {}, &block) ⇒ Object
Alias for ::tempster.
42 43 44 |
# File 'lib/tempster.rb', line 42 def self._tempster(opts={}, &block) # :nodoc: tempster(opts, &block) end |
.mktemp(opts = {}, &block) ⇒ Object
Creates a temporary file.
151 152 153 |
# File 'lib/tempster.rb', line 151 def self.mktemp(opts={}, &block) tempster({:kind => :file}.merge(opts), &block) end |
.mktempdir(opts = {}, &block) ⇒ Object
Creates a temporary directory.
WARNING: See WARNING text at the top of this class’s documentation!
158 159 160 161 |
# File 'lib/tempster.rb', line 158 def self.mktempdir(opts={}, &block) tempster({:kind => :directory}.merge(opts), &block) end |
.mktempdircd(opts = {}, &block) ⇒ Object
Creates a temporary directory and changes into it using chdir
. This is a shortcut for using mktempdir
with the :cd => true
option.
WARNING: See WARNING text at the top of this class’s documentation!
167 168 169 |
# File 'lib/tempster.rb', line 167 def self.mktempdircd(opts={}, &block) tempster({:kind => :directory, :cd => true}.merge(opts), &block) end |
.tempster(opts = {}, &block) ⇒ Object
Options:
-
:kind – Create a :file or :directory, required.
-
:prefix – String to prefix the temporary name with, defaults to “tempster”.
-
:suffix – String to suffix the temporary name with, defaults is no suffix.
-
:name – Same as :prefix
-
:dir – Base directory to create temporary entries in, uses system-wide temporary directory (e.g.,
/tmp
) by default. -
:cd – Change into the newly directory created using
ch
within the block, and then switch back to the previous directory. Only used when a block is given and the :kind is :directory. Default is false. See WARNING at the top of this class’s documentation! -
:noop – no-operation mode, pretends to do actions without actually creating or deleting temporary entries. Default is false. WARNING: See WARNING at the top of this class’s documentation!
-
:verbose – Print status messages about creating and deleting the temporary entries. Default is false.
-
:delete – Delete the temporary entries when exiting block. Default is true when given a block, false otherwise. If you don’t use a block, you’re responsible for deleting the entries yourself.
-
:tries – Number of tries to create a temporary entry, usually it’ll succeed on the first try. Default is 10.
-
:armor – Length of armor to append to the prefix. These are random characters padding out the temporary entry names to prevent them from using existing files. If you have a very short armor, you’re likely to get a collision and the algorithm will have to try again for the specified number of
tries
. -
:message_callback –
lambda
called when there’s a message, e.g.,lambda{|message| puts message}
, regardless of :verbose state. By default :messaging is nil and messages are printed to STDOUT only when :verbose is true. -
:message_prefix – String to put in front of messages, e.g., “# ”
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/tempster.rb', line 60 def self.tempster(opts={}, &block) kind = opts.delete(:kind) or raise ArgumentError.new("'kind' option not specified") prefix = opts.delete(:prefix) || opts.delete(:name) || DEFAULT_PREFIX suffix = opts.delete(:suffix) || nil dir = opts.delete(:dir) || Dir.tmpdir cd = opts.delete(:cd) || false noop = opts.delete(:noop) || false verbose = opts.delete(:verbose) || false delete = opts.delete(:delete) || block ? true : false tries = opts.delete(:tries) || 10 armor = opts.delete(:armor) || DEFAULT_ARMOR_LENGTH = opts.delete(:message_callback) || nil = opts.delete(:message_prefix) || "" mode = opts.delete(:mode) || \ case kind when :file DEFAULT_FILE_MODE when :directory DEFAULT_DIRECTORY_MODE else raise ArgumentError.new("unknown kind: #{kind}") end raise ArgumentError.new("can only use 'delete' option with block") if delete and not block raise ArgumentError.new("can only use 'cd' with directories and blocks") if cd and (not dir or not block) raise ArgumentError.new("unknown extra options: #{opts.inspect}") unless opts.empty? = Messager.new(verbose, , ) path = nil success = false for i in 1..tries begin name = prefix+"_"+_armor_string(armor) name << suffix if suffix path = File.join(dir, name) unless noop case kind when :file File.open(path, File::RDWR|File::CREAT|File::EXCL).close File.chmod(mode, path) when :directory Dir.mkdir(path, mode) else raise ArgumentError.new("unknown kind: #{kind}") end end = "mktempster --mode=0%o --kind=%s --dir=%s --prefix=%s" % [mode, kind, dir, prefix] << (" --suffix=%s" % suffix) if suffix << (" # => %s" % path) if block success = true break rescue Errno::EEXIST # Try again end end raise IOError.new("couldn't create temporary #{kind}, ") unless success if block previous = Dir.pwd if cd begin if cd Dir.chdir(path) unless noop .puts("pushd #{path}") end block.call(path) rescue Exception => e # Re-throw exception after cleaning up raise e ensure if cd Dir.chdir(previous) unless noop .puts("popd # => #{previous}") end if delete FileUtils.rm_rf(path) unless noop .puts("rm -rf #{path}") end end return true else return path end end |