automateit 0.70923

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data.tar.gz.sig +1 -0
  2. data/CHANGES.txt +100 -0
  3. data/Hoe.rake +35 -0
  4. data/Manifest.txt +111 -0
  5. data/README.txt +44 -0
  6. data/Rakefile +284 -0
  7. data/TESTING.txt +57 -0
  8. data/TODO.txt +26 -0
  9. data/TUTORIAL.txt +390 -0
  10. data/bin/ai +3 -0
  11. data/bin/aifield +82 -0
  12. data/bin/aitag +128 -0
  13. data/bin/automateit +117 -0
  14. data/docs/friendly_errors.txt +50 -0
  15. data/docs/previews.txt +86 -0
  16. data/env.sh +4 -0
  17. data/examples/basic/Rakefile +26 -0
  18. data/examples/basic/config/automateit_env.rb +16 -0
  19. data/examples/basic/config/fields.yml +3 -0
  20. data/examples/basic/config/tags.yml +13 -0
  21. data/examples/basic/dist/README.txt +9 -0
  22. data/examples/basic/dist/myapp_server.erb +30 -0
  23. data/examples/basic/install.log +15 -0
  24. data/examples/basic/lib/README.txt +10 -0
  25. data/examples/basic/recipes/README.txt +4 -0
  26. data/examples/basic/recipes/install.rb +53 -0
  27. data/examples/basic/recipes/uninstall.rb +6 -0
  28. data/gpl.txt +674 -0
  29. data/lib/automateit.rb +66 -0
  30. data/lib/automateit/account_manager.rb +106 -0
  31. data/lib/automateit/account_manager/linux.rb +171 -0
  32. data/lib/automateit/account_manager/passwd.rb +69 -0
  33. data/lib/automateit/account_manager/portable.rb +136 -0
  34. data/lib/automateit/address_manager.rb +165 -0
  35. data/lib/automateit/address_manager/linux.rb +80 -0
  36. data/lib/automateit/address_manager/portable.rb +37 -0
  37. data/lib/automateit/cli.rb +80 -0
  38. data/lib/automateit/common.rb +65 -0
  39. data/lib/automateit/constants.rb +33 -0
  40. data/lib/automateit/edit_manager.rb +292 -0
  41. data/lib/automateit/error.rb +10 -0
  42. data/lib/automateit/field_manager.rb +103 -0
  43. data/lib/automateit/interpreter.rb +641 -0
  44. data/lib/automateit/package_manager.rb +242 -0
  45. data/lib/automateit/package_manager/apt.rb +63 -0
  46. data/lib/automateit/package_manager/egg.rb +64 -0
  47. data/lib/automateit/package_manager/gem.rb +179 -0
  48. data/lib/automateit/package_manager/portage.rb +69 -0
  49. data/lib/automateit/package_manager/yum.rb +65 -0
  50. data/lib/automateit/platform_manager.rb +47 -0
  51. data/lib/automateit/platform_manager/darwin.rb +30 -0
  52. data/lib/automateit/platform_manager/debian.rb +26 -0
  53. data/lib/automateit/platform_manager/freebsd.rb +25 -0
  54. data/lib/automateit/platform_manager/gentoo.rb +26 -0
  55. data/lib/automateit/platform_manager/lsb.rb +40 -0
  56. data/lib/automateit/platform_manager/struct.rb +78 -0
  57. data/lib/automateit/platform_manager/uname.rb +29 -0
  58. data/lib/automateit/platform_manager/windows.rb +33 -0
  59. data/lib/automateit/plugin.rb +7 -0
  60. data/lib/automateit/plugin/base.rb +32 -0
  61. data/lib/automateit/plugin/driver.rb +218 -0
  62. data/lib/automateit/plugin/manager.rb +232 -0
  63. data/lib/automateit/project.rb +460 -0
  64. data/lib/automateit/root.rb +14 -0
  65. data/lib/automateit/service_manager.rb +79 -0
  66. data/lib/automateit/service_manager/chkconfig.rb +39 -0
  67. data/lib/automateit/service_manager/rc_update.rb +37 -0
  68. data/lib/automateit/service_manager/sysv.rb +126 -0
  69. data/lib/automateit/service_manager/update_rcd.rb +35 -0
  70. data/lib/automateit/shell_manager.rb +261 -0
  71. data/lib/automateit/shell_manager/base_link.rb +67 -0
  72. data/lib/automateit/shell_manager/link.rb +24 -0
  73. data/lib/automateit/shell_manager/portable.rb +421 -0
  74. data/lib/automateit/shell_manager/symlink.rb +32 -0
  75. data/lib/automateit/shell_manager/which.rb +25 -0
  76. data/lib/automateit/tag_manager.rb +63 -0
  77. data/lib/automateit/tag_manager/struct.rb +101 -0
  78. data/lib/automateit/tag_manager/tag_parser.rb +91 -0
  79. data/lib/automateit/tag_manager/yaml.rb +29 -0
  80. data/lib/automateit/template_manager.rb +55 -0
  81. data/lib/automateit/template_manager/base.rb +172 -0
  82. data/lib/automateit/template_manager/erb.rb +17 -0
  83. data/lib/ext/metaclass.rb +17 -0
  84. data/lib/ext/object.rb +18 -0
  85. data/lib/hashcache.rb +22 -0
  86. data/lib/helpful_erb.rb +63 -0
  87. data/lib/nested_error.rb +33 -0
  88. data/lib/queued_logger.rb +68 -0
  89. data/lib/tempster.rb +239 -0
  90. data/misc/index_gem_repository.rb +303 -0
  91. data/misc/setup_egg.rb +12 -0
  92. data/misc/setup_gem_dependencies.sh +7 -0
  93. data/misc/setup_rubygems.sh +21 -0
  94. data/misc/which.cmd +6 -0
  95. data/spec/extras/automateit_service_sysv_test +50 -0
  96. data/spec/extras/scratch.rb +15 -0
  97. data/spec/extras/simple_recipe.rb +8 -0
  98. data/spec/integration/account_manager_spec.rb +218 -0
  99. data/spec/integration/address_manager_linux_spec.rb +119 -0
  100. data/spec/integration/address_manager_portable_spec.rb +30 -0
  101. data/spec/integration/cli_spec.rb +215 -0
  102. data/spec/integration/examples_spec.rb +54 -0
  103. data/spec/integration/examples_spec_editor.rb +71 -0
  104. data/spec/integration/package_manager_spec.rb +104 -0
  105. data/spec/integration/platform_manager_spec.rb +69 -0
  106. data/spec/integration/service_manager_sysv_spec.rb +115 -0
  107. data/spec/integration/shell_manager_spec.rb +471 -0
  108. data/spec/integration/template_manager_erb_spec.rb +31 -0
  109. data/spec/spec_helper.rb +23 -0
  110. data/spec/unit/edit_manager_spec.rb +162 -0
  111. data/spec/unit/field_manager_spec.rb +79 -0
  112. data/spec/unit/hashcache_spec.rb +28 -0
  113. data/spec/unit/interpreter_spec.rb +98 -0
  114. data/spec/unit/platform_manager_spec.rb +44 -0
  115. data/spec/unit/plugins_spec.rb +253 -0
  116. data/spec/unit/tag_manager_spec.rb +189 -0
  117. data/spec/unit/template_manager_erb_spec.rb +137 -0
  118. metadata +249 -0
  119. 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
@@ -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
+
@@ -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
@@ -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
@@ -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
@@ -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