automateit 0.70923
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.
- data.tar.gz.sig +1 -0
- data/CHANGES.txt +100 -0
- data/Hoe.rake +35 -0
- data/Manifest.txt +111 -0
- data/README.txt +44 -0
- data/Rakefile +284 -0
- data/TESTING.txt +57 -0
- data/TODO.txt +26 -0
- data/TUTORIAL.txt +390 -0
- data/bin/ai +3 -0
- data/bin/aifield +82 -0
- data/bin/aitag +128 -0
- data/bin/automateit +117 -0
- data/docs/friendly_errors.txt +50 -0
- data/docs/previews.txt +86 -0
- data/env.sh +4 -0
- data/examples/basic/Rakefile +26 -0
- data/examples/basic/config/automateit_env.rb +16 -0
- data/examples/basic/config/fields.yml +3 -0
- data/examples/basic/config/tags.yml +13 -0
- data/examples/basic/dist/README.txt +9 -0
- data/examples/basic/dist/myapp_server.erb +30 -0
- data/examples/basic/install.log +15 -0
- data/examples/basic/lib/README.txt +10 -0
- data/examples/basic/recipes/README.txt +4 -0
- data/examples/basic/recipes/install.rb +53 -0
- data/examples/basic/recipes/uninstall.rb +6 -0
- data/gpl.txt +674 -0
- data/lib/automateit.rb +66 -0
- data/lib/automateit/account_manager.rb +106 -0
- data/lib/automateit/account_manager/linux.rb +171 -0
- data/lib/automateit/account_manager/passwd.rb +69 -0
- data/lib/automateit/account_manager/portable.rb +136 -0
- data/lib/automateit/address_manager.rb +165 -0
- data/lib/automateit/address_manager/linux.rb +80 -0
- data/lib/automateit/address_manager/portable.rb +37 -0
- data/lib/automateit/cli.rb +80 -0
- data/lib/automateit/common.rb +65 -0
- data/lib/automateit/constants.rb +33 -0
- data/lib/automateit/edit_manager.rb +292 -0
- data/lib/automateit/error.rb +10 -0
- data/lib/automateit/field_manager.rb +103 -0
- data/lib/automateit/interpreter.rb +641 -0
- data/lib/automateit/package_manager.rb +242 -0
- data/lib/automateit/package_manager/apt.rb +63 -0
- data/lib/automateit/package_manager/egg.rb +64 -0
- data/lib/automateit/package_manager/gem.rb +179 -0
- data/lib/automateit/package_manager/portage.rb +69 -0
- data/lib/automateit/package_manager/yum.rb +65 -0
- data/lib/automateit/platform_manager.rb +47 -0
- data/lib/automateit/platform_manager/darwin.rb +30 -0
- data/lib/automateit/platform_manager/debian.rb +26 -0
- data/lib/automateit/platform_manager/freebsd.rb +25 -0
- data/lib/automateit/platform_manager/gentoo.rb +26 -0
- data/lib/automateit/platform_manager/lsb.rb +40 -0
- data/lib/automateit/platform_manager/struct.rb +78 -0
- data/lib/automateit/platform_manager/uname.rb +29 -0
- data/lib/automateit/platform_manager/windows.rb +33 -0
- data/lib/automateit/plugin.rb +7 -0
- data/lib/automateit/plugin/base.rb +32 -0
- data/lib/automateit/plugin/driver.rb +218 -0
- data/lib/automateit/plugin/manager.rb +232 -0
- data/lib/automateit/project.rb +460 -0
- data/lib/automateit/root.rb +14 -0
- data/lib/automateit/service_manager.rb +79 -0
- data/lib/automateit/service_manager/chkconfig.rb +39 -0
- data/lib/automateit/service_manager/rc_update.rb +37 -0
- data/lib/automateit/service_manager/sysv.rb +126 -0
- data/lib/automateit/service_manager/update_rcd.rb +35 -0
- data/lib/automateit/shell_manager.rb +261 -0
- data/lib/automateit/shell_manager/base_link.rb +67 -0
- data/lib/automateit/shell_manager/link.rb +24 -0
- data/lib/automateit/shell_manager/portable.rb +421 -0
- data/lib/automateit/shell_manager/symlink.rb +32 -0
- data/lib/automateit/shell_manager/which.rb +25 -0
- data/lib/automateit/tag_manager.rb +63 -0
- data/lib/automateit/tag_manager/struct.rb +101 -0
- data/lib/automateit/tag_manager/tag_parser.rb +91 -0
- data/lib/automateit/tag_manager/yaml.rb +29 -0
- data/lib/automateit/template_manager.rb +55 -0
- data/lib/automateit/template_manager/base.rb +172 -0
- data/lib/automateit/template_manager/erb.rb +17 -0
- data/lib/ext/metaclass.rb +17 -0
- data/lib/ext/object.rb +18 -0
- data/lib/hashcache.rb +22 -0
- data/lib/helpful_erb.rb +63 -0
- data/lib/nested_error.rb +33 -0
- data/lib/queued_logger.rb +68 -0
- data/lib/tempster.rb +239 -0
- data/misc/index_gem_repository.rb +303 -0
- data/misc/setup_egg.rb +12 -0
- data/misc/setup_gem_dependencies.sh +7 -0
- data/misc/setup_rubygems.sh +21 -0
- data/misc/which.cmd +6 -0
- data/spec/extras/automateit_service_sysv_test +50 -0
- data/spec/extras/scratch.rb +15 -0
- data/spec/extras/simple_recipe.rb +8 -0
- data/spec/integration/account_manager_spec.rb +218 -0
- data/spec/integration/address_manager_linux_spec.rb +119 -0
- data/spec/integration/address_manager_portable_spec.rb +30 -0
- data/spec/integration/cli_spec.rb +215 -0
- data/spec/integration/examples_spec.rb +54 -0
- data/spec/integration/examples_spec_editor.rb +71 -0
- data/spec/integration/package_manager_spec.rb +104 -0
- data/spec/integration/platform_manager_spec.rb +69 -0
- data/spec/integration/service_manager_sysv_spec.rb +115 -0
- data/spec/integration/shell_manager_spec.rb +471 -0
- data/spec/integration/template_manager_erb_spec.rb +31 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/unit/edit_manager_spec.rb +162 -0
- data/spec/unit/field_manager_spec.rb +79 -0
- data/spec/unit/hashcache_spec.rb +28 -0
- data/spec/unit/interpreter_spec.rb +98 -0
- data/spec/unit/platform_manager_spec.rb +44 -0
- data/spec/unit/plugins_spec.rb +253 -0
- data/spec/unit/tag_manager_spec.rb +189 -0
- data/spec/unit/template_manager_erb_spec.rb +137 -0
- metadata +249 -0
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# == TemplateManager::ERB
|
|
2
|
+
#
|
|
3
|
+
# Renders ERB templates for TemplateManager.
|
|
4
|
+
class AutomateIt::TemplateManager::ERB < AutomateIt::TemplateManager::BaseDriver
|
|
5
|
+
depends_on :nothing
|
|
6
|
+
|
|
7
|
+
def suitability(method, *args) # :nodoc:
|
|
8
|
+
return 1
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# See documentation for TemplateManager#render
|
|
12
|
+
def render(*options)
|
|
13
|
+
return _render_helper(*options) do |o|
|
|
14
|
+
HelpfulERB.new(o[:text], o[:filename]).result(o[:binder])
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
|
2
|
+
|
|
3
|
+
class Object
|
|
4
|
+
# The hidden singleton lurks behind everyone
|
|
5
|
+
def metaclass; class << self; self; end; end
|
|
6
|
+
def meta_eval &blk; metaclass.instance_eval &blk; end
|
|
7
|
+
|
|
8
|
+
# Adds methods to a metaclass
|
|
9
|
+
def meta_def name, &blk
|
|
10
|
+
meta_eval { define_method name, &blk }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Defines an instance method within a class
|
|
14
|
+
def class_def name, &blk
|
|
15
|
+
class_eval { define_method name, &blk }
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/ext/object.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
class Object
|
|
2
|
+
# Lists methods unique to an instance.
|
|
3
|
+
def unique_methods
|
|
4
|
+
(public_methods - Object.methods).sort
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Lists methods unique to a class.
|
|
8
|
+
def self.unique_methods
|
|
9
|
+
(public_methods - Object.methods).sort
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Returns a list of arguments and an options hash. Source taken from RSpec.
|
|
13
|
+
def args_and_opts(*args)
|
|
14
|
+
options = Hash === args.last ? args.pop : {}
|
|
15
|
+
return args, options
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
data/lib/hashcache.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# A very simple cache. Works just like a Hash, but can optionally store values
|
|
2
|
+
# during the fetch process.
|
|
3
|
+
#
|
|
4
|
+
# Example:
|
|
5
|
+
# hc = HashCache.new
|
|
6
|
+
# hc.fetch("foo")
|
|
7
|
+
# => nil
|
|
8
|
+
# hc.fetch("foo"){:bar} # Block gets called because 'foo' is nil
|
|
9
|
+
# => :bar
|
|
10
|
+
# hc.fetch("foo"){raise "Block won't be called because 'foo' is cached"}
|
|
11
|
+
# => :bar
|
|
12
|
+
class HashCache < Hash
|
|
13
|
+
def fetch(key, &block)
|
|
14
|
+
if has_key?(key)
|
|
15
|
+
self[key]
|
|
16
|
+
elsif block
|
|
17
|
+
self[key] = block.call
|
|
18
|
+
else
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/helpful_erb.rb
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'erb'
|
|
2
|
+
require 'nested_error'
|
|
3
|
+
|
|
4
|
+
class HelpfulERB
|
|
5
|
+
class Error < ::NestedError; end
|
|
6
|
+
|
|
7
|
+
# ERB object
|
|
8
|
+
attr_accessor :erb
|
|
9
|
+
|
|
10
|
+
attr_accessor :lines_before
|
|
11
|
+
|
|
12
|
+
attr_accessor :lines_after
|
|
13
|
+
|
|
14
|
+
# Template filename
|
|
15
|
+
attr_accessor :filename
|
|
16
|
+
|
|
17
|
+
def initialize(text, filename=nil, opts={})
|
|
18
|
+
@text = text
|
|
19
|
+
@filename = filename
|
|
20
|
+
@lines_before = opts[:before] || 5
|
|
21
|
+
@lines_after = opts[:before] || 1
|
|
22
|
+
|
|
23
|
+
@erb = ::ERB.new(@text, nil, '-')
|
|
24
|
+
@erb.filename = @filename if @filename
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def result(binder=nil)
|
|
28
|
+
begin
|
|
29
|
+
return @erb.result(binder)
|
|
30
|
+
rescue Exception => e
|
|
31
|
+
stack = caller 0
|
|
32
|
+
for i in 0..e.backtrace.size
|
|
33
|
+
l = e.backtrace[i]
|
|
34
|
+
#puts "%s %s" % [i, l];
|
|
35
|
+
break if l =~ /^([^:]+):(\d+):in `(render|result)'$/
|
|
36
|
+
end
|
|
37
|
+
template = $1
|
|
38
|
+
line_number = $2.to_i
|
|
39
|
+
raise Exception.new("Caught ERB error but couldn't find line number in backtrace:\n#{e.backtrace.join("\n")}") unless line_number
|
|
40
|
+
|
|
41
|
+
lines = @text.split(/\n/)
|
|
42
|
+
|
|
43
|
+
min = line_number - @lines_before
|
|
44
|
+
min = 0 if min < 0
|
|
45
|
+
|
|
46
|
+
max = line_number + @lines_after
|
|
47
|
+
max = lines.size if max > lines.size
|
|
48
|
+
|
|
49
|
+
width = max.to_s.size
|
|
50
|
+
|
|
51
|
+
msg = "Problem with template '#{template}' at line #{line_number}:\n"
|
|
52
|
+
for i in min..max
|
|
53
|
+
n = i+1
|
|
54
|
+
marker = n == line_number ? "*" : ""
|
|
55
|
+
msg << "\n%2s %#{width}i %s" % [marker, n, lines[i]]
|
|
56
|
+
end
|
|
57
|
+
msg << "\n\n(#{e.exception.class}) #{e.message}"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
raise NestedError.new(msg, e)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
data/lib/nested_error.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# == NestedError
|
|
2
|
+
#
|
|
3
|
+
# An exception class that records the cause of another error. Useful when you
|
|
4
|
+
# need to raise a general kind of error, yet still be able to determine the
|
|
5
|
+
# underlying cause.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
#
|
|
9
|
+
# class MyGeneralError < NestedError; end
|
|
10
|
+
#
|
|
11
|
+
# begin
|
|
12
|
+
# begin
|
|
13
|
+
# # Cause a specific error
|
|
14
|
+
# 1/0 # Divide by zero error
|
|
15
|
+
# rescue Exception => e
|
|
16
|
+
# # Wrap the specific error in a general, nested error
|
|
17
|
+
# raise MyGeneralError("Something bad happened!", e)
|
|
18
|
+
# end
|
|
19
|
+
# rescue MyGeneralError => e
|
|
20
|
+
# # Intercept the nested error and inspect the cause
|
|
21
|
+
# puts e.message # => "Something bad happened!"
|
|
22
|
+
# puts e.cause.message # => "divided by 0"
|
|
23
|
+
# end
|
|
24
|
+
class NestedError < StandardError
|
|
25
|
+
attr_accessor :cause
|
|
26
|
+
|
|
27
|
+
# Create a NestedObject with a +message+ String and a +cause+ Exception.
|
|
28
|
+
def initialize(message, cause)
|
|
29
|
+
self.cause = cause
|
|
30
|
+
super(message)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
|
|
3
|
+
class QueuedLogger < Logger
|
|
4
|
+
def initialize(*args)
|
|
5
|
+
super(*args)
|
|
6
|
+
@queue = []
|
|
7
|
+
@emitted = false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def process_queue
|
|
11
|
+
if queued?
|
|
12
|
+
while true
|
|
13
|
+
entry = @queue.shift or break
|
|
14
|
+
severity, message = entry
|
|
15
|
+
raw_method = "#{severity}_without_queue"
|
|
16
|
+
severity_i = self.class.send(:const_get, severity.to_s.upcase)
|
|
17
|
+
send(raw_method, message)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def enqueue(level, message)
|
|
23
|
+
@queue << [level, message]
|
|
24
|
+
@emitted = false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def dequeue(level=nil, message=nil)
|
|
28
|
+
if queued?
|
|
29
|
+
@queue.clear
|
|
30
|
+
elsif level and message
|
|
31
|
+
send("%s_without_queue"%level, message) if @emitted
|
|
32
|
+
end
|
|
33
|
+
@emitted = false
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def queued?
|
|
37
|
+
! @queue.empty?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
for level in %w(debug info warn error fatal) do
|
|
41
|
+
class_eval <<-EOB
|
|
42
|
+
def #{level}_with_queue(*args)
|
|
43
|
+
severity = self.class.send(:const_get, "#{level.upcase}")
|
|
44
|
+
process_queue if severity >= self.level
|
|
45
|
+
@emitted = true
|
|
46
|
+
#{level}_without_queue(*args)
|
|
47
|
+
end
|
|
48
|
+
alias_method_chain :#{level}, :queue
|
|
49
|
+
EOB
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if __FILE__ == $0
|
|
55
|
+
# TODO QueuedLogger -- write a spec
|
|
56
|
+
|
|
57
|
+
q = QueuedLogger.new($stdout)
|
|
58
|
+
q.level = Logger::INFO
|
|
59
|
+
q.info("first message")
|
|
60
|
+
q.enqueue(:info, "queued message that'll be pushed")
|
|
61
|
+
q.info("second message, which pushed out queued message")
|
|
62
|
+
q.enqueue(:error, "ERROR: queued message that'll be discarded")
|
|
63
|
+
q.debug("ERROR: message that'll be discarded and won't push queue")
|
|
64
|
+
q.dequeue(:error, "ERROR: dequeue message that'll be discarded")
|
|
65
|
+
q.enqueue(:info, "queued message that'll be pushed")
|
|
66
|
+
q.info("message that'll push out the queue and dequeue messages")
|
|
67
|
+
q.dequeue(:info, "dequeue message that'll be pushed")
|
|
68
|
+
end
|
data/lib/tempster.rb
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
require 'tmpdir'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
# == Tempster
|
|
5
|
+
#
|
|
6
|
+
# Tempster is a pure-Ruby library for creating temporary files and directories.
|
|
7
|
+
# Unlike other tools, it can create both temporary files and directories, and
|
|
8
|
+
# is designed to be secure, thread-safe, easy-to-use, powerful thanks to
|
|
9
|
+
# user-configurable options, and user-friendly thanks to good defaults so you
|
|
10
|
+
# don't need to provide any arguments.
|
|
11
|
+
#
|
|
12
|
+
# Why write another library for this? The Tempfile standard library provides no
|
|
13
|
+
# way to create temporary directories and always deletes the files it creates,
|
|
14
|
+
# even if you want to keep them. The MkTemp gem is insecure and fails on
|
|
15
|
+
# collisions. Linux "mktemp" works fine but is platform-specific. Therefore, I
|
|
16
|
+
# had to write something.
|
|
17
|
+
#
|
|
18
|
+
# === WARNING: Using 'cd' and :noop together can be dangerous!
|
|
19
|
+
#
|
|
20
|
+
# Tempster will only *pretend* to make directories in :noop (no-operation)
|
|
21
|
+
# mode. In :noop mode, it will also only *pretend* to change into the directory
|
|
22
|
+
# when using :cd or +mktempdircd+.
|
|
23
|
+
#
|
|
24
|
+
# This can be *disastrous* if you're executing non-AutomateIt commands (e.g.
|
|
25
|
+
# +system+) that use *relative* *paths* and expect to be run inside the
|
|
26
|
+
# newly-created temporary directory because the +chdir+ didn't actually happen.
|
|
27
|
+
#
|
|
28
|
+
# Read previews.txt[link:files/docs/previews_txt.html] for instructions on how
|
|
29
|
+
# to write code that can be safely previewed.
|
|
30
|
+
#
|
|
31
|
+
# == Credits
|
|
32
|
+
# * Random string generator taken from
|
|
33
|
+
# http://pleac.sourceforge.net/pleac_ruby/numbers.html
|
|
34
|
+
class Tempster
|
|
35
|
+
DEFAULT_NAME = "tempster"
|
|
36
|
+
DEFAULT_FILE_MODE = 0600
|
|
37
|
+
DEFAULT_DIRECTORY_MODE = 0700
|
|
38
|
+
DEFAULT_ARMOR_LENGTH = 10
|
|
39
|
+
ARMOR_CHARACTERS = ["A".."Z","a".."z","0".."9"].collect{|r| r.to_a}.join
|
|
40
|
+
|
|
41
|
+
# Options:
|
|
42
|
+
# * :name -- Name prefix to usse, defaults to "tempster".
|
|
43
|
+
# * :kind -- Create a :file or :directory, required.
|
|
44
|
+
# * :dir -- Base directory to create temporary entries in, uses system-wide temporary directory (e.g., <tt>/tmp</tt>) by default.
|
|
45
|
+
# * :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!
|
|
46
|
+
# * :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!
|
|
47
|
+
# * :verbose -- Print status messages about creating and deleting the temporary entries. Default is false.
|
|
48
|
+
# * :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.
|
|
49
|
+
# * :tries -- Number of tries to create a temporary entry, usually it'll succeed on the first try. Default is 10.
|
|
50
|
+
# * :armor -- Length of armor to add to the name. 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+.
|
|
51
|
+
# * :message_callback -- +lambda+ called when there's a message, e.g., <tt>lambda{|message| puts message}</tt>, regardless of :verbose state. By default :messaging is nil and messages are printed to STDOUT only when :verbose is true.
|
|
52
|
+
# * :message_prefix -- String to put in front of messages, e.g., "# "
|
|
53
|
+
def self._tempster(opts={}, &block)
|
|
54
|
+
name = opts.delete(:name) || DEFAULT_NAME
|
|
55
|
+
kind = opts.delete(:kind) or raise ArgumentError.new("'kind' option not specified")
|
|
56
|
+
dir = opts.delete(:dir) || Dir.tmpdir
|
|
57
|
+
cd = opts.delete(:cd) || false
|
|
58
|
+
noop = opts.delete(:noop) || false
|
|
59
|
+
verbose = opts.delete(:verbose) || false
|
|
60
|
+
delete = opts.delete(:delete) || block ? true : false
|
|
61
|
+
tries = opts.delete(:tries) || 10
|
|
62
|
+
armor = opts.delete(:armor) || DEFAULT_ARMOR_LENGTH
|
|
63
|
+
message_callback = opts.delete(:message_callback) || nil
|
|
64
|
+
message_prefix = opts.delete(:message_prefix) || ""
|
|
65
|
+
mode = opts.delete(:mode) || \
|
|
66
|
+
case kind
|
|
67
|
+
when :file
|
|
68
|
+
DEFAULT_FILE_MODE
|
|
69
|
+
when :directory
|
|
70
|
+
DEFAULT_DIRECTORY_MODE
|
|
71
|
+
else
|
|
72
|
+
raise ArgumentError.new("unknown kind: #{kind}")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
raise ArgumentError.new("can only use 'delete' option with block") if delete and not block
|
|
76
|
+
raise ArgumentError.new("can only use 'cd' with directories and blocks") if cd and (not dir or not block)
|
|
77
|
+
raise ArgumentError.new("unknown extra options: #{opts.inspect}") unless opts.empty?
|
|
78
|
+
|
|
79
|
+
messager = Messager.new(verbose, message_callback, message_prefix)
|
|
80
|
+
|
|
81
|
+
path = nil
|
|
82
|
+
success = false
|
|
83
|
+
for i in 1..tries
|
|
84
|
+
begin
|
|
85
|
+
path = File.join(dir, name+"_"+_armor_string(armor))
|
|
86
|
+
unless noop
|
|
87
|
+
case kind
|
|
88
|
+
when :file
|
|
89
|
+
File.open(path, File::RDWR|File::CREAT|File::EXCL).close
|
|
90
|
+
File.chmod(mode, path)
|
|
91
|
+
when :directory
|
|
92
|
+
Dir.mkdir(path, mode)
|
|
93
|
+
else
|
|
94
|
+
raise ArgumentError.new("unknown kind: #{kind}")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
# XXX Should we pretend that it's mktemp? Or give users something more useful?
|
|
98
|
+
# messager.puts("mktemp -m 0%o%s -p %s %s # => %s" % [mode, kind == :directory ? ' -d' : '', dir, name, path])
|
|
99
|
+
if block
|
|
100
|
+
messager.puts("mktempster --mode=0%o --kind=%s --dir=%s --name=%s" % [mode, kind, dir, name])
|
|
101
|
+
else
|
|
102
|
+
messager.puts("mktempster --mode=0%o --kind=%s --dir=%s --name=%s # => %s" % [mode, kind, dir, name, path])
|
|
103
|
+
end
|
|
104
|
+
success = true
|
|
105
|
+
break
|
|
106
|
+
rescue Errno::EEXIST
|
|
107
|
+
# Try again
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
raise IOError.new("couldn't create temporary #{kind}, ") unless success
|
|
111
|
+
if block
|
|
112
|
+
previous = Dir.pwd if cd
|
|
113
|
+
begin
|
|
114
|
+
if cd
|
|
115
|
+
Dir.chdir(path) unless noop
|
|
116
|
+
messager.puts("pushd #{path}")
|
|
117
|
+
end
|
|
118
|
+
block.call(path)
|
|
119
|
+
rescue Exception => e
|
|
120
|
+
# Re-throw exception after cleaning up
|
|
121
|
+
raise e
|
|
122
|
+
ensure
|
|
123
|
+
if cd
|
|
124
|
+
Dir.chdir(previous) unless noop
|
|
125
|
+
messager.puts("popd # => #{previous}")
|
|
126
|
+
end
|
|
127
|
+
if delete
|
|
128
|
+
FileUtils.rm_rf(path) unless noop
|
|
129
|
+
messager.puts("rm -rf #{path}")
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
return true
|
|
133
|
+
else
|
|
134
|
+
return path
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Returns a string of random characters.
|
|
139
|
+
def self._armor_string(length=DEFAULT_ARMOR_LENGTH)
|
|
140
|
+
(1..length).collect{ARMOR_CHARACTERS[rand(ARMOR_CHARACTERS.size)]}.pack("C*")
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Creates a temporary file.
|
|
144
|
+
def self.mktemp(opts={}, &block)
|
|
145
|
+
_tempster({:kind => :file}.merge(opts), &block)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Creates a temporary directory.
|
|
149
|
+
#
|
|
150
|
+
# *WARNING*: See WARNING text at the top of this class's documentation!
|
|
151
|
+
def self.mktempdir(opts={}, &block)
|
|
152
|
+
_tempster({:kind => :directory}.merge(opts), &block)
|
|
153
|
+
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Creates a temporary directory and changes into it using +chdir+. This is a
|
|
157
|
+
# shortcut for using +mktempdir+ with the <tt>:cd => true</tt> option.
|
|
158
|
+
#
|
|
159
|
+
# *WARNING*: See WARNING text at the top of this class's documentation!
|
|
160
|
+
def self.mktempdircd(opts={}, &block)
|
|
161
|
+
_tempster({:kind => :directory, :cd => true}.merge(opts), &block)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
class Messager
|
|
165
|
+
def initialize(verbose, callback=nil, prefix="")
|
|
166
|
+
@verbose = verbose
|
|
167
|
+
@callback = callback
|
|
168
|
+
@prefix = prefix
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def puts(message)
|
|
172
|
+
if @callback
|
|
173
|
+
@callback.call(@prefix+message)
|
|
174
|
+
else
|
|
175
|
+
if @verbose
|
|
176
|
+
STDOUT.puts @prefix+message
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
if __FILE__ == $0
|
|
184
|
+
# TODO Tempster -- write a spec
|
|
185
|
+
|
|
186
|
+
# Show a temp file created
|
|
187
|
+
x = Tempster.mktemp(:verbose => true)
|
|
188
|
+
File.stat(x)
|
|
189
|
+
File.unlink(x)
|
|
190
|
+
|
|
191
|
+
# Show a temp directory created
|
|
192
|
+
x = Tempster.mktempdir(:verbose => true)
|
|
193
|
+
File.directory?(x)
|
|
194
|
+
FileUtils.rm_r(x)
|
|
195
|
+
|
|
196
|
+
# Show a temp file created and removed with block
|
|
197
|
+
path = nil
|
|
198
|
+
Tempster.mktemp(:verbose => true) do |file|
|
|
199
|
+
path = file
|
|
200
|
+
puts file
|
|
201
|
+
end
|
|
202
|
+
begin
|
|
203
|
+
File.unlink(path)
|
|
204
|
+
raise "temporary file wasn't deleted when block ended: #{path}"
|
|
205
|
+
rescue Errno::ENOENT
|
|
206
|
+
# Expect the error
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Show temp directory created and removed with block
|
|
210
|
+
path = nil
|
|
211
|
+
Tempster.mktempdir(:verbose => true) do |dir|
|
|
212
|
+
puts dir
|
|
213
|
+
path = dir
|
|
214
|
+
puts File.directory?(path)
|
|
215
|
+
end
|
|
216
|
+
puts File.directory?(path)
|
|
217
|
+
|
|
218
|
+
# Show temp directory created and removed with block and cd
|
|
219
|
+
path = nil
|
|
220
|
+
Tempster.mktempdircd(:verbose => true) do |dir|
|
|
221
|
+
path = dir
|
|
222
|
+
puts "block's arg: "+dir
|
|
223
|
+
puts "block's pwd: "+Dir.pwd
|
|
224
|
+
puts "block's dir exists?: %s" % File.directory?(path)
|
|
225
|
+
end
|
|
226
|
+
puts "after dir exists?: %s" % File.directory?(path)
|
|
227
|
+
puts "after pwd: "+Dir.pwd
|
|
228
|
+
|
|
229
|
+
# Same with message callback
|
|
230
|
+
path = nil
|
|
231
|
+
Tempster.mktempdircd(:message_callback => lambda{|message| puts "$$$ "+message}) do |dir|
|
|
232
|
+
path = dir
|
|
233
|
+
puts "block's arg: "+dir
|
|
234
|
+
puts "block's pwd: "+Dir.pwd
|
|
235
|
+
puts "block's dir exists?: %s" % File.directory?(path)
|
|
236
|
+
end
|
|
237
|
+
puts "after dir exists?: %s" % File.directory?(path)
|
|
238
|
+
puts "after pwd: "+Dir.pwd
|
|
239
|
+
end
|