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,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'