automate-it 0.9.0

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.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.hgignore +10 -0
  4. data/.loadpath +5 -0
  5. data/.project +17 -0
  6. data/CHANGES.txt +314 -0
  7. data/Hoe.rake +40 -0
  8. data/Manifest.txt +164 -0
  9. data/README.txt +40 -0
  10. data/Rakefile +256 -0
  11. data/TESTING.txt +57 -0
  12. data/TODO.txt +50 -0
  13. data/TUTORIAL.txt +391 -0
  14. data/automate-it.gemspec +25 -0
  15. data/bin/ai +3 -0
  16. data/bin/aifield +75 -0
  17. data/bin/aissh +93 -0
  18. data/bin/aitag +134 -0
  19. data/bin/automateit +133 -0
  20. data/docs/friendly_errors.txt +50 -0
  21. data/docs/previews.txt +86 -0
  22. data/examples/basic/Rakefile +26 -0
  23. data/examples/basic/config/automateit_env.rb +16 -0
  24. data/examples/basic/config/fields.yml +3 -0
  25. data/examples/basic/config/tags.yml +7 -0
  26. data/examples/basic/dist/README.txt +9 -0
  27. data/examples/basic/dist/myapp_server.erb +30 -0
  28. data/examples/basic/install.log +15 -0
  29. data/examples/basic/lib/README.txt +10 -0
  30. data/examples/basic/recipes/README.txt +4 -0
  31. data/examples/basic/recipes/install.rb +61 -0
  32. data/examples/basic/recipes/uninstall.rb +6 -0
  33. data/gpl.txt +674 -0
  34. data/helpers/cpan_wrapper.pl +220 -0
  35. data/helpers/which.cmd +7 -0
  36. data/lib/automateit.rb +55 -0
  37. data/lib/automateit/account_manager.rb +114 -0
  38. data/lib/automateit/account_manager/base.rb +138 -0
  39. data/lib/automateit/account_manager/etc.rb +128 -0
  40. data/lib/automateit/account_manager/nscd.rb +33 -0
  41. data/lib/automateit/account_manager/passwd_expect.rb +40 -0
  42. data/lib/automateit/account_manager/passwd_pty.rb +69 -0
  43. data/lib/automateit/account_manager/posix.rb +138 -0
  44. data/lib/automateit/address_manager.rb +88 -0
  45. data/lib/automateit/address_manager/base.rb +171 -0
  46. data/lib/automateit/address_manager/bsd.rb +28 -0
  47. data/lib/automateit/address_manager/freebsd.rb +59 -0
  48. data/lib/automateit/address_manager/linux.rb +42 -0
  49. data/lib/automateit/address_manager/openbsd.rb +66 -0
  50. data/lib/automateit/address_manager/portable.rb +37 -0
  51. data/lib/automateit/address_manager/sunos.rb +34 -0
  52. data/lib/automateit/cli.rb +85 -0
  53. data/lib/automateit/common.rb +65 -0
  54. data/lib/automateit/constants.rb +35 -0
  55. data/lib/automateit/download_manager.rb +48 -0
  56. data/lib/automateit/edit_manager.rb +321 -0
  57. data/lib/automateit/error.rb +10 -0
  58. data/lib/automateit/field_manager.rb +103 -0
  59. data/lib/automateit/interpreter.rb +631 -0
  60. data/lib/automateit/package_manager.rb +257 -0
  61. data/lib/automateit/package_manager/apt.rb +27 -0
  62. data/lib/automateit/package_manager/cpan.rb +101 -0
  63. data/lib/automateit/package_manager/dpkg.rb +54 -0
  64. data/lib/automateit/package_manager/egg.rb +64 -0
  65. data/lib/automateit/package_manager/gem.rb +201 -0
  66. data/lib/automateit/package_manager/pear.rb +95 -0
  67. data/lib/automateit/package_manager/pecl.rb +80 -0
  68. data/lib/automateit/package_manager/portage.rb +69 -0
  69. data/lib/automateit/package_manager/yum.rb +65 -0
  70. data/lib/automateit/platform_manager.rb +49 -0
  71. data/lib/automateit/platform_manager/darwin.rb +30 -0
  72. data/lib/automateit/platform_manager/debian.rb +26 -0
  73. data/lib/automateit/platform_manager/freebsd.rb +29 -0
  74. data/lib/automateit/platform_manager/gentoo.rb +26 -0
  75. data/lib/automateit/platform_manager/lsb.rb +44 -0
  76. data/lib/automateit/platform_manager/openbsd.rb +28 -0
  77. data/lib/automateit/platform_manager/struct.rb +80 -0
  78. data/lib/automateit/platform_manager/sunos.rb +39 -0
  79. data/lib/automateit/platform_manager/uname.rb +29 -0
  80. data/lib/automateit/platform_manager/windows.rb +40 -0
  81. data/lib/automateit/plugin.rb +7 -0
  82. data/lib/automateit/plugin/base.rb +32 -0
  83. data/lib/automateit/plugin/driver.rb +256 -0
  84. data/lib/automateit/plugin/manager.rb +224 -0
  85. data/lib/automateit/project.rb +493 -0
  86. data/lib/automateit/root.rb +17 -0
  87. data/lib/automateit/service_manager.rb +93 -0
  88. data/lib/automateit/service_manager/chkconfig.rb +39 -0
  89. data/lib/automateit/service_manager/rc_update.rb +37 -0
  90. data/lib/automateit/service_manager/sysv.rb +139 -0
  91. data/lib/automateit/service_manager/update_rcd.rb +35 -0
  92. data/lib/automateit/shell_manager.rb +316 -0
  93. data/lib/automateit/shell_manager/base_link.rb +67 -0
  94. data/lib/automateit/shell_manager/link.rb +24 -0
  95. data/lib/automateit/shell_manager/portable.rb +523 -0
  96. data/lib/automateit/shell_manager/symlink.rb +32 -0
  97. data/lib/automateit/shell_manager/which_base.rb +30 -0
  98. data/lib/automateit/shell_manager/which_unix.rb +16 -0
  99. data/lib/automateit/shell_manager/which_windows.rb +20 -0
  100. data/lib/automateit/tag_manager.rb +127 -0
  101. data/lib/automateit/tag_manager/struct.rb +121 -0
  102. data/lib/automateit/tag_manager/tag_parser.rb +93 -0
  103. data/lib/automateit/tag_manager/yaml.rb +29 -0
  104. data/lib/automateit/template_manager.rb +56 -0
  105. data/lib/automateit/template_manager/base.rb +181 -0
  106. data/lib/automateit/template_manager/erb.rb +17 -0
  107. data/lib/ext/metaclass.rb +17 -0
  108. data/lib/ext/object.rb +18 -0
  109. data/lib/ext/shell_escape.rb +7 -0
  110. data/lib/hashcache.rb +22 -0
  111. data/lib/helpful_erb.rb +63 -0
  112. data/lib/inactive_support.rb +53 -0
  113. data/lib/inactive_support/basic_object.rb +6 -0
  114. data/lib/inactive_support/clean_logger.rb +127 -0
  115. data/lib/inactive_support/core_ext/array/extract_options.rb +19 -0
  116. data/lib/inactive_support/core_ext/blank.rb +50 -0
  117. data/lib/inactive_support/core_ext/class/attribute_accessors.rb +48 -0
  118. data/lib/inactive_support/core_ext/class/inheritable_attributes.rb +140 -0
  119. data/lib/inactive_support/core_ext/enumerable.rb +63 -0
  120. data/lib/inactive_support/core_ext/hash/keys.rb +54 -0
  121. data/lib/inactive_support/core_ext/module/aliasing.rb +70 -0
  122. data/lib/inactive_support/core_ext/numeric/time.rb +91 -0
  123. data/lib/inactive_support/core_ext/string/inflections.rb +153 -0
  124. data/lib/inactive_support/core_ext/symbol.rb +14 -0
  125. data/lib/inactive_support/core_ext/time/conversions.rb +96 -0
  126. data/lib/inactive_support/duration.rb +96 -0
  127. data/lib/inactive_support/inflections.rb +53 -0
  128. data/lib/inactive_support/inflector.rb +282 -0
  129. data/lib/nested_error.rb +33 -0
  130. data/lib/nitpick.rb +33 -0
  131. data/lib/queued_logger.rb +68 -0
  132. data/lib/tempster.rb +250 -0
  133. data/misc/index_gem_repository.rb +304 -0
  134. data/misc/setup_egg.rb +12 -0
  135. data/misc/setup_gem_dependencies.sh +6 -0
  136. data/misc/setup_rubygems.sh +21 -0
  137. metadata +279 -0
@@ -0,0 +1,65 @@
1
+ module AutomateIt
2
+ # == Common
3
+ #
4
+ # Common is the abstract class that most AutomateIt classes inherit from.
5
+ class Common
6
+ include AutomateIt::Constants
7
+
8
+ # Interpreter instance for this class.
9
+ attr_accessor :interpreter
10
+
11
+ # Calls #setup with +options+ for processing.
12
+ def initialize(options={})
13
+ setup(options)
14
+ end
15
+
16
+ # Setup the class. Options:
17
+ # * :interpreter - Set the Interpreter.
18
+ def setup(options={})
19
+ @interpreter = options[:interpreter] if options[:interpreter]
20
+ end
21
+
22
+ #---[ Interpreter aliases ]---------------------------------------------
23
+
24
+ unless defined?(AutomateIt::Interpreter) and AutomateIt::Interpreter === self
25
+ # See Interpreter#log
26
+ def log() @interpreter.log end
27
+
28
+ # See Interpreter#noop=
29
+ def noop=(value) @interpreter.noop=(value) end
30
+
31
+ # See Interpreter#noop
32
+ def noop(value) @interpreter.noop(value) end
33
+
34
+ # See Interpreter#noop?
35
+ def noop?() @interpreter.noop?() end
36
+
37
+ # See Interpreter#writing=
38
+ def writing=(value) @interpreter.writing=(value) end
39
+
40
+ # See Interpreter#writing
41
+ def writing(value) @interpreter.writing(value) end
42
+
43
+ # See Interpreter#writing?
44
+ def writing?() @interpreter.writing?() end
45
+
46
+ # See Interpreter#preview?
47
+ def preview?() @interpreter.preview?() end
48
+
49
+ # See Interpreter#preview
50
+ def preview(value=nil) @interpreter.preview(value) end
51
+
52
+ # See Interpreter#preview=
53
+ def preview=(value) @interpreter.preview=(value) end
54
+
55
+ # See Interpreter#preview_for
56
+ def preview_for(message, &block) @interpreter.preview_for(message, &block) end
57
+
58
+ # See Interpreter#superuser?
59
+ def superuser?() @interpreter.superuser? end
60
+
61
+ # See Interpreter#nitpick
62
+ def nitpick(value=nil) @interpreter.nitpick(value) end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,35 @@
1
+ module AutomateIt # :nodoc:
2
+ # === AutomateIt::Constants
3
+ #
4
+ # Various constants.
5
+ module AutomateIt::Constants
6
+ INSTALL_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
7
+
8
+ HELPERS_DIR = File.join(INSTALL_DIR, "helpers")
9
+
10
+ # Output prefix for command execution, e.g., "** ls -la"
11
+ PEXEC = "** "
12
+
13
+ # Output prefix for notes, e.g., "=> Something happened"
14
+ PNOTE = "=> "
15
+
16
+ # Output prefix for errors, e.g., "!! Something bad happened"
17
+ PERROR = "!! "
18
+
19
+ # Boilerplate to add to tops of generated files, warning people not to edit
20
+ # them directly.
21
+ WARNING_BOILERPLATE = <<-HERE
22
+ # +---------------------------------------------------------------------+
23
+ # | WARNING: Do NOT edit this file directly or your changes will be |
24
+ # | lost. If you need to change this file, you must incorporate your |
25
+ # | changes into the AutomateIt project that created it. If you don't |
26
+ # | know what this means, please talk to your system administrator. |
27
+ # +---------------------------------------------------------------------+
28
+ #
29
+ HERE
30
+ end
31
+
32
+ # Inject constants back into top, providing AutomateIt::VERSION and such.
33
+ module_eval { include Constants }
34
+ end
35
+
@@ -0,0 +1,48 @@
1
+ # == DownloadManager
2
+ #
3
+ # The DownloadManager provides a way of downloading files.
4
+ module AutomateIt
5
+ class DownloadManager < Plugin::Manager
6
+ alias_methods :download
7
+
8
+ # Downloads the +source+ document.
9
+ #
10
+ # Options:
11
+ # * :to -- Saves source to this filename or directory. Defaults to current directory.
12
+ def download(*arguments) dispatch(*arguments) end
13
+
14
+ # == DownloadManager::BaseDriver
15
+ #
16
+ # Base class for all DownloadManager drivers.
17
+ class BaseDriver < Plugin::Driver
18
+ end
19
+
20
+ # == DownloadManager::OpenURI
21
+ #
22
+ # A DownloadManager driver using the OpenURI module for handling HTTP and FTP transfers.
23
+ class OpenURI < BaseDriver
24
+ depends_on :libraries => %w(open-uri)
25
+
26
+ def suitability(method, *args) # :nodoc:
27
+ return available? ? 1 : 0
28
+ end
29
+
30
+ # See DownloadManager#download
31
+ def download(*arguments)
32
+ args, opts = args_and_opts(*arguments)
33
+ source = args[0] or raise ArgumentError.new("No source specified")
34
+ target = args[1] || opts[:to] || File.basename(source)
35
+ target = File.join(target, File.basename(source)) if File.directory?(target)
36
+ log.info(PNOTE+"Downloading #{target}")
37
+ if writing?
38
+ open(target, "w+") do |writer|
39
+ open(source) do |reader|
40
+ writer.write(reader.read)
41
+ end
42
+ end
43
+ end
44
+ return writing?
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,321 @@
1
+ # == EditManager
2
+ #
3
+ # The EditManager provides a way of editing files and strings
4
+ # programmatically.
5
+ #
6
+ # See documentation for EditManager::EditSession.
7
+ class AutomateIt::EditManager < AutomateIt::Plugin::Manager
8
+ alias_methods :edit
9
+
10
+ # Creates an editing session. See documentation for EditManager::EditSession.
11
+ def edit(*opts, &block) dispatch(*opts, &block) end
12
+ end
13
+
14
+ # == EditManager::BaseDriver
15
+ #
16
+ # Base class for all EditManager drivers.
17
+ class AutomateIt::EditManager::BaseDriver < AutomateIt::Plugin::Driver
18
+ end
19
+
20
+ # == EditManager::Simple
21
+ #
22
+ # Provides a way to edit files and strings.
23
+ #
24
+ # See documentation for EditSession.
25
+ class AutomateIt::EditManager::Simple < AutomateIt::EditManager::BaseDriver
26
+ depends_on :nothing
27
+
28
+ def suitability(method, *args) # :nodoc:
29
+ 1
30
+ end
31
+
32
+ # Creates an editing session. See documentation for EditSession#edit.
33
+ def edit(*opts, &block)
34
+ AutomateIt::EditManager::EditSession.new(:interpreter => @interpreter).edit(*opts, &block)
35
+ end
36
+ end # class Base
37
+
38
+ # == EditSession
39
+ #
40
+ # EditSession provides a way to edit files and strings.
41
+ #
42
+ # For example, here's how to edit a string from the Interpreter:
43
+ #
44
+ # edit(:text => "# hello") do
45
+ # uncomment "llo"
46
+ # append "world"
47
+ # end
48
+ # # => "hello\nworld"
49
+ #
50
+ # The above example edits a text string containing "# hello". The editing
51
+ # session uncomments the line containing "llo" and then appends a line with the
52
+ # word "world". The edited result is returned, containing two lines: "hello"
53
+ # and "world".
54
+ #
55
+ # The edit session only makes changes if they're needed. In the above example,
56
+ # once the "hello" line is uncommented, the "uncomment" command won't do
57
+ # anything. Similarly, once the word "world" has been appended, it won't be
58
+ # appended again. So if you re-edit the resulting string, it won't be changed
59
+ # because it's already in the desired state.
60
+ #
61
+ # This approach simplifies editing because you only need to specify the
62
+ # commands that are needed to change the file, and the session will figure out
63
+ # which ones to run.
64
+ class AutomateIt::EditManager::EditSession < AutomateIt::Common
65
+ # Create an EditSession.
66
+ #
67
+ # Options:
68
+ # * :interpreter -- AutomateIt Interpreter, required. Will be automatically
69
+ # set if you use AutomateIt::Interpreter#edit.
70
+ def initialize(*args)
71
+ super(*args)
72
+ interpreter.add_method_missing_to(self)
73
+ end
74
+
75
+ # Edit a file or string.
76
+ #
77
+ # Requires a filename argument or options hash -- e.g.,.
78
+ # <tt>edit("foo")</tt> and <tt>edit(:file => "foo")</tt> will both edit a
79
+ # file called +foo+.
80
+ #
81
+ # Options:
82
+ # * :file -- File to edit.
83
+ # * :text -- String to edit.
84
+ # * :params -- Hash to make available to editor session.
85
+ # * :create -- Create the file if it doesn't exist? Defaults to false.
86
+ # * :mode, :user, :group -- Set permissions on generated file, see ShellManager#chperm
87
+ # * :backup -- Make a backup of original file? Defaults to true.
88
+ #
89
+ # Edit a string:
90
+ #
91
+ # edit(:text => "foo") do
92
+ # replace "o", "@"
93
+ # end
94
+ # # => "f@@"
95
+ #
96
+ # Edit a file and pass parameters to the editing session:
97
+ #
98
+ # edit(:file => "myfile", :params => {:greet => "world"} do
99
+ # prepend "MyHeader"
100
+ # append "Hello "+params[:greet]
101
+ # end
102
+ #
103
+ # Edit a file, create it and set permissions if necessary:
104
+ #
105
+ # edit("/tmp/foo", :create => true, :mode => 0600, :user => :root) do
106
+ # prepend "Hello world!"
107
+ # end
108
+ def edit(*a, &block)
109
+ args, opts = args_and_opts(*a)
110
+ if args.first
111
+ @filename = args.first
112
+ else
113
+ raise ArgumentError.new("no file or text specified for editing") unless opts[:file] or opts[:text]
114
+ @filename = opts[:file]
115
+ @contents = opts[:text]
116
+ end
117
+ @params = opts[:params] || {}
118
+ @is_backup = opts[:backup].nil? ? true : opts[:backup]
119
+ @comment_prefix = "# "
120
+ @comment_suffix = ""
121
+ begin
122
+ @contents ||= _read || ""
123
+ rescue Errno::ENOENT => e
124
+ if opts[:create]
125
+ @contents = ""
126
+ else
127
+ raise e
128
+ end
129
+ end
130
+ @original_contents = @contents.clone
131
+
132
+ raise ArgumentError.new("no block given") unless block
133
+ instance_eval(&block)
134
+ if @filename
135
+ if different?
136
+ _backup if @is_backup
137
+ _write
138
+ end
139
+
140
+ chperm_opts = {}
141
+ for key in [:owner, :user, :group, :mode]
142
+ chperm_opts[key] = opts[key] if opts[key]
143
+ end
144
+ chperm(@filename, chperm_opts) unless chperm_opts.empty?
145
+
146
+ return different?
147
+ else
148
+ return contents
149
+ end
150
+ end
151
+
152
+ # File that was read for editing.
153
+ attr_accessor :filename
154
+
155
+ # Current contents of the editing buffer.
156
+ attr_accessor :contents
157
+
158
+ # Original contents of the editing buffer before any changes were made.
159
+ attr_accessor :original_contents
160
+
161
+ # Hash of parameters to make available to the editing session.
162
+ attr_accessor :params
163
+
164
+ # Comment prefix, e.g., "/*"
165
+ attr_accessor :comment_prefix
166
+
167
+ # Comment suffix, e.g., "*/"
168
+ attr_accessor :comment_suffix
169
+
170
+ # Prepend +line+ to the top of the buffer, but only if it's not in this
171
+ # file already.
172
+ #
173
+ # Options:
174
+ # * :unless -- Look for this String or Regexp instead and don't prepend
175
+ # if it matches.
176
+ #
177
+ # Example:
178
+ # # Buffer's contents are 'add this line'
179
+ #
180
+ # # This will prepend a line because they're not identical.
181
+ # prepend("add this line")
182
+ #
183
+ # # Won't prepend line because Regexp matches exisint line in buffer.
184
+ # prepend("add this line", :unless => /add\s*this\*line/)
185
+ def prepend(line, opts={})
186
+ query = opts[:unless] || line
187
+ if query.is_a?(String)
188
+ query = Regexp.new(Regexp.escape(query))
189
+ end
190
+ return if contains?(query)
191
+ @contents = "%s\n%s" % [line.chomp, @contents]
192
+ end
193
+
194
+ # Append +line+ to the bottom of the buffer, but only if it's not in
195
+ # this file already.
196
+ #
197
+ # Options:
198
+ # * :unless -- Look for this String or Regexp instead and don't append
199
+ # if it matches.
200
+ #
201
+ # See example for #prepend.
202
+ def append(line, opts={})
203
+ query = opts[:unless] || line
204
+ if query.is_a?(String)
205
+ query = Regexp.new(Regexp.escape(query))
206
+ end
207
+ return if contains?(query)
208
+ @contents = "%s\n%s\n" % [@contents.chomp, line]
209
+ end
210
+
211
+ # Does the buffer contain anything that matches the String or Regexp +query+?
212
+ def contains?(line)
213
+ query = line.is_a?(String) ? Regexp.new(Regexp.escape(line)) : line
214
+ ! @contents.match(query).nil?
215
+ end
216
+
217
+ # Delete lines matching the String or Regexp +query+
218
+ def delete(line, opts={})
219
+ query = line.is_a?(String) ? Regexp.escape(line) : line
220
+ query = Regexp.new("^[^\n]*%s[^\n]*\n?" % query)
221
+ @contents.gsub!(query, "")
222
+ end
223
+
224
+ # Specify the comment style's +prefix+ and +suffix+.
225
+ #
226
+ # Example:
227
+ # # C style comments
228
+ # comment_style "/*", "*/"
229
+ def comment_style(prefix, suffix="")
230
+ @comment_prefix = prefix
231
+ @comment_suffix = suffix
232
+ end
233
+
234
+ # Comment out lines matching the String or Regexp +query+.
235
+ def comment(line, opts={})
236
+ query = line.is_a?(String) ? Regexp.escape(line) : line
237
+ query = Regexp.new("^(?!#{comment_prefix})([^\n]*%s[^\n]*)(\n*)" % query)
238
+ return false unless @contents.match(query)
239
+ @contents.gsub!(query, "%s%s%s%s" % [@comment_prefix, $1, @comment_suffix, $2])
240
+ end
241
+
242
+ # Uncomment lines matching the String or Regexp +query+.
243
+ def uncomment(line, opts={})
244
+ query = line.is_a?(String) ? Regexp.escape(line) : line
245
+ query = Regexp.new("^(%s)([^\n]*%s[^\n]*)(%s)(\n*)" % [@comment_prefix, query, @comment_suffix])
246
+ return false unless @contents.match(query)
247
+ @contents.gsub!(query, "%s%s" % [$2, $4])
248
+ end
249
+
250
+ # Replace contents matching the String or Regexp +query+ with the +string+.
251
+ def replace(line, string, opts={})
252
+ query = line.is_a?(String) ? Regexp.new(Regexp.escape(line)) : line
253
+ @contents.gsub!(query, string)
254
+ end
255
+
256
+ # Manipulate the buffer. The result of your block will replace the
257
+ # buffer. This is very useful for complex edits.
258
+ #
259
+ # Example:
260
+ # manipulate do |buffer|
261
+ # buffer.gsub(/foo/, "bar")
262
+ # end
263
+ def manipulate(&block) # :yields: buffer
264
+ @contents = block.call(@contents)
265
+ end
266
+
267
+ # Is the buffer currently different than its original contents?
268
+ def different?
269
+ @contents != @original_contents
270
+ end
271
+
272
+ protected
273
+
274
+ # Read contents from #filename. Called by the #edit command to load text
275
+ # into the buffer.
276
+ def _read
277
+ @contents = \
278
+ if writing? or (preview? and @filename and _exists? and _readable?)
279
+ File.read(@filename)
280
+ elsif preview? and not _readable?
281
+ log.info(PNOTE+"Not allowed to read file, previewing edits as if it doesn't exist: #{@filename}")
282
+ nil
283
+ else
284
+ nil
285
+ end
286
+ end
287
+
288
+ # Write contents to #filename. Used by the #edit command to write the buffer
289
+ # to a file.
290
+ def _write
291
+ return false unless @filename
292
+ log.info(PNOTE+"Edited '#{@filename}'")
293
+ if preview?
294
+ true
295
+ else
296
+ File.open(@filename, "w+"){|writer| writer.write(@contents)}
297
+ end
298
+ end
299
+
300
+ # Backup the original file.
301
+ def _backup
302
+ return false unless @filename and File.exists?(@filename)
303
+ result = nil
304
+ log.silence(Logger::WARN) do
305
+ result = backup(@filename)
306
+ end
307
+ log.debug(PNOTE+"Saved '#{@filename}' to '#{result}'")
308
+ end
309
+
310
+ # Does the file exist?
311
+ def _exists?
312
+ File.exists?(@filename)
313
+ end
314
+
315
+ # Is the file readable?
316
+ def _readable?
317
+ FileTest.readable?(@filename)
318
+ end
319
+
320
+
321
+ end # class EditSession