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,17 @@
|
|
1
|
+
# See AutomateIt::Interpreter for usage information.
|
2
|
+
module AutomateIt # :nodoc:
|
3
|
+
# AutomateIt version
|
4
|
+
VERSION=Gem::Version.new("0.80624")
|
5
|
+
|
6
|
+
# Instantiates a new Interpreter. See documentation for
|
7
|
+
# Interpreter#setup.
|
8
|
+
def self.new(opts={})
|
9
|
+
Interpreter.new(opts)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Invokes an Interpreter on the recipe. See documentation for
|
13
|
+
# Interpreter::invoke.
|
14
|
+
def self.invoke(recipe, opts={})
|
15
|
+
Interpreter.invoke(recipe, opts)
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# == ServiceManager
|
2
|
+
#
|
3
|
+
# ServiceManager provides a way of managing services, such starting and
|
4
|
+
# stopping Unix daemons.
|
5
|
+
class AutomateIt::ServiceManager < AutomateIt::Plugin::Manager
|
6
|
+
# Is this +service+ started?
|
7
|
+
#
|
8
|
+
# Options:
|
9
|
+
# * :wait -- Maximum number of seconds to wait until service starts. Useful
|
10
|
+
# when a service accepts a #start and returns immediately before the service
|
11
|
+
# has finished starting.
|
12
|
+
def started?(service, opts={}) dispatch(service, opts) end
|
13
|
+
|
14
|
+
# Is this +service+ stopped?
|
15
|
+
#
|
16
|
+
# Options:
|
17
|
+
# * :wait -- Maximum number of seconds to wait until service stops. Useful
|
18
|
+
# when a service accepts a #stop and returns immediately while the service
|
19
|
+
# continues running for a few seconds.
|
20
|
+
def stopped?(service, opts={}) dispatch(service, opts) end
|
21
|
+
|
22
|
+
# Alias for #started?
|
23
|
+
def running?(service, opts={}) dispatch_to(:started?, service, opts) end
|
24
|
+
|
25
|
+
# Start this +service+ if it's not running.
|
26
|
+
#
|
27
|
+
# Options:
|
28
|
+
# * :wait -- Same as :wait option for #started?
|
29
|
+
# * :force -- Start service without checking if it's running.
|
30
|
+
def start(service, opts={}) dispatch(service, opts) end
|
31
|
+
|
32
|
+
# Stop this +service+ if it's running.
|
33
|
+
#
|
34
|
+
# Options:
|
35
|
+
# * :wait -- Same as :wait option for #stopped?
|
36
|
+
# * :force -- Stop service without checking if it's running.
|
37
|
+
def stop(service, opts={}) dispatch(service, opts) end
|
38
|
+
|
39
|
+
# Restart this +service+ if it's running, or start it if it's stopped.
|
40
|
+
#
|
41
|
+
# Options:
|
42
|
+
# * :wait -- Maxmimum seconds to wait for service to STOP.
|
43
|
+
# * :pause -- Maximum seconds to wait for service to START before stopping
|
44
|
+
# it. Only set this if you just started the service and then decided to
|
45
|
+
# restart it.
|
46
|
+
def restart(service, opts={}) dispatch(service, opts) end
|
47
|
+
|
48
|
+
# If +is_restart+, #restart the service, otherwise #start it.
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
# modified = edit "/etc/myapp.conf" {#...}
|
52
|
+
# service_manager.start_or_restart("myapp", modified)
|
53
|
+
def start_or_restart(service, is_restart, opts={}) dispatch(service, is_restart, opts) end
|
54
|
+
|
55
|
+
# Start and enable the service using #start and #enable.
|
56
|
+
def start_and_enable(service, opts={}) dispatch(service, opts) end
|
57
|
+
|
58
|
+
# Tell the +service+ to take a specific +action+, e.g., "condrestart".
|
59
|
+
def tell(service, action, opts={}) dispatch(service, action, opts={}) end
|
60
|
+
|
61
|
+
# Will this +service+ start when the computer is rebooted?
|
62
|
+
def enabled?(service) dispatch(service) end
|
63
|
+
|
64
|
+
# Make this +service+ start when the computer is rebooted, but only if it's
|
65
|
+
# not already enabled.
|
66
|
+
def enable(service, opts={}) dispatch(service, opts) end
|
67
|
+
|
68
|
+
# Don't make this +service+ start when the computer is rebooted, but only
|
69
|
+
# if it's already enabled.
|
70
|
+
def disable(service, opts={}) dispatch(service, opts) end
|
71
|
+
end
|
72
|
+
|
73
|
+
# == ServiceManager::BaseDriver
|
74
|
+
#
|
75
|
+
# Base class for all ServiceManager drivers.
|
76
|
+
class AutomateIt::ServiceManager::BaseDriver < AutomateIt::Plugin::Driver
|
77
|
+
# See ServiceManager#start_or_restart
|
78
|
+
def start_or_restart(service, is_restart, opts={})
|
79
|
+
send(is_restart ? :restart : :start, service, opts)
|
80
|
+
end
|
81
|
+
|
82
|
+
# See ServiceManager#start_and_enable
|
83
|
+
def start_and_enable(service, opts={})
|
84
|
+
start(service, opts)
|
85
|
+
enable(service, opts)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Drivers
|
90
|
+
require 'automateit/service_manager/sysv'
|
91
|
+
require 'automateit/service_manager/update_rcd'
|
92
|
+
require 'automateit/service_manager/chkconfig'
|
93
|
+
require 'automateit/service_manager/rc_update'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# == ServiceManager::Chkconfig
|
2
|
+
#
|
3
|
+
# The Chkconfig driver implements the ServiceManager methods for #enabled?,
|
4
|
+
# #enable and #disable on RedHat-like platforms. It uses the SYSV driver
|
5
|
+
# for handling the methods #running?, #start and #stop.
|
6
|
+
class AutomateIt::ServiceManager::Chkconfig < AutomateIt::ServiceManager::SYSV
|
7
|
+
depends_on :programs => %w(chkconfig)
|
8
|
+
|
9
|
+
def suitability(method, *args) # :nodoc:
|
10
|
+
return available? ? 2 : 0
|
11
|
+
end
|
12
|
+
|
13
|
+
# See ServiceManager#enabled?
|
14
|
+
def enabled?(service)
|
15
|
+
_raise_unless_available
|
16
|
+
# "chkconfig --list service" may produce output like the below:
|
17
|
+
# service httpd supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add automateit_service_sysv_test')
|
18
|
+
# => httpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off
|
19
|
+
if matcher = `chkconfig --list #{service} < /dev/null 2>&1` \
|
20
|
+
.match(/^(#{service}).+?(\d+:(on|off).+?)$/)
|
21
|
+
return true if matcher[2].match(/\b\d+:on\b/)
|
22
|
+
end
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
# See ServiceManager#enable
|
27
|
+
def enable(service, opts={})
|
28
|
+
_raise_unless_available
|
29
|
+
return false if enabled?(service)
|
30
|
+
interpreter.sh("chkconfig --add #{service}")
|
31
|
+
end
|
32
|
+
|
33
|
+
# See ServiceManager#disable
|
34
|
+
def disable(service, opts={})
|
35
|
+
_raise_unless_available
|
36
|
+
return false unless enabled?(service)
|
37
|
+
interpreter.sh("chkconfig --del #{service}")
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# == ServiceManager::RC_Update
|
2
|
+
#
|
3
|
+
# RC_Update implements the #enabled?, #enable and #disable features of the
|
4
|
+
# ServiceManager on Gentoo-like systems.
|
5
|
+
class AutomateIt::ServiceManager::RC_Update < AutomateIt::ServiceManager::SYSV
|
6
|
+
depends_on :programs => %w(rc-update)
|
7
|
+
|
8
|
+
def suitability(method, *args) # :nodoc:
|
9
|
+
return available? ? 2 : 0
|
10
|
+
end
|
11
|
+
|
12
|
+
# See ServiceManager#enabled?
|
13
|
+
def enabled?(service)
|
14
|
+
_raise_unless_available
|
15
|
+
# Do NOT use Gentoo's rc-update because the idiot that wrote that utility
|
16
|
+
# truncates service names to look "prettier" and provides no way to disable
|
17
|
+
# this annoyance for people that need to query services by name.
|
18
|
+
result = %w(boot default).select do |runlevel|
|
19
|
+
File.exists?(File.join("/etc/runlevels", runlevel, service))
|
20
|
+
end
|
21
|
+
return ! result.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
# See ServiceManager#enable
|
25
|
+
def enable(service, opts={})
|
26
|
+
_raise_unless_available
|
27
|
+
return false if enabled?(service)
|
28
|
+
interpreter.sh("rc-update add #{service} default > /dev/null 2>&1")
|
29
|
+
end
|
30
|
+
|
31
|
+
# See ServiceManager#disable
|
32
|
+
def disable(service, opts={})
|
33
|
+
_raise_unless_available
|
34
|
+
return false unless enabled?(service)
|
35
|
+
interpreter.sh("rc-update del #{service} default > /dev/null 2>&1")
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# == ServiceManager::SYSV
|
2
|
+
#
|
3
|
+
# The SYSV driver implements the ServiceManager methods for #running?,
|
4
|
+
# #start and #stop on Unix-like platforms that use the System V init
|
5
|
+
# process using a <tt>/etc/init.d</tt> directory.
|
6
|
+
#
|
7
|
+
# It also implements a basic #enabled? method that's very fast but may not
|
8
|
+
# work correctly on all SysV platforms. This method should be overridden by
|
9
|
+
# more specific drivers when reasonable.
|
10
|
+
#
|
11
|
+
# It does not implement the #enable and #disable methods because these are
|
12
|
+
# not standardized and must be implemented using platform-specific drivers,
|
13
|
+
# e.g., Chkconfig on RedHat-like platforms.
|
14
|
+
class AutomateIt::ServiceManager::SYSV < AutomateIt::ServiceManager::BaseDriver
|
15
|
+
ETC_INITD = "/etc/init.d"
|
16
|
+
|
17
|
+
depends_on :directories => [ETC_INITD]
|
18
|
+
|
19
|
+
def suitability(method, *args) # :nodoc:
|
20
|
+
return 0 if %w(enabled? enable disable).include?(method.to_s)
|
21
|
+
return available? ? 1 : 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def _run_command(args, opts={})
|
25
|
+
_raise_unless_available
|
26
|
+
cmd = String === args ? args : args.join(' ')
|
27
|
+
if opts[:silent] or opts[:check]
|
28
|
+
cmd += " > /dev/null 2>&1" # Discard STDOUT and STDERR
|
29
|
+
elsif opts[:quiet]
|
30
|
+
cmd += " > /dev/null" # Discard only STDOUT
|
31
|
+
end
|
32
|
+
|
33
|
+
level = (opts[:quiet] || opts[:silent] || opts[:check]) ? :debug : :info
|
34
|
+
log.send(level, PEXEC+cmd)
|
35
|
+
if writing? or opts[:check]
|
36
|
+
system(cmd)
|
37
|
+
return $?.exitstatus.zero?
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
private :_run_command
|
43
|
+
|
44
|
+
# See ServiceManager#tell
|
45
|
+
def tell(service, action, opts={})
|
46
|
+
sudo = opts[:sudo] ? 'sudo' : ''
|
47
|
+
return _run_command(["#{sudo} #{ETC_INITD}/#{service}", action.to_s], opts)
|
48
|
+
end
|
49
|
+
|
50
|
+
# See ServiceManager#running?
|
51
|
+
def running?(service, opts={})
|
52
|
+
return started?(service, opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def _started_and_stopped_helper(kind, service, opts={})
|
56
|
+
expected = \
|
57
|
+
case kind
|
58
|
+
when :started?
|
59
|
+
true
|
60
|
+
when :stopped?
|
61
|
+
false
|
62
|
+
else
|
63
|
+
raise ArgumentError.new("unknown kind argument: #{kind}")
|
64
|
+
end
|
65
|
+
|
66
|
+
result = tell(service, :status, :check => true)
|
67
|
+
nitpick("_sash top: k=%s r=%s e=%s" % [kind, result, expected])
|
68
|
+
return result if expected == result
|
69
|
+
if opts[:wait]
|
70
|
+
timeout = Time.now + opts[:wait]
|
71
|
+
while timeout > Time.now
|
72
|
+
log.info(PNOTE+" ServiceManager#%s waiting on '%s' for %0.1f more seconds" %
|
73
|
+
[kind, service, timeout - Time.now])
|
74
|
+
sleep 0.5
|
75
|
+
result = tell(service, :status, :check => true)
|
76
|
+
nitpick("_sash rep: k=%s r=%s e=%s" % [kind, result, expected])
|
77
|
+
break if expected == result
|
78
|
+
end
|
79
|
+
log.info(PNOTE+" ServiceManager#%s finished waiting for '%s', got: %s" %
|
80
|
+
[kind, service, result])
|
81
|
+
end
|
82
|
+
return result
|
83
|
+
end
|
84
|
+
protected :_started_and_stopped_helper
|
85
|
+
|
86
|
+
# See ServiceManager#started?
|
87
|
+
def started?(service, opts={})
|
88
|
+
return _started_and_stopped_helper(:started?, service, opts)
|
89
|
+
end
|
90
|
+
|
91
|
+
# See ServiceManager#stopped?
|
92
|
+
def stopped?(service, opts={})
|
93
|
+
return ! _started_and_stopped_helper(:stopped?, service, opts)
|
94
|
+
end
|
95
|
+
|
96
|
+
# See ServiceManager#start
|
97
|
+
def start(service, opts={})
|
98
|
+
if not opts[:force] and started?(service, :wait => opts[:wait])
|
99
|
+
# Already started
|
100
|
+
return false
|
101
|
+
else
|
102
|
+
# Needs starting or forced
|
103
|
+
tell(service, :start, opts)
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# See ServiceManager#stop
|
109
|
+
def stop(service, opts={})
|
110
|
+
if not opts[:force] and stopped?(service, :wait => opts[:wait])
|
111
|
+
# Already stopped
|
112
|
+
return false
|
113
|
+
else
|
114
|
+
# Needs stopping or forced
|
115
|
+
tell(service, :stop, opts)
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# See ServiceManager#restart
|
121
|
+
def restart(service, opts={})
|
122
|
+
if started?(service, :wait => opts[:pause])
|
123
|
+
# We're certain that service is started
|
124
|
+
stop_opts = opts.clone
|
125
|
+
stop_opts[:force] = true # Don't check again
|
126
|
+
stop(service, stop_opts)
|
127
|
+
end
|
128
|
+
|
129
|
+
# We're certain that service is stopped
|
130
|
+
start_opts = opts.clone
|
131
|
+
start_opts[:force] = true # Don't check again
|
132
|
+
return start(service, start_opts)
|
133
|
+
end
|
134
|
+
|
135
|
+
# See ServiceManager#enabled?
|
136
|
+
def enabled?(service)
|
137
|
+
return ! Dir["/etc/rc*.d/*"].grep(/\/S\d{2}#{service}$/).empty?
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# == ServiceManager::UpdateRCD
|
2
|
+
#
|
3
|
+
# The UpdateRCD driver implements the ServiceManager methods for #enabled?,
|
4
|
+
# #enable and #disable on Debian-like platforms. It uses the SYSV driver
|
5
|
+
# for handling the methods #running?, #start and #stop.
|
6
|
+
class AutomateIt::ServiceManager::UpdateRCD < AutomateIt::ServiceManager::SYSV
|
7
|
+
TOOL = "update-rc.d"
|
8
|
+
|
9
|
+
depends_on :programs => [TOOL]
|
10
|
+
|
11
|
+
def suitability(method, *args) # :nodoc:
|
12
|
+
return available? ? 3 : 0
|
13
|
+
end
|
14
|
+
|
15
|
+
# See ServiceManager#enable
|
16
|
+
def enable(service, opts={})
|
17
|
+
_raise_unless_available
|
18
|
+
return false if enabled?(service)
|
19
|
+
interpreter.sh("#{TOOL} #{service} defaults < /dev/null > /dev/null")
|
20
|
+
end
|
21
|
+
|
22
|
+
# See ServiceManager#disable
|
23
|
+
def disable(service, opts={})
|
24
|
+
_raise_unless_available
|
25
|
+
return false unless enabled?(service)
|
26
|
+
interpreter.sh("#{TOOL} -f #{service} remove < /dev/null > /dev/null")
|
27
|
+
end
|
28
|
+
|
29
|
+
def enabled?(service, opts={})
|
30
|
+
_raise_unless_available
|
31
|
+
cmd = "#{TOOL} -n -f #{service} remove < /dev/null"
|
32
|
+
output = `#{cmd}`
|
33
|
+
return ! output.match(/etc\/rc[\dS].d|Nothing to do\./).nil?
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# == ShellManager
|
2
|
+
#
|
3
|
+
# The ShellManager provides Unix-like shell commands for manipulating files and
|
4
|
+
# executing commands.
|
5
|
+
#
|
6
|
+
# *WARNING*: Previewing code can be dangerous. Read
|
7
|
+
# previews.txt[link:files/docs/previews_txt.html] for instructions on how to
|
8
|
+
# write code that can be safely previewed.
|
9
|
+
class AutomateIt::ShellManager < AutomateIt::Plugin::Manager
|
10
|
+
alias_methods :backup, :sh, :which, :which!, :mktemp, :mktempdir, :mktempdircd, :chperm, :umask
|
11
|
+
alias_methods :cd, :pwd, :mkdir, :mkdir_p, :rmdir, :ln, :ln_s, :ln_sf, :cp, :cp_r, :cp_R, :mv, :rm, :rm_r, :rm_rf, :install, :chmod, :chmod_R, :chown, :chown_R, :touch
|
12
|
+
|
13
|
+
#...[ Detection commands ]..............................................
|
14
|
+
|
15
|
+
# See ShellManager#provides_mode?
|
16
|
+
def provides_mode?() dispatch_safely end
|
17
|
+
|
18
|
+
# See ShellManager#provides_mode?
|
19
|
+
def provides_ownership?() dispatch_safely end
|
20
|
+
|
21
|
+
# See ShellManager#provides_mode?
|
22
|
+
def provides_symlink?() dispatch_safely end
|
23
|
+
|
24
|
+
# See ShellManager#provides_mode?
|
25
|
+
def provides_link?() dispatch_safely end
|
26
|
+
|
27
|
+
#...[ Custom commands ].................................................
|
28
|
+
|
29
|
+
# Backup +sources+ if they exist. Returns the names of the backups created.
|
30
|
+
#
|
31
|
+
# Options:
|
32
|
+
# * :quiet -- Don't display output? Default is false.
|
33
|
+
#
|
34
|
+
# These backups are copies of the original sources saved into the same
|
35
|
+
# directories as the originals. The pathnames of these copies are timestamped
|
36
|
+
# and guaranteed to be unique, so you can have multiple backups of the same
|
37
|
+
# sources.
|
38
|
+
#
|
39
|
+
# *WARNING*: This method is not conditional. It will make a backup every time
|
40
|
+
# it's called if the sources exist. Therefore, only execute this method when
|
41
|
+
# its needed.
|
42
|
+
#
|
43
|
+
# For example, backup a file:
|
44
|
+
#
|
45
|
+
# backup("/tmp/myfile") # => "/tmp/myfile.1190994237_M2xhLrC6Sj.bak
|
46
|
+
#
|
47
|
+
# In the above example, the backup's name contains two special strings. The
|
48
|
+
# "1190994237" is the time the backup was made in seconds since the Epoch.
|
49
|
+
# The "M2xhLrC6Sj" is a random string used to guarantee the uniqueness of
|
50
|
+
# this backup in case two are made at exactly the same time.
|
51
|
+
def backup(*sources) dispatch(*sources) end
|
52
|
+
|
53
|
+
# Execute a shell command.
|
54
|
+
def sh(*commands) dispatch(*commands) end
|
55
|
+
|
56
|
+
# What is the path for this command? Returns +nil+ if command isn't found.
|
57
|
+
#
|
58
|
+
# Example:
|
59
|
+
# which("ls") # => "/bin/ls"
|
60
|
+
def which(command) dispatch(command) end
|
61
|
+
|
62
|
+
# Same as #which but throws an ArgumentError if command isn't found.
|
63
|
+
def which!(command) dispatch(command) end
|
64
|
+
|
65
|
+
# Creates a temporary file. Optionally takes a +name+ argument which is
|
66
|
+
# purely cosmetic, e.g., if the +name+ is "foo", the routine may create a
|
67
|
+
# temporary file named <tt>/tmp/foo_qeKo7nJk1s</tt>.
|
68
|
+
#
|
69
|
+
# When called with a block, invokes the block with the path of the temporary
|
70
|
+
# file and deletes the file at the end of the block.
|
71
|
+
#
|
72
|
+
# Without a block, returns the path of the temporary file and you're
|
73
|
+
# responsible for removing it when done.
|
74
|
+
def mktemp(name=nil, &block) # :yields: path
|
75
|
+
dispatch(name, &block)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a temporary directory. See #mktemp for details on the +name+
|
79
|
+
# argument.
|
80
|
+
#
|
81
|
+
# When called with a block, invokes the block with the path of the
|
82
|
+
# temporary directory and recursively deletes the directory and its
|
83
|
+
# contents at the end of the block.
|
84
|
+
#
|
85
|
+
# Without a block, returns the path of the temporary directory and you're
|
86
|
+
# responsible for removing it when done.
|
87
|
+
#
|
88
|
+
# CAUTION: Read notes at the top of ShellManager for potentially
|
89
|
+
# problematic situations that may be encountered if using this command in
|
90
|
+
# preview mode!
|
91
|
+
def mktempdir(name=nil, &block) # :yields: path
|
92
|
+
dispatch(name, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Same as #mktempdir but performs a #cd into the directory for the duration
|
96
|
+
# of the block.
|
97
|
+
#
|
98
|
+
# Example:
|
99
|
+
#
|
100
|
+
# puts pwd # => "/home/bubba"
|
101
|
+
# mktempdircd do |path|
|
102
|
+
# puts path # => "/tmp/tempster_qeKo7nJk1s"
|
103
|
+
# puts pwd # => "/tmp/tempster_qeKo7nJk1s"
|
104
|
+
# end
|
105
|
+
# puts File.exists?("/tmp/tempster_qeKo7nJk1s") # => false
|
106
|
+
def mktempdircd(name=nil, &block) # :yields: path
|
107
|
+
dispatch(name, &block)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Change the permissions of the +targets+. This command is like the #chmod
|
111
|
+
# and #chown in a single command.
|
112
|
+
#
|
113
|
+
# Options:
|
114
|
+
# * :recursive -- Change files and directories recursively. Defaults to false.
|
115
|
+
# * :user -- User name to change ownership to.
|
116
|
+
# * :group -- Group name to change ownership to.
|
117
|
+
# * :mode -- Mode to use as octal, e.g., <tt>0400</tt> to make a file
|
118
|
+
# readable only to its owner.
|
119
|
+
# * :details -- Reports the files modified, rather than the arguments
|
120
|
+
# modified. An argument might be a single directory, but this may result in
|
121
|
+
# modifications to many files within that directory. Use :details for
|
122
|
+
# situations when there's a need to see all files actually changed. The
|
123
|
+
# reason :details is off by default is that it will flood the screen with a
|
124
|
+
# list of all files modified in a large directory, which is overwhelming
|
125
|
+
# and probably unnecessary unless you actually need to see these details.
|
126
|
+
# Defaults to false.
|
127
|
+
def chperm(targets, opts={}) dispatch(targets, opts) end
|
128
|
+
|
129
|
+
# Set the umask to +mode+. If given a block, changes the umask only for the
|
130
|
+
# duration of the block and changes it back to its previous setting at the
|
131
|
+
# end.
|
132
|
+
def umask(mode=nil, &block) dispatch(mode, &block) end
|
133
|
+
|
134
|
+
#...[ FileUtils wrappers ]...............................................
|
135
|
+
|
136
|
+
# Changes the directory into the specified +dir+. If called with a block,
|
137
|
+
# changes to the directory for the duration of the block, and then changes
|
138
|
+
# back to the previous directory at the end.
|
139
|
+
#
|
140
|
+
# *WARNING*: Previewing code can be dangerous. Read
|
141
|
+
# previews.txt[link:files/docs/previews_txt.html] for instructions on how to
|
142
|
+
# write code that can be safely previewed.
|
143
|
+
def cd(dir, opts={}, &block) dispatch(dir, opts, &block) end
|
144
|
+
|
145
|
+
# Returns the current directory.
|
146
|
+
def pwd() dispatch() end
|
147
|
+
|
148
|
+
# Create a directory or directories. Returns an array of directories
|
149
|
+
# created or +false+ if all directories are already present.
|
150
|
+
#
|
151
|
+
# Options:
|
152
|
+
# * :parents -- Create parents, like "mkdir -p". Boolean.
|
153
|
+
# * :mode, :user, :group -- See #chperm
|
154
|
+
#
|
155
|
+
# *WARNING*: Previewing code can be dangerous. Read
|
156
|
+
# previews.txt[link:files/docs/previews_txt.html] for instructions on how to
|
157
|
+
# write code that can be safely previewed.
|
158
|
+
def mkdir(dirs, opts={}, &block) dispatch(dirs, &block) end
|
159
|
+
|
160
|
+
# Create a directory or directories with their parents. Returns an array of
|
161
|
+
# directories created or +false+ if all directories are already present.
|
162
|
+
#
|
163
|
+
# Options same as #mkdir.
|
164
|
+
#
|
165
|
+
# Example:
|
166
|
+
# File.exists?("/tmp/foo") # => false
|
167
|
+
# mkdir_p("/tmp/foo/bar")
|
168
|
+
# File.exists?("/tmp/foo") # => true
|
169
|
+
# File.exists?("/tmp/foo/bar") # => true
|
170
|
+
#
|
171
|
+
# *WARNING*: Previewing code can be dangerous. Read
|
172
|
+
# previews.txt[link:files/docs/previews_txt.html] for instructions on how to
|
173
|
+
# write code that can be safely previewed.
|
174
|
+
def mkdir_p(dirs, opts={}, &block) dispatch(dirs, &block) end
|
175
|
+
|
176
|
+
# Remove a directory or directories. The directories must be empty or an
|
177
|
+
# exception is thrown. Returns the directories removed or +false+ if none
|
178
|
+
# of the directories exist.
|
179
|
+
def rmdir(dirs) dispatch(dirs) end
|
180
|
+
|
181
|
+
# Create a hard link between the +source+ and +target+. Your platform must
|
182
|
+
# support hard links to use this. Returns the target created or +false+ if
|
183
|
+
# the link is already present.
|
184
|
+
def ln(source, target, opts={}) dispatch(source, target, opts) end
|
185
|
+
|
186
|
+
# Create a symbolic link between the +sources+ and +target+. Your platform
|
187
|
+
# must support symbolic links to use this. Returns an array of sources
|
188
|
+
# linked or +false+ if all are already present.
|
189
|
+
def ln_s(sources, target, opts={}) dispatch(sources, target, opts) end
|
190
|
+
|
191
|
+
# Create a symbolic link between the +sources+ and +target+. If the
|
192
|
+
# +target+ already exists, will remove it and recreate it. Your platform
|
193
|
+
# must support symbolic links to use this. Returns an array of sources
|
194
|
+
# linked or +false+ if all are already present.
|
195
|
+
def ln_sf(sources, target, opts={}) dispatch(sources, target, opts) end
|
196
|
+
|
197
|
+
# Copy the +sources+ to the +target+. Returns an array of sources copied or
|
198
|
+
# +false+ if all are present.
|
199
|
+
#
|
200
|
+
# Options:
|
201
|
+
# * :preserve -- Preserve file modification time and ownership. Defaults to
|
202
|
+
# false. Can be +true+, +false+, or :try. If :try, the properties will be
|
203
|
+
# preserved if possible on the platform, whereas +true+ will raise an
|
204
|
+
# exception if not available.
|
205
|
+
# * :recursive -- Copy files and directories recursively, boolean.
|
206
|
+
def cp(sources, target, opts={}) dispatch(sources, target, opts) end
|
207
|
+
|
208
|
+
# Copy the +sources+ to the +target+ recursively. Returns an array of
|
209
|
+
# sources copied or +false+ if all are present.
|
210
|
+
def cp_r(sources, target, opts={}) dispatch(sources, target, opts) end
|
211
|
+
|
212
|
+
# Copy the +sources+ to the +target+ recursively. Returns an array of
|
213
|
+
# sources copied or +false+ if all are present.
|
214
|
+
def cp_R(sources, target, opts={}) dispatch(sources, target, opts) end
|
215
|
+
|
216
|
+
# Move the +sources+ to the +target+. Returns an array of sources copied or
|
217
|
+
# +false+ if none of the sources exist.
|
218
|
+
def mv(sources, target) dispatch(sources, target) end
|
219
|
+
|
220
|
+
# Remove the +targets+. Returns a list of targets removed or +false+ if
|
221
|
+
# none of them exist.
|
222
|
+
def rm(targets, opts={}) dispatch(targets, opts) end
|
223
|
+
|
224
|
+
# Remove the +targets+ recursively. Returns a list of targets removed or
|
225
|
+
# +false+ if none of them exist.
|
226
|
+
def rm_r(targets, opts={}) dispatch(targets, opts) end
|
227
|
+
|
228
|
+
# Remove the +targets+ recursively and forcefully. Returns a list of
|
229
|
+
# targets removed or +false+ if none of them exist.
|
230
|
+
def rm_rf(targets, opts={}) dispatch(targets, opts) end
|
231
|
+
|
232
|
+
# Copy the +source+ to the +target+ and set its +mode+. Returns true if the
|
233
|
+
# file was installed or +false+ if already present.
|
234
|
+
def install(source, target, mode) dispatch(source, target, mode) end
|
235
|
+
|
236
|
+
# Change the permission +mode+ of the +targets+. Returns an array of
|
237
|
+
# targets modified or +false+ if all have the desired mode.
|
238
|
+
def chmod(mode, targets, opts={}) dispatch(mode, targets, opts) end
|
239
|
+
|
240
|
+
# Change the permission +mode+ of the +targets+ recursively. Returns an
|
241
|
+
# array of targets modified or +false+ if all have the desired mode.
|
242
|
+
def chmod_R(mode, targets, opts={}) dispatch(mode, targets, opts) end
|
243
|
+
|
244
|
+
# Change the +user+ and +group+ ownership of the +targets+. You can leave
|
245
|
+
# either the user or group as nil if you don't want to change it. Returns
|
246
|
+
# an array of targets modified or +false+ if all have the desired
|
247
|
+
# ownership.
|
248
|
+
def chown(user, group, targets, opts={}) dispatch(user, group, targets, opts) end
|
249
|
+
|
250
|
+
# Change the +user+ and +group+ ownership of the +targets+ recursively. You
|
251
|
+
# can leave either the user or group as nil if you don't want to change it.
|
252
|
+
# Returns an array of targets modified or +false+ if all have the desired
|
253
|
+
# ownership.
|
254
|
+
def chown_R(user, group, targets, opts={}) dispatch(user, group, targets, opts) end
|
255
|
+
|
256
|
+
# Create the +targets+ as files if needed and update their modification
|
257
|
+
# time. Unlike most other commands provided by ShellManager, this one will
|
258
|
+
# always modify the targets. Returns an array of targets modified.
|
259
|
+
#
|
260
|
+
# Options:
|
261
|
+
# * :like -- Touch the targets like this file. Defaults to none.
|
262
|
+
# * :stamp -- Set the targets to the specified timestamp. Defaults to Time.now.
|
263
|
+
def touch(targets, opts={}) dispatch(targets, opts) end
|
264
|
+
end
|
265
|
+
|
266
|
+
# == ShellManager::BaseDriver
|
267
|
+
#
|
268
|
+
# Base class for all ShellManager drivers.
|
269
|
+
class AutomateIt::ShellManager::BaseDriver < AutomateIt::Plugin::Driver
|
270
|
+
# Returns derived filename to use as a peer given the +source+ and +target+.
|
271
|
+
# This is necessary for differentiating between directory and file targets.
|
272
|
+
#
|
273
|
+
# For example:
|
274
|
+
#
|
275
|
+
# # Get the peer for an extant target directory:
|
276
|
+
# peer_for("foo", "/tmp") # => "/tmp/foo"
|
277
|
+
#
|
278
|
+
# # Get the peer for anything else:
|
279
|
+
# peer_for("foo", "/bar") # => "/bar"
|
280
|
+
def peer_for(source, target)
|
281
|
+
return FileUtils.send(:fu_each_src_dest0, source, target){|a, b| b}
|
282
|
+
end
|
283
|
+
|
284
|
+
protected
|
285
|
+
def _replace_owner_with_user(opts)
|
286
|
+
value = opts.delete(:owner)
|
287
|
+
opts[:user] = value if value and not opts[:user]
|
288
|
+
return opts
|
289
|
+
end
|
290
|
+
|
291
|
+
# Returns hash of verbosity and preview settings for FileUtils commands.
|
292
|
+
def _fileutils_opts
|
293
|
+
opts = {}
|
294
|
+
opts[:verbose] = false # Generate our own log messages
|
295
|
+
opts[:noop] = true if preview?
|
296
|
+
return opts
|
297
|
+
end
|
298
|
+
|
299
|
+
# Return array of all the directory's top-level contents, including hidden
|
300
|
+
# files with "." prefix on UNIX. Directories are returned just as a name,
|
301
|
+
# you'll need to expand those separately if needed.
|
302
|
+
def _directory_contents(directory)
|
303
|
+
return Dir[directory+"/{,.}*"].reject{|t| t =~ /(^|#{File::SEPARATOR})\.{1,2}$/}
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Drivers
|
308
|
+
require 'automateit/shell_manager/portable'
|
309
|
+
|
310
|
+
require 'automateit/shell_manager/which_base'
|
311
|
+
require 'automateit/shell_manager/which_unix'
|
312
|
+
require 'automateit/shell_manager/which_windows'
|
313
|
+
|
314
|
+
require 'automateit/shell_manager/base_link'
|
315
|
+
require 'automateit/shell_manager/symlink'
|
316
|
+
require 'automateit/shell_manager/link'
|