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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.hgignore +10 -0
- data/.loadpath +5 -0
- data/.project +17 -0
- data/CHANGES.txt +314 -0
- data/Hoe.rake +40 -0
- data/Manifest.txt +164 -0
- data/README.txt +40 -0
- data/Rakefile +256 -0
- data/TESTING.txt +57 -0
- data/TODO.txt +50 -0
- data/TUTORIAL.txt +391 -0
- data/automate-it.gemspec +25 -0
- data/bin/ai +3 -0
- data/bin/aifield +75 -0
- data/bin/aissh +93 -0
- data/bin/aitag +134 -0
- data/bin/automateit +133 -0
- data/docs/friendly_errors.txt +50 -0
- data/docs/previews.txt +86 -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 +7 -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 +61 -0
- data/examples/basic/recipes/uninstall.rb +6 -0
- data/gpl.txt +674 -0
- data/helpers/cpan_wrapper.pl +220 -0
- data/helpers/which.cmd +7 -0
- data/lib/automateit.rb +55 -0
- data/lib/automateit/account_manager.rb +114 -0
- data/lib/automateit/account_manager/base.rb +138 -0
- data/lib/automateit/account_manager/etc.rb +128 -0
- data/lib/automateit/account_manager/nscd.rb +33 -0
- data/lib/automateit/account_manager/passwd_expect.rb +40 -0
- data/lib/automateit/account_manager/passwd_pty.rb +69 -0
- data/lib/automateit/account_manager/posix.rb +138 -0
- data/lib/automateit/address_manager.rb +88 -0
- data/lib/automateit/address_manager/base.rb +171 -0
- data/lib/automateit/address_manager/bsd.rb +28 -0
- data/lib/automateit/address_manager/freebsd.rb +59 -0
- data/lib/automateit/address_manager/linux.rb +42 -0
- data/lib/automateit/address_manager/openbsd.rb +66 -0
- data/lib/automateit/address_manager/portable.rb +37 -0
- data/lib/automateit/address_manager/sunos.rb +34 -0
- data/lib/automateit/cli.rb +85 -0
- data/lib/automateit/common.rb +65 -0
- data/lib/automateit/constants.rb +35 -0
- data/lib/automateit/download_manager.rb +48 -0
- data/lib/automateit/edit_manager.rb +321 -0
- data/lib/automateit/error.rb +10 -0
- data/lib/automateit/field_manager.rb +103 -0
- data/lib/automateit/interpreter.rb +631 -0
- data/lib/automateit/package_manager.rb +257 -0
- data/lib/automateit/package_manager/apt.rb +27 -0
- data/lib/automateit/package_manager/cpan.rb +101 -0
- data/lib/automateit/package_manager/dpkg.rb +54 -0
- data/lib/automateit/package_manager/egg.rb +64 -0
- data/lib/automateit/package_manager/gem.rb +201 -0
- data/lib/automateit/package_manager/pear.rb +95 -0
- data/lib/automateit/package_manager/pecl.rb +80 -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 +49 -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 +29 -0
- data/lib/automateit/platform_manager/gentoo.rb +26 -0
- data/lib/automateit/platform_manager/lsb.rb +44 -0
- data/lib/automateit/platform_manager/openbsd.rb +28 -0
- data/lib/automateit/platform_manager/struct.rb +80 -0
- data/lib/automateit/platform_manager/sunos.rb +39 -0
- data/lib/automateit/platform_manager/uname.rb +29 -0
- data/lib/automateit/platform_manager/windows.rb +40 -0
- data/lib/automateit/plugin.rb +7 -0
- data/lib/automateit/plugin/base.rb +32 -0
- data/lib/automateit/plugin/driver.rb +256 -0
- data/lib/automateit/plugin/manager.rb +224 -0
- data/lib/automateit/project.rb +493 -0
- data/lib/automateit/root.rb +17 -0
- data/lib/automateit/service_manager.rb +93 -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 +139 -0
- data/lib/automateit/service_manager/update_rcd.rb +35 -0
- data/lib/automateit/shell_manager.rb +316 -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 +523 -0
- data/lib/automateit/shell_manager/symlink.rb +32 -0
- data/lib/automateit/shell_manager/which_base.rb +30 -0
- data/lib/automateit/shell_manager/which_unix.rb +16 -0
- data/lib/automateit/shell_manager/which_windows.rb +20 -0
- data/lib/automateit/tag_manager.rb +127 -0
- data/lib/automateit/tag_manager/struct.rb +121 -0
- data/lib/automateit/tag_manager/tag_parser.rb +93 -0
- data/lib/automateit/tag_manager/yaml.rb +29 -0
- data/lib/automateit/template_manager.rb +56 -0
- data/lib/automateit/template_manager/base.rb +181 -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/ext/shell_escape.rb +7 -0
- data/lib/hashcache.rb +22 -0
- data/lib/helpful_erb.rb +63 -0
- data/lib/inactive_support.rb +53 -0
- data/lib/inactive_support/basic_object.rb +6 -0
- data/lib/inactive_support/clean_logger.rb +127 -0
- data/lib/inactive_support/core_ext/array/extract_options.rb +19 -0
- data/lib/inactive_support/core_ext/blank.rb +50 -0
- data/lib/inactive_support/core_ext/class/attribute_accessors.rb +48 -0
- data/lib/inactive_support/core_ext/class/inheritable_attributes.rb +140 -0
- data/lib/inactive_support/core_ext/enumerable.rb +63 -0
- data/lib/inactive_support/core_ext/hash/keys.rb +54 -0
- data/lib/inactive_support/core_ext/module/aliasing.rb +70 -0
- data/lib/inactive_support/core_ext/numeric/time.rb +91 -0
- data/lib/inactive_support/core_ext/string/inflections.rb +153 -0
- data/lib/inactive_support/core_ext/symbol.rb +14 -0
- data/lib/inactive_support/core_ext/time/conversions.rb +96 -0
- data/lib/inactive_support/duration.rb +96 -0
- data/lib/inactive_support/inflections.rb +53 -0
- data/lib/inactive_support/inflector.rb +282 -0
- data/lib/nested_error.rb +33 -0
- data/lib/nitpick.rb +33 -0
- data/lib/queued_logger.rb +68 -0
- data/lib/tempster.rb +250 -0
- data/misc/index_gem_repository.rb +304 -0
- data/misc/setup_egg.rb +12 -0
- data/misc/setup_gem_dependencies.sh +6 -0
- data/misc/setup_rubygems.sh +21 -0
- 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
|