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,67 @@
|
|
1
|
+
# == ShellManager::BaseLink
|
2
|
+
#
|
3
|
+
# An abstract ShellManager driver used by drivers that provide either hard or
|
4
|
+
# symbolic links.
|
5
|
+
class AutomateIt::ShellManager::BaseLink < AutomateIt::ShellManager::BaseDriver
|
6
|
+
abstract_driver
|
7
|
+
|
8
|
+
# See ShellManager#ln
|
9
|
+
def _ln(sources, target, opts={})
|
10
|
+
kind = \
|
11
|
+
if opts[:symbolic] and opts[:force]
|
12
|
+
:ln_sf
|
13
|
+
elsif opts[:symbolic]
|
14
|
+
:ln_s
|
15
|
+
else
|
16
|
+
:ln
|
17
|
+
end
|
18
|
+
|
19
|
+
missing = []
|
20
|
+
sources = [sources].flatten
|
21
|
+
|
22
|
+
if kind == :ln
|
23
|
+
raise TypeError.new("source for hard link must be a String") unless sources.size == 1
|
24
|
+
end
|
25
|
+
|
26
|
+
for source in sources
|
27
|
+
peer = peer_for(source, target)
|
28
|
+
begin
|
29
|
+
peer_stat = File.stat(peer)
|
30
|
+
source_stat = File.stat(source)
|
31
|
+
|
32
|
+
if peer_stat.ino == source_stat.ino
|
33
|
+
next
|
34
|
+
elsif kind == :ln
|
35
|
+
missing << source
|
36
|
+
elsif Pathname.new(peer).realpath != Pathname.new(source).realpath
|
37
|
+
# It's either :ln_s or :ln_sf
|
38
|
+
missing << source
|
39
|
+
end
|
40
|
+
rescue Errno::ENOENT
|
41
|
+
# File doesn't exist, so obviously missing
|
42
|
+
missing << source
|
43
|
+
end
|
44
|
+
end
|
45
|
+
return false if missing.empty?
|
46
|
+
|
47
|
+
log.debug(PNOTE+"_ln(%s, %s, %s) # => %s" % [kind, sources.inspect, target.inspect, missing.inspect])
|
48
|
+
missing = missing.first if missing.size == 1
|
49
|
+
|
50
|
+
displayed = "ln"
|
51
|
+
if opts[:symbolic] and opts[:force]
|
52
|
+
displayed << " -sf"
|
53
|
+
else
|
54
|
+
displayed << " -s" if opts[:symbolic]
|
55
|
+
displayed << " -f" if opts[:force]
|
56
|
+
end
|
57
|
+
|
58
|
+
if kind == :ln
|
59
|
+
log.info(PEXEC+"#{displayed} #{missing} #{target}")
|
60
|
+
FileUtils.ln(missing, target, _fileutils_opts) && missing
|
61
|
+
else
|
62
|
+
log.info(PEXEC+"#{displayed} #{String === missing ? missing : missing.join(' ')} #{target}")
|
63
|
+
FileUtils.send(kind, missing, target, _fileutils_opts) && missing
|
64
|
+
end
|
65
|
+
return missing
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# == ShellManager::Link
|
2
|
+
#
|
3
|
+
# A ShellManager driver providing access to the hard link +ln+ command found on
|
4
|
+
# Unix-like systems.
|
5
|
+
class AutomateIt::ShellManager::Link < AutomateIt::ShellManager::BaseLink
|
6
|
+
depends_on :callbacks => [lambda{
|
7
|
+
RUBY_PLATFORM !~ /mswin/i and File.respond_to?(:link)
|
8
|
+
}]
|
9
|
+
|
10
|
+
def suitability(method, *args) # :nodoc:
|
11
|
+
# Level must be higher than Portable
|
12
|
+
return available? ? 2 : 0
|
13
|
+
end
|
14
|
+
|
15
|
+
# See ShellManager#provides_link?
|
16
|
+
def provides_link?
|
17
|
+
available? ? true : false
|
18
|
+
end
|
19
|
+
|
20
|
+
# See ShellManager#ln
|
21
|
+
def ln(*args)
|
22
|
+
_ln(*args)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,523 @@
|
|
1
|
+
# == ShellManager::Portable
|
2
|
+
#
|
3
|
+
# Pure-Ruby, portable driver for ShellManager provides Unix-like shell
|
4
|
+
# commands for manipulating files and executing commands.
|
5
|
+
#
|
6
|
+
# It does not provide commands for:
|
7
|
+
# * #which
|
8
|
+
# * #which!
|
9
|
+
class AutomateIt::ShellManager::Portable < AutomateIt::ShellManager::BaseDriver
|
10
|
+
depends_on :nothing
|
11
|
+
|
12
|
+
def suitability(method, *args) # :nodoc:
|
13
|
+
return available? ? 1 : 0
|
14
|
+
end
|
15
|
+
|
16
|
+
def broken?
|
17
|
+
RUBY_PLATFORM =~ /mswin|java/
|
18
|
+
end
|
19
|
+
private :broken?
|
20
|
+
|
21
|
+
def provides_mode?
|
22
|
+
! broken?
|
23
|
+
end
|
24
|
+
|
25
|
+
def provides_ownership?
|
26
|
+
! broken?
|
27
|
+
end
|
28
|
+
|
29
|
+
#...[ Custom commands ].................................................
|
30
|
+
|
31
|
+
# See ShellManager#backup
|
32
|
+
def backup(*sources)
|
33
|
+
sources, opts = args_and_opts(*sources)
|
34
|
+
|
35
|
+
targets = []
|
36
|
+
for source in sources
|
37
|
+
is_dir = File.directory?(source)
|
38
|
+
|
39
|
+
tempster_opts = {
|
40
|
+
:verbose => false,
|
41
|
+
:noop => noop?,
|
42
|
+
:delete => false,
|
43
|
+
:dir => File.dirname(source),
|
44
|
+
:prefix => "%s.%s" % [File.basename(source), Time.now.to_i],
|
45
|
+
:suffix => ".bak",
|
46
|
+
:kind => is_dir ? :directory : :file,
|
47
|
+
}
|
48
|
+
|
49
|
+
target = ::Tempster.tempster(tempster_opts)
|
50
|
+
|
51
|
+
log.silence(opts[:quiet] ? Logger::WARN : log.level) do
|
52
|
+
if is_dir
|
53
|
+
cp_opts = {}
|
54
|
+
cp_opts[:recursive] = true if is_dir
|
55
|
+
cp_opts[:preserve] = :try
|
56
|
+
|
57
|
+
source_children = _directory_contents(source)
|
58
|
+
#puts "sc: %s" % source_children.inspect
|
59
|
+
|
60
|
+
interpreter.cp_r(source_children, target, cp_opts)
|
61
|
+
else
|
62
|
+
interpreter.cp(source, target)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
targets << target
|
67
|
+
end
|
68
|
+
return sources.size == 1 ? targets.first : targets
|
69
|
+
end
|
70
|
+
|
71
|
+
# See ShellManager#sh
|
72
|
+
def sh(*commands)
|
73
|
+
args, opts = args_and_opts(*commands)
|
74
|
+
log.info(PEXEC+"#{args.join(' ')}")
|
75
|
+
return writing? ? system(*args) : true
|
76
|
+
end
|
77
|
+
|
78
|
+
def _mktemp_helper(kind, name=nil, opts={}, &block)
|
79
|
+
# Tempster takes care of rethrowing exceptions
|
80
|
+
opts[:name] = name || "automateit_temp"
|
81
|
+
opts[:message_callback] = lambda{|msg| log.info(PEXEC+msg)}
|
82
|
+
opts[:noop] = interpreter.preview?
|
83
|
+
::Tempster.send(kind, opts, &block)
|
84
|
+
end
|
85
|
+
private :_mktemp_helper
|
86
|
+
|
87
|
+
# See ShellManager#mktemp
|
88
|
+
def mktemp(name=nil, &block)
|
89
|
+
_mktemp_helper(:mktemp, name, &block)
|
90
|
+
end
|
91
|
+
|
92
|
+
# See ShellManager#mktempdir
|
93
|
+
def mktempdir(name=nil, &block)
|
94
|
+
_mktemp_helper(:mktempdir, name, &block)
|
95
|
+
end
|
96
|
+
|
97
|
+
# See ShellManager#mktempdircd
|
98
|
+
def mktempdircd(name=nil, &block)
|
99
|
+
_mktemp_helper(:mktempdircd, name, &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
# See ShellManager#umask
|
103
|
+
def umask(mode=nil, &block)
|
104
|
+
if mode
|
105
|
+
old = File::umask
|
106
|
+
File::umask(mode)
|
107
|
+
if block
|
108
|
+
begin
|
109
|
+
block.call
|
110
|
+
rescue Exception => e
|
111
|
+
raise e
|
112
|
+
ensure
|
113
|
+
File::umask(old)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
else
|
117
|
+
File::umask
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
#...[ FileUtils wrappers ]...............................................
|
122
|
+
|
123
|
+
# See ShellManager#cd
|
124
|
+
def cd(dir, opts={}, &block)
|
125
|
+
if block
|
126
|
+
log.enqueue(:info, PEXEC+(block ? "pushd" : "cd")+" "+dir)
|
127
|
+
begin
|
128
|
+
if writing? or File.directory?(dir)
|
129
|
+
FileUtils.cd(dir, &block)
|
130
|
+
else
|
131
|
+
block.call(true)
|
132
|
+
end
|
133
|
+
rescue Exception => e
|
134
|
+
raise e
|
135
|
+
ensure
|
136
|
+
log.dequeue(:info, PEXEC+"popd # => #{pwd}")
|
137
|
+
end
|
138
|
+
else
|
139
|
+
FileUtils.cd(dir) if writing?
|
140
|
+
end
|
141
|
+
return dir
|
142
|
+
end
|
143
|
+
|
144
|
+
# See ShellManager#pwd
|
145
|
+
def pwd()
|
146
|
+
return FileUtils.pwd()
|
147
|
+
end
|
148
|
+
|
149
|
+
# See ShellManager#mkdir
|
150
|
+
def mkdir(dirs, opts={}, &block)
|
151
|
+
_replace_owner_with_user(opts)
|
152
|
+
kind = opts[:parents] ? :mkdir_p : :mkdir
|
153
|
+
missing = [dirs].flatten.select{|dir| ! File.directory?(dir)}
|
154
|
+
result = false
|
155
|
+
if missing.empty? and not block
|
156
|
+
chperm(opts) if opts[:user] or opts[:group] or opts[:mode]
|
157
|
+
return result
|
158
|
+
end
|
159
|
+
unless missing.empty?
|
160
|
+
cmd = kind.to_s.gsub(/_/, ' -')
|
161
|
+
log.info(PEXEC+"#{cmd} #{missing.join(" ")}")
|
162
|
+
result = [FileUtils.send(kind, missing, _fileutils_opts)].flatten
|
163
|
+
result = result.first if [dirs].flatten.size == 1
|
164
|
+
end
|
165
|
+
if block
|
166
|
+
if missing.size > 1
|
167
|
+
raise ArgumentError.new(
|
168
|
+
"can only use a block if you mkdir a single directory")
|
169
|
+
end
|
170
|
+
dir = [dirs].flatten.first
|
171
|
+
cd(dir) do
|
172
|
+
block.call(result)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
chperm(opts) if opts[:user] or opts[:group] or opts[:mode]
|
176
|
+
return missing
|
177
|
+
end
|
178
|
+
|
179
|
+
# See ShellManager#mkdir_p
|
180
|
+
def mkdir_p(dirs, opts={}, &block)
|
181
|
+
mkdir(dirs, {:parents => true}.merge(opts), &block)
|
182
|
+
end
|
183
|
+
|
184
|
+
# See ShellManager#rmdir
|
185
|
+
def rmdir(dirs)
|
186
|
+
present = [dirs].flatten.select{|dir| File.directory?(dir)}
|
187
|
+
return false if present.empty?
|
188
|
+
log.info(PEXEC+"rmdir #{String === dirs ? dirs : dirs.join(' ')}")
|
189
|
+
FileUtils.rmdir(present, _fileutils_opts)
|
190
|
+
return present
|
191
|
+
end
|
192
|
+
|
193
|
+
# See ShellManager#install
|
194
|
+
def install(source, target, mode=nil)
|
195
|
+
cp_rv = nil
|
196
|
+
chmod_rv = nil
|
197
|
+
log.silence(Logger::WARN) do
|
198
|
+
cp_rv = cp(source, target)
|
199
|
+
chmod_rv = chmod(mode, peer_for(source, target)) if mode
|
200
|
+
end
|
201
|
+
|
202
|
+
return false unless cp_rv or chmod_rv
|
203
|
+
|
204
|
+
log.info(PEXEC+"install%s %s %s" %
|
205
|
+
[mode ? ' -m 0%o' % mode : '', source, target])
|
206
|
+
return source
|
207
|
+
end
|
208
|
+
|
209
|
+
# See ShellManager#cp
|
210
|
+
def cp(sources, target, opts={})
|
211
|
+
# TODO ShellManager::Portable#cp -- rather funky, needs a code review
|
212
|
+
fu_opts = _fileutils_opts
|
213
|
+
for opt in [:noop, :verbose]
|
214
|
+
opt = opt.to_sym
|
215
|
+
fu_opts[opt] = opts[opt] if opts[opt]
|
216
|
+
end
|
217
|
+
|
218
|
+
fu_opts_with_preserve = fu_opts.clone
|
219
|
+
fu_opts_with_preserve[:preserve] = \
|
220
|
+
if opts[:preserve] == :try
|
221
|
+
fsim = File::Stat.instance_methods
|
222
|
+
(fsim.include?("uid") and fsim.include?("gid") and
|
223
|
+
fsim.include?("mode") and fsim.include?("atime"))
|
224
|
+
else
|
225
|
+
opts[:preserve]
|
226
|
+
end
|
227
|
+
|
228
|
+
changed = []
|
229
|
+
sources_a = [sources].flatten
|
230
|
+
sources_a.each do |parent|
|
231
|
+
Find.find(parent) do |child|
|
232
|
+
source_fn = File.directory?(child) ? child+"/" : child
|
233
|
+
target_dir = File.directory?(target)
|
234
|
+
target_fn = peer_for(source_fn, target)
|
235
|
+
|
236
|
+
log.debug(PNOTE+"comparing %s => %s" % [source_fn, target_fn])
|
237
|
+
source_st = File.stat(source_fn)
|
238
|
+
is_copy = false
|
239
|
+
begin
|
240
|
+
begin
|
241
|
+
target_st = File.stat(target_fn)
|
242
|
+
|
243
|
+
unless target_dir
|
244
|
+
# Is the file obviously different?
|
245
|
+
if source_st.file?
|
246
|
+
for kind in %w(size mtime)
|
247
|
+
next if kind == "mtime" and ! opts[:preserve]
|
248
|
+
unless source_st.send(kind) == target_st.send(kind)
|
249
|
+
log.debug(PNOTE+"%s not same %s" % [target_fn, kind])
|
250
|
+
raise EOFError.new
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
unless FileUtils.identical?(source_fn, target_fn)
|
255
|
+
log.debug(PNOTE+"%s not identical" % target_fn)
|
256
|
+
raise EOFError.new
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# File just needs to be altered
|
261
|
+
if opts[:preserve]
|
262
|
+
unless source_st.mode == target_st.mode
|
263
|
+
changed << child
|
264
|
+
log.debug(PNOTE+"%s not same mode" % target_fn)
|
265
|
+
chmod(source_st.mode, target_fn, fu_opts)
|
266
|
+
end
|
267
|
+
unless source_st.uid == target_st.uid and source_st.gid == target_st.gid
|
268
|
+
changed << child
|
269
|
+
log.debug(PNOTE+"%s not same uid/gid" % target_fn)
|
270
|
+
chown(source_st.uid, source_st.gid, target_fn, fu_opts)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
rescue EOFError
|
275
|
+
changed << child
|
276
|
+
is_copy = true
|
277
|
+
end
|
278
|
+
rescue Errno::ENOENT
|
279
|
+
changed << child
|
280
|
+
log.debug(PNOTE+"%s not present" % target_fn)
|
281
|
+
is_copy = true
|
282
|
+
end
|
283
|
+
if is_copy
|
284
|
+
log.info(PEXEC+"cp%s %s %s" % [opts[:recursive] ? ' -r' : '', source_fn, target_fn])
|
285
|
+
## puts "fo %s" % fu_opts.inspect
|
286
|
+
## puts "fowp %s" % fu_opts_with_preserve.inspect
|
287
|
+
FileUtils.cp_r(source_fn, target_fn, fu_opts_with_preserve)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
result = \
|
293
|
+
if changed.empty?
|
294
|
+
false
|
295
|
+
else
|
296
|
+
if sources_a.size == 1
|
297
|
+
changed.first
|
298
|
+
else
|
299
|
+
changed.uniq
|
300
|
+
end
|
301
|
+
end
|
302
|
+
return result
|
303
|
+
end
|
304
|
+
|
305
|
+
# See ShellManager#cp_r
|
306
|
+
def cp_r(sources, target, opts={})
|
307
|
+
cp(sources, target, {:recursive => true}.merge(opts))
|
308
|
+
end
|
309
|
+
|
310
|
+
# See ShellManager#cp_R
|
311
|
+
def cp_R(*args)
|
312
|
+
cp_r(*args)
|
313
|
+
end
|
314
|
+
|
315
|
+
# See ShellManager#mv
|
316
|
+
def mv(sources, target)
|
317
|
+
present = [sources].flatten.select{|entry| self._present?(entry)}
|
318
|
+
return false if present.empty?
|
319
|
+
present = present.first if present.size == 1
|
320
|
+
FileUtils.mv(present, target, _fileutils_opts) && present
|
321
|
+
return present
|
322
|
+
end
|
323
|
+
|
324
|
+
# See ShellManager#rm
|
325
|
+
def rm(targets, opts={})
|
326
|
+
kind = \
|
327
|
+
if opts[:recursive] and opts[:force]
|
328
|
+
:rm_rf
|
329
|
+
elsif opts[:recursive]
|
330
|
+
:rm_r
|
331
|
+
else
|
332
|
+
:rm
|
333
|
+
end
|
334
|
+
|
335
|
+
present = [targets].flatten.select{|entry| self._present?(entry)}
|
336
|
+
return false if present.empty?
|
337
|
+
|
338
|
+
msg = "rm"
|
339
|
+
if opts[:recursive] and opts[:force]
|
340
|
+
msg << " -rf"
|
341
|
+
elsif opts[:recursive]
|
342
|
+
msg << " -r"
|
343
|
+
elsif opts[:force]
|
344
|
+
msg << " -f"
|
345
|
+
end
|
346
|
+
msg << " " << present.join(' ')
|
347
|
+
log.info(PEXEC+msg)
|
348
|
+
|
349
|
+
present = present.first if present.size == 0
|
350
|
+
|
351
|
+
FileUtils.send(kind, present, _fileutils_opts)
|
352
|
+
return present
|
353
|
+
end
|
354
|
+
|
355
|
+
# See ShellManager#rm_r
|
356
|
+
def rm_r(targets, opts={})
|
357
|
+
rm(targets, {:recursive => true}.merge(opts))
|
358
|
+
end
|
359
|
+
|
360
|
+
# See ShellManager#rm_rf
|
361
|
+
def rm_rf(targets, opts={})
|
362
|
+
rm(targets, {:recursive => true, :force => true}.merge(opts))
|
363
|
+
end
|
364
|
+
|
365
|
+
FILE_MASK = 0100000
|
366
|
+
DIRECTORY_MASK = 040000
|
367
|
+
|
368
|
+
# See ShellManager#chperm
|
369
|
+
def chperm(targets, opts={})
|
370
|
+
_replace_owner_with_user(opts)
|
371
|
+
user = \
|
372
|
+
if opts[:user]
|
373
|
+
opts[:user] = opts[:user].to_s if opts[:user].is_a?(Symbol)
|
374
|
+
if opts[:user].is_a?(String)
|
375
|
+
begin
|
376
|
+
Etc.getpwnam(opts[:user]).uid
|
377
|
+
rescue ArgumentError
|
378
|
+
:not_present
|
379
|
+
end
|
380
|
+
else
|
381
|
+
opts[:user]
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
group = \
|
386
|
+
if opts[:group]
|
387
|
+
opts[:group] = opts[:group].to_s if opts[:group].is_a?(Symbol)
|
388
|
+
if opts[:group].is_a?(String)
|
389
|
+
begin
|
390
|
+
Etc.getgrnam(opts[:group]).gid
|
391
|
+
rescue ArgumentError
|
392
|
+
:not_present
|
393
|
+
end
|
394
|
+
else
|
395
|
+
opts[:group]
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
modified_entries = []
|
400
|
+
modified_ownership = false
|
401
|
+
modified_permission = false
|
402
|
+
Find.find(*targets) do |path|
|
403
|
+
modified = false
|
404
|
+
stat = writing? || File.exists?(path) ? File.stat(path) : nil
|
405
|
+
if opts[:mode]
|
406
|
+
# TODO ShellManager::Portable#chperm -- process chmod symbolic strings, e.g., [ugoa...][[+-=][rwxXstugo...]...][,...]
|
407
|
+
mode = opts[:mode] | (stat.directory? ? DIRECTORY_MASK : FILE_MASK) if stat
|
408
|
+
unless stat and (mode ^ stat.mode).zero?
|
409
|
+
modified = true
|
410
|
+
modified_permission = true
|
411
|
+
File.chmod(mode, path) if writing?
|
412
|
+
end
|
413
|
+
end
|
414
|
+
if user and (not stat or user != stat.uid)
|
415
|
+
modified = true
|
416
|
+
modified_ownership = true
|
417
|
+
File.chown(user, nil, path) if writing?
|
418
|
+
end
|
419
|
+
if group and (not stat or group != stat.gid)
|
420
|
+
modified = true
|
421
|
+
modified_ownership = true
|
422
|
+
File.chown(nil, group, path) if writing?
|
423
|
+
end
|
424
|
+
modified_entries << path if modified
|
425
|
+
Find.prune if not opts[:recursive] and File.directory?(path)
|
426
|
+
end
|
427
|
+
|
428
|
+
return false if modified_entries.empty?
|
429
|
+
|
430
|
+
display_entries = opts[:details] ? modified_entries : targets
|
431
|
+
display_entries = [display_entries].flatten
|
432
|
+
|
433
|
+
if modified_permission
|
434
|
+
msg = "chmod"
|
435
|
+
msg << " -R" if opts[:recursive]
|
436
|
+
msg << " 0%o" % opts[:mode] if opts[:mode]
|
437
|
+
msg << " " << display_entries.join(' ')
|
438
|
+
log.info(PEXEC+msg)
|
439
|
+
end
|
440
|
+
if modified_ownership
|
441
|
+
msg = "chown"
|
442
|
+
msg << " -R" if opts[:recursive]
|
443
|
+
msg << " %s" % opts[:user] if opts[:user]
|
444
|
+
msg << ":" if opts[:user] and opts[:group]
|
445
|
+
msg << "%s" % opts[:group] if opts[:group]
|
446
|
+
msg << " " << display_entries.join(' ')
|
447
|
+
log.info(PEXEC+msg)
|
448
|
+
end
|
449
|
+
return targets.is_a?(String) ? modified_entries.first : modified_entries
|
450
|
+
end
|
451
|
+
|
452
|
+
# See ShellManager#chmod
|
453
|
+
def chmod(mode, targets, opts={})
|
454
|
+
chperm(targets, {:mode => mode}.merge(opts))
|
455
|
+
end
|
456
|
+
|
457
|
+
# See ShellManager#chmod_R
|
458
|
+
def chmod_R(mode, targets, opts={})
|
459
|
+
chmod(mode, targets, {:recursive => true}.merge(opts))
|
460
|
+
end
|
461
|
+
|
462
|
+
# See ShellManager#chown
|
463
|
+
def chown(user, group, targets, opts={})
|
464
|
+
chperm(targets, {:user => user, :group => group}.merge(opts))
|
465
|
+
end
|
466
|
+
|
467
|
+
# See ShellManager#chown_R
|
468
|
+
def chown_R(user, group, targets, opts={})
|
469
|
+
chown(user, group, targets, {:recursive => true}.merge(opts))
|
470
|
+
end
|
471
|
+
|
472
|
+
# See ShellManager#touch
|
473
|
+
def touch(targets, opts={})
|
474
|
+
like = opts.delete(:like)
|
475
|
+
stamp = opts.delete(:stamp)
|
476
|
+
quiet = opts.delete(:quiet) == true ? true : false
|
477
|
+
time = \
|
478
|
+
if stamp
|
479
|
+
stamp
|
480
|
+
elsif like
|
481
|
+
begin
|
482
|
+
File.stat(like).mtime
|
483
|
+
rescue Errno::ENOENT => e
|
484
|
+
if preview?
|
485
|
+
Time.now
|
486
|
+
else
|
487
|
+
raise e
|
488
|
+
end
|
489
|
+
end
|
490
|
+
else
|
491
|
+
Time.now
|
492
|
+
end
|
493
|
+
|
494
|
+
unless quiet
|
495
|
+
msg = "touch"
|
496
|
+
msg << " --reference %s" % like if like
|
497
|
+
msg << " --stamp %s" % stamp if stamp
|
498
|
+
msg << " " << [targets].flatten.join(" ")
|
499
|
+
log.info(PEXEC+msg)
|
500
|
+
end
|
501
|
+
|
502
|
+
results = []
|
503
|
+
for target in [targets].flatten
|
504
|
+
begin
|
505
|
+
stat = File.stat(target)
|
506
|
+
next if stat.mtime.to_i == time.to_i
|
507
|
+
rescue Errno::ENOENT
|
508
|
+
File.open(target, "a"){} unless preview?
|
509
|
+
end
|
510
|
+
File.utime(time, time, target) unless preview?
|
511
|
+
results << target
|
512
|
+
end
|
513
|
+
|
514
|
+
return false if results.empty?
|
515
|
+
return targets.is_a?(String) ? results.first : results
|
516
|
+
end
|
517
|
+
|
518
|
+
# Is the file or symlink at this +path+ present?
|
519
|
+
def _present?(path)
|
520
|
+
File.symlink?(path) ? true : File.exists?(path)
|
521
|
+
end
|
522
|
+
protected :_present?
|
523
|
+
end
|