automateit 0.70923

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 (119) hide show
  1. data.tar.gz.sig +1 -0
  2. data/CHANGES.txt +100 -0
  3. data/Hoe.rake +35 -0
  4. data/Manifest.txt +111 -0
  5. data/README.txt +44 -0
  6. data/Rakefile +284 -0
  7. data/TESTING.txt +57 -0
  8. data/TODO.txt +26 -0
  9. data/TUTORIAL.txt +390 -0
  10. data/bin/ai +3 -0
  11. data/bin/aifield +82 -0
  12. data/bin/aitag +128 -0
  13. data/bin/automateit +117 -0
  14. data/docs/friendly_errors.txt +50 -0
  15. data/docs/previews.txt +86 -0
  16. data/env.sh +4 -0
  17. data/examples/basic/Rakefile +26 -0
  18. data/examples/basic/config/automateit_env.rb +16 -0
  19. data/examples/basic/config/fields.yml +3 -0
  20. data/examples/basic/config/tags.yml +13 -0
  21. data/examples/basic/dist/README.txt +9 -0
  22. data/examples/basic/dist/myapp_server.erb +30 -0
  23. data/examples/basic/install.log +15 -0
  24. data/examples/basic/lib/README.txt +10 -0
  25. data/examples/basic/recipes/README.txt +4 -0
  26. data/examples/basic/recipes/install.rb +53 -0
  27. data/examples/basic/recipes/uninstall.rb +6 -0
  28. data/gpl.txt +674 -0
  29. data/lib/automateit.rb +66 -0
  30. data/lib/automateit/account_manager.rb +106 -0
  31. data/lib/automateit/account_manager/linux.rb +171 -0
  32. data/lib/automateit/account_manager/passwd.rb +69 -0
  33. data/lib/automateit/account_manager/portable.rb +136 -0
  34. data/lib/automateit/address_manager.rb +165 -0
  35. data/lib/automateit/address_manager/linux.rb +80 -0
  36. data/lib/automateit/address_manager/portable.rb +37 -0
  37. data/lib/automateit/cli.rb +80 -0
  38. data/lib/automateit/common.rb +65 -0
  39. data/lib/automateit/constants.rb +33 -0
  40. data/lib/automateit/edit_manager.rb +292 -0
  41. data/lib/automateit/error.rb +10 -0
  42. data/lib/automateit/field_manager.rb +103 -0
  43. data/lib/automateit/interpreter.rb +641 -0
  44. data/lib/automateit/package_manager.rb +242 -0
  45. data/lib/automateit/package_manager/apt.rb +63 -0
  46. data/lib/automateit/package_manager/egg.rb +64 -0
  47. data/lib/automateit/package_manager/gem.rb +179 -0
  48. data/lib/automateit/package_manager/portage.rb +69 -0
  49. data/lib/automateit/package_manager/yum.rb +65 -0
  50. data/lib/automateit/platform_manager.rb +47 -0
  51. data/lib/automateit/platform_manager/darwin.rb +30 -0
  52. data/lib/automateit/platform_manager/debian.rb +26 -0
  53. data/lib/automateit/platform_manager/freebsd.rb +25 -0
  54. data/lib/automateit/platform_manager/gentoo.rb +26 -0
  55. data/lib/automateit/platform_manager/lsb.rb +40 -0
  56. data/lib/automateit/platform_manager/struct.rb +78 -0
  57. data/lib/automateit/platform_manager/uname.rb +29 -0
  58. data/lib/automateit/platform_manager/windows.rb +33 -0
  59. data/lib/automateit/plugin.rb +7 -0
  60. data/lib/automateit/plugin/base.rb +32 -0
  61. data/lib/automateit/plugin/driver.rb +218 -0
  62. data/lib/automateit/plugin/manager.rb +232 -0
  63. data/lib/automateit/project.rb +460 -0
  64. data/lib/automateit/root.rb +14 -0
  65. data/lib/automateit/service_manager.rb +79 -0
  66. data/lib/automateit/service_manager/chkconfig.rb +39 -0
  67. data/lib/automateit/service_manager/rc_update.rb +37 -0
  68. data/lib/automateit/service_manager/sysv.rb +126 -0
  69. data/lib/automateit/service_manager/update_rcd.rb +35 -0
  70. data/lib/automateit/shell_manager.rb +261 -0
  71. data/lib/automateit/shell_manager/base_link.rb +67 -0
  72. data/lib/automateit/shell_manager/link.rb +24 -0
  73. data/lib/automateit/shell_manager/portable.rb +421 -0
  74. data/lib/automateit/shell_manager/symlink.rb +32 -0
  75. data/lib/automateit/shell_manager/which.rb +25 -0
  76. data/lib/automateit/tag_manager.rb +63 -0
  77. data/lib/automateit/tag_manager/struct.rb +101 -0
  78. data/lib/automateit/tag_manager/tag_parser.rb +91 -0
  79. data/lib/automateit/tag_manager/yaml.rb +29 -0
  80. data/lib/automateit/template_manager.rb +55 -0
  81. data/lib/automateit/template_manager/base.rb +172 -0
  82. data/lib/automateit/template_manager/erb.rb +17 -0
  83. data/lib/ext/metaclass.rb +17 -0
  84. data/lib/ext/object.rb +18 -0
  85. data/lib/hashcache.rb +22 -0
  86. data/lib/helpful_erb.rb +63 -0
  87. data/lib/nested_error.rb +33 -0
  88. data/lib/queued_logger.rb +68 -0
  89. data/lib/tempster.rb +239 -0
  90. data/misc/index_gem_repository.rb +303 -0
  91. data/misc/setup_egg.rb +12 -0
  92. data/misc/setup_gem_dependencies.sh +7 -0
  93. data/misc/setup_rubygems.sh +21 -0
  94. data/misc/which.cmd +6 -0
  95. data/spec/extras/automateit_service_sysv_test +50 -0
  96. data/spec/extras/scratch.rb +15 -0
  97. data/spec/extras/simple_recipe.rb +8 -0
  98. data/spec/integration/account_manager_spec.rb +218 -0
  99. data/spec/integration/address_manager_linux_spec.rb +119 -0
  100. data/spec/integration/address_manager_portable_spec.rb +30 -0
  101. data/spec/integration/cli_spec.rb +215 -0
  102. data/spec/integration/examples_spec.rb +54 -0
  103. data/spec/integration/examples_spec_editor.rb +71 -0
  104. data/spec/integration/package_manager_spec.rb +104 -0
  105. data/spec/integration/platform_manager_spec.rb +69 -0
  106. data/spec/integration/service_manager_sysv_spec.rb +115 -0
  107. data/spec/integration/shell_manager_spec.rb +471 -0
  108. data/spec/integration/template_manager_erb_spec.rb +31 -0
  109. data/spec/spec_helper.rb +23 -0
  110. data/spec/unit/edit_manager_spec.rb +162 -0
  111. data/spec/unit/field_manager_spec.rb +79 -0
  112. data/spec/unit/hashcache_spec.rb +28 -0
  113. data/spec/unit/interpreter_spec.rb +98 -0
  114. data/spec/unit/platform_manager_spec.rb +44 -0
  115. data/spec/unit/plugins_spec.rb +253 -0
  116. data/spec/unit/tag_manager_spec.rb +189 -0
  117. data/spec/unit/template_manager_erb_spec.rb +137 -0
  118. metadata +249 -0
  119. metadata.gz.sig +0 -0
@@ -0,0 +1,242 @@
1
+ # == PackageManager
2
+ #
3
+ # The PackageManager provides a way to manage packages, e.g., install,
4
+ # uninstall and query if the Apache package is installed with APT.
5
+ #
6
+ # Examples:
7
+ #
8
+ # package_manager.installed?("apache2") # => false
9
+ # package_manager.install("apache2") # => true
10
+ # package_manager.installed?("apache2") # => true
11
+ # package_manager.uninstall("apache2") # => true
12
+ # package_manager.not_installed("apache2") # => true
13
+ #
14
+ # Commands can accept arrays:
15
+ #
16
+ # package_manager.install("apache2", "bash")
17
+ # package_manager.installed? %w(apache2 bash)
18
+ #
19
+ # Commands can also accept a single, annotated string as a manifest -- useful
20
+ # for installing large numbers of packages at once:
21
+ #
22
+ # package_manager.install <<HERE, :with => :apt
23
+ # # One per line
24
+ # apache
25
+ # bash
26
+ #
27
+ # # Or many on the same line
28
+ # sysvconfig sysv-rc-conf
29
+ # HERE
30
+ #
31
+ # Commands can also accept a hash of names to paths -- necessary for installing
32
+ # packages stored on the filesystem:
33
+ #
34
+ # # Is the package called "TracTags" installed? If not, run the installer
35
+ # # with the "/tmp/tractags_latest" path as an argument:
36
+ # package.manager.install({"TracTags" => "/tmp/tractags_latest"}, :with => :egg)
37
+ class AutomateIt::PackageManager < AutomateIt::Plugin::Manager
38
+ # Alias for #install
39
+ def add(*packages) dispatch_to(:install, *packages) end
40
+
41
+ # Alias for #uninstall
42
+ def remove(*packages) dispatch_to(:uninstall, *packages) end
43
+
44
+ # Are these +packages+ installed?
45
+ #
46
+ # Options:
47
+ # * :details -- Returns an array containing the boolean result value and an
48
+ # array with a subset of installed +packages+. Boolean, defaults to false.
49
+ def installed?(*packages) dispatch(*packages) end
50
+
51
+ # Are these +packages+ not installed?
52
+ #
53
+ # Options:
54
+ # * :details -- Returns an array containing the boolean result value and an
55
+ # array with a subset of +packages+ not installed. Boolean, defaults to false.
56
+ def not_installed?(*packages) dispatch(*packages) end
57
+
58
+ # Install these +packages+. Returns +true+ if any packages are installed
59
+ # successfully; or +false+ if all packages were already installed.
60
+ def install(*packages) dispatch(*packages) end
61
+
62
+ # Uninstall these +packages+. Returns +true+ if any packages are uninstalled
63
+ # successfully; or +false+ if none of the packages are installed.
64
+ def uninstall(*packages) dispatch(*packages) end
65
+ end
66
+
67
+ # == PackageManager::BaseDriver
68
+ #
69
+ # Base class for all PackageManager drivers.
70
+ class AutomateIt::PackageManager::BaseDriver < AutomateIt::Plugin::Driver
71
+ protected
72
+
73
+ # Are these +packages+ installed? Works like PackageManager#installed?
74
+ # but calls a block that actually checks whether the packages are
75
+ # installed and returns an array of packages installed.
76
+ #
77
+ # For example:
78
+ # _installed_helper?("package1", "package2", :details => true) do |packages, opts|
79
+ # # Dummy code which reports that these packages are installed:
80
+ # ["package1]
81
+ # end
82
+ def _installed_helper?(*packages, &block) # :yields: filtered_packages, opts
83
+ _raise_unless_available
84
+
85
+ packages, opts = args_and_opts(*packages)
86
+ packages = _list_normalizer(packages)
87
+ packages = packages.keys if Hash === packages
88
+
89
+ available = block.call(packages, opts)
90
+ truth = (packages - available).empty?
91
+ result = opts[:details] ? [truth, available] : truth
92
+ log.debug(PNOTE+"installed?(#{packages.inspect}) => #{truth}: #{available.inspect}")
93
+ return result
94
+ end
95
+
96
+ # Are these +packages+ not installed?
97
+ def _not_installed_helper?(*packages)
98
+ _raise_unless_available
99
+
100
+ # Requires that your PackageManager#installed? method is implemented.
101
+ packages, opts = args_and_opts(*packages)
102
+ packages = _list_normalizer(packages)
103
+ packages = packages.keys if Hash === packages
104
+
105
+ available = [installed?(packages, :details => true)].flatten
106
+ missing = packages - available
107
+ truth = (packages - missing).empty?
108
+ result = opts[:details] ? [truth, missing] : truth
109
+ log.debug(PNOTE+"not_installed?(#{packages.inspect}) => #{truth}: #{missing.inspect}")
110
+ return result
111
+ end
112
+
113
+ # Install these +packages+. Works like PackageManager#install but calls a
114
+ # block that's responsible for actually installing the packages and
115
+ # returning true if the installation succeeded. This block is only called
116
+ # if packages need to be installed and receives a filtered list of
117
+ # packages that are guaranteed not to be installed on the system already.
118
+ #
119
+ # For example:
120
+ # _install_helper("package1", "package2", :quiet => true) do |packages, opts|
121
+ # # Dummy code that installs packages here, e.g:
122
+ # system("apt-get", "install", "-y", packages)
123
+ # end
124
+ def _install_helper(*packages, &block) # :yields: filtered_packages, opts
125
+ _raise_unless_available
126
+
127
+ packages, opts = args_and_opts(*packages)
128
+ packages = _list_normalizer(packages)
129
+
130
+ check_packages = \
131
+ case packages
132
+ when Hash: packages.keys
133
+ else packages
134
+ end
135
+
136
+ missing = not_installed?(check_packages, :details => true)[1]
137
+ return false if missing.blank?
138
+
139
+ install_packages = \
140
+ case packages
141
+ when Hash: missing.map{|t| packages[t]}
142
+ else missing
143
+ end
144
+ block.call(install_packages, opts)
145
+
146
+ return true if preview?
147
+ unless (failed = not_installed?(check_packages, :details => true)[1]).empty?
148
+ raise ArgumentError.new("Couldn't install: #{failed.join(' ')}")
149
+ else
150
+ return true
151
+ end
152
+ end
153
+
154
+ # Uninstall these +packages+. Works like PackageManager#uninstall but calls a
155
+ # block that's responsible for actually uninstalling the packages and
156
+ # returning true if the uninstall succeeded. This block is only called
157
+ # if packages need to be uninstalled and receives a filtered list of
158
+ # packages that are guaranteed to be installed on the system.
159
+ #
160
+ # For example:
161
+ # _uninstall_helper("package1", "package2", :quiet => true) do |packages, opts|
162
+ # # Dummy code that removes packages here, e.g:
163
+ # system("apt-get", "remove", "-y", packages)
164
+ # end
165
+ def _uninstall_helper(*packages, &block) # :yields: filtered_packages, opts
166
+ _raise_unless_available
167
+
168
+ packages, opts = args_and_opts(*packages)
169
+ packages = _list_normalizer(packages)
170
+
171
+ check_packages = \
172
+ case packages
173
+ when Hash: packages.keys
174
+ else packages
175
+ end
176
+
177
+ present = installed?(check_packages, :details => true)[1]
178
+ return false if present.blank?
179
+
180
+ uninstall_packages = \
181
+ case packages
182
+ when Hash: present.map{|t| packages[t]}
183
+ else present
184
+ end
185
+ block.call(uninstall_packages, opts)
186
+
187
+ return true if preview?
188
+ unless (failed = installed?(check_packages, :details => true)[1]).empty?
189
+ raise ArgumentError.new("Couldn't uninstall: #{failed.join(' ')}")
190
+ else
191
+ return true
192
+ end
193
+ end
194
+
195
+ # Returns a normalized array of packages. Transforms manifest string into
196
+ # packages. Turns symbols into string, strips blank lines and comments.
197
+ def _list_normalizer(*packages)
198
+ packages = [packages].flatten
199
+ if packages.size == 1
200
+ packages = packages.first
201
+ nitpick "LN SI %s" % packages.inspect
202
+ nitpick "LN Sc %s" % packages.class
203
+ case packages
204
+ when Symbol
205
+ nitpick "LN Sy"
206
+ packages = packages.to_s
207
+ when String
208
+ nitpick "LN Ss"
209
+ packages = packages.grep(LIST_NORMALIZER_RE).join(" ").split
210
+ when Hash
211
+ # Don't do anything
212
+ nitpick "LN Sh"
213
+ else
214
+ nitpick "LN S?"
215
+ raise TypeError.new("Unknown input type: #{packages.class}")
216
+ end
217
+ nitpick "LN SO %s" % packages.inspect
218
+ end
219
+
220
+ case packages
221
+ when Array
222
+ result = packages.map(&:to_s).grep(LIST_NORMALIZER_RE)
223
+ when Hash
224
+ result = packages.stringify_keys
225
+ else
226
+ raise TypeError.new("Unknown input type: #{packages.class}")
227
+ end
228
+
229
+ nitpick "LN RR %s" % result.inspect
230
+ return result
231
+ end
232
+
233
+ # Expression for matching packages in arguments
234
+ LIST_NORMALIZER_RE = /^\s*([^\s#]+)/
235
+ end
236
+
237
+ # Drivers
238
+ require 'automateit/package_manager/apt'
239
+ require 'automateit/package_manager/yum'
240
+ require 'automateit/package_manager/gem'
241
+ require 'automateit/package_manager/egg'
242
+ require 'automateit/package_manager/portage'
@@ -0,0 +1,63 @@
1
+ # == PackageManager::APT
2
+ #
3
+ # The APT driver for the PackageManager provides a way to manage software
4
+ # packages on Debian-style systems using <tt>apt-get</tt> and <tt>dpkg</tt>.
5
+ class AutomateIt::PackageManager::APT < AutomateIt::PackageManager::BaseDriver
6
+ depends_on :programs => %w(apt-get dpkg)
7
+
8
+ def suitability(method, *args) # :nodoc:
9
+ return available? ? 1 : 0
10
+ end
11
+
12
+ # See AutomateIt::PackageManager#installed?
13
+ def installed?(*packages)
14
+ return _installed_helper?(*packages) do |list, opts|
15
+ ### data = `dpkg --status nomarch apache2 not_a_real_package 2>&1`
16
+ cmd = "dpkg --status "+list.join(" ")+" 2>&1"
17
+
18
+ log.debug(PEXEC+cmd)
19
+ data = `#{cmd}`
20
+ matches = data.scan(/^Package: (.+)$\s*^Status: (.+)$/)
21
+ available = matches.inject([]) do |sum, match|
22
+ package, status = match
23
+ sum << package if status.match(/(?:^|\s)installed\b/)
24
+ sum
25
+ end
26
+
27
+ available
28
+ end
29
+ end
30
+
31
+ # See AutomateIt::PackageManager#not_installed?
32
+ def not_installed?(*packages)
33
+ return _not_installed_helper?(*packages)
34
+ end
35
+
36
+ # See AutomateIt::PackageManager#install
37
+ def install(*packages)
38
+ return _install_helper(*packages) do |list, opts|
39
+ # apt-get options:
40
+ # -y : yes to all queries
41
+ # -q : no interactive progress bars
42
+ cmd = "export DEBIAN_FRONTEND=noninteractive; apt-get install -y -q "+list.join(" ")+" < /dev/null"
43
+ cmd << " > /dev/null" if opts[:quiet]
44
+ cmd << " 2>&1"
45
+
46
+ interpreter.sh(cmd)
47
+ end
48
+ end
49
+
50
+ # See AutomateIt::PackageManager#uninstall
51
+ def uninstall(*packages)
52
+ return _uninstall_helper(*packages) do |list, opts|
53
+ # apt-get options:
54
+ # -y : yes to all queries
55
+ # -q : no interactive progress bars
56
+ cmd = "export DEBIAN_FRONTEND=noninteractive; apt-get remove -y -q "+list.join(" ")+" < /dev/null"
57
+ cmd << " > /dev/null" if opts[:quiet]
58
+ cmd << " 2>&1"
59
+
60
+ interpreter.sh(cmd)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,64 @@
1
+ # == PackageManager::Egg
2
+ #
3
+ # The Egg driver for the PackageManager provides a way to manage
4
+ # Python software packages with the PEAK +easy_install+ tool.
5
+ class AutomateIt::PackageManager::Egg < AutomateIt::PackageManager::BaseDriver
6
+ depends_on :programs => %w(python easy_install)
7
+
8
+ def suitability(method, *args) # :nodoc:
9
+ # Never select as default driver
10
+ return 0
11
+ end
12
+
13
+ # See AutomateIt::PackageManager#installed?
14
+ def installed?(*packages)
15
+ return _installed_helper?(*packages) do |list, opts|
16
+ cmd = "python -c 'import sys; print(sys.path)' 2>&1"
17
+
18
+ log.debug(PEXEC+cmd)
19
+ data = `#{cmd}`
20
+ # Extract array elements, turn them into basenames, and then split on
21
+ # '-' because that's the separator for the name and version.
22
+ found = data.scan(/'([^']+\.egg)'/).flatten.map{|t| File.basename(t).split('-', 2)[0]}
23
+ available = found & list
24
+ end
25
+ end
26
+
27
+ # See AutomateIt::PackageManager#not_installed?
28
+ def not_installed?(*packages)
29
+ return _not_installed_helper?(*packages)
30
+ end
31
+
32
+ # See AutomateIt::PackageManager#install
33
+ def install(*packages)
34
+ return _install_helper(*packages) do |list, opts|
35
+ # easy_install options:
36
+ # -Z : install into a direcory rather than a file
37
+ cmd = "easy_install -Z "+list.join(" ")+" < /dev/null"
38
+ cmd << " > /dev/null" if opts[:quiet]
39
+ cmd << " 2>&1"
40
+
41
+ interpreter.sh(cmd)
42
+ end
43
+ end
44
+
45
+ # See AutomateIt::PackageManager#uninstall
46
+ def uninstall(*packages)
47
+ return _uninstall_helper(*packages) do |list, opts|
48
+ # easy_install options:
49
+ # -m : removes package from the easy-install.pth
50
+ cmd = "easy_install -m "+list.join(" ")+" < /dev/null"
51
+ cmd << " > /dev/null" if opts[:quiet]
52
+ cmd << " 2>&1"
53
+
54
+ # Parse output for paths and remove the orphaned entries
55
+ log.info(PEXEC+cmd)
56
+ return packages if preview?
57
+ data = `#{cmd}`
58
+ paths = data.scan(/^Using ([^\n]+\.egg)$/m).flatten
59
+ for path in paths
60
+ interpreter.rm_rf(path)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,179 @@
1
+ # == PackageManager::Gem
2
+ #
3
+ # The Gem driver for the PackageManager provides a way to manage software
4
+ # packages for RubyGems using the +gem+ command.
5
+ class AutomateIt::PackageManager::Gem < AutomateIt::PackageManager::BaseDriver
6
+ depends_on \
7
+ :programs => %w(gem),
8
+ :callbacks => [lambda{
9
+ # TODO PackageManager::Gem -- Misleading #depends_on makes entire driver unavailable, although only #install requires PTY.
10
+ begin
11
+ require 'expect'
12
+ require 'pty'
13
+ return true
14
+ rescue LoadError
15
+ return false
16
+ end
17
+ }]
18
+
19
+ def suitability(method, *args) # :nodoc:
20
+ # Never select GEM as the default driver
21
+ return 0
22
+ end
23
+
24
+ # See PackageManager#installed?
25
+ def installed?(*packages)
26
+ return _installed_helper?(*packages) do |list, opts|
27
+ cmd = "gem list --local 2>&1"
28
+
29
+ log.debug(PEXEC+cmd)
30
+ data = `#{cmd}`
31
+
32
+ # Gem lists packages out of order, which screws up the
33
+ # install/uninstall sequence, so we need to put them back in the
34
+ # order that the user specified.
35
+ present = data.scan(/^([^\s\(]+)\s+\([^\)]+\)\s*$/).flatten
36
+ available = []
37
+ for package in list
38
+ available << package if present.include?(package)
39
+ end
40
+ available
41
+ end
42
+ end
43
+
44
+ # See PackageManager#not_installed?
45
+ def not_installed?(*packages)
46
+ _not_installed_helper?(*packages)
47
+ end
48
+
49
+ # Special options:
50
+ # * :docs -- If set to false, won't install rdoc or ri.
51
+ # * :source -- URL source to retrieve Gems from.
52
+ #
53
+ # See PackageManager#install
54
+ def install(*packages)
55
+ return _install_helper(*packages) do |list, opts|
56
+ # Why is the "gem" utility such a steaming pile of offal? Lameness include:
57
+ # - Requires interactive input to install a package, with no way to prevent this
58
+ # - Repeatedly updates indexes even when there's no reason to, and can't be told to stop
59
+ # - Doesn't cache packages, insists on downloading them again
60
+ # - Installs broken packages, often without giving any indication of failure
61
+ # - Installs broken packages and leaves you to deal with the jagged pieces
62
+ # - Sometimes fails through exit status, sometimes through output, but not both and not consistently
63
+ # - Lacks a proper "is this package installed?" feature
64
+ # - A nightmare to deal with if you want to install your own GEMHOME/GEMPATH
65
+
66
+ # Example of an invalid gem that'll cause the failure I'm trying to avoid below:
67
+ # package_manager.install("sys-cpu", :with => :gem)
68
+
69
+ # gem options:
70
+ # -y : Include dependencies,
71
+ # -E : use /usr/bin/env for installed executables; but only with >= 0.9.4
72
+ cmd = "gem install -y"
73
+ cmd << " --no-ri" if opts[:ri] == false or opts[:docs] == false
74
+ cmd << " --no-rdoc" if opts[:rdoc] == false or opts[:docs] == false
75
+ cmd << " --source #{opts[:source]}" if opts[:source]
76
+ cmd << " "+list.join(" ")
77
+ cmd << " " << opts[:args] if opts[:args]
78
+ cmd << " 2>&1"
79
+
80
+ # XXX Try to warn the user that they won't see any output for a while
81
+ log.info(PNOTE+"Installing Gems, this will take a while...") if writing? and not opts[:quiet]
82
+ log.info(PEXEC+cmd)
83
+ return true if preview?
84
+
85
+ uninstall_needed = false
86
+ begin
87
+ require 'expect'
88
+ exitstruct = Open4::popen4(cmd) do |pid, sin, sout, serr|
89
+ $expect_verbose = opts[:quiet] ? false : true
90
+
91
+ re_missing=/Could not find.+in any repository/m
92
+ re_select=/Select which gem to install.+>/m
93
+ re_failed=/Gem files will remain.+for inspection/m
94
+ re_refused=/Errno::ECONNREFUSED reading .+?\.gem/m
95
+ re_all=/#{re_missing}|#{re_select}|#{re_failed}|#{re_refused}/m
96
+
97
+ while true
98
+ begin
99
+ captureded = sout.expect(re_all)
100
+ rescue NoMethodError
101
+ log.debug(PNOTE+"Gem seems to be done")
102
+ break
103
+ end
104
+ ### puts "Captureded %s" % captureded.inspect
105
+ captured = captureded.first
106
+ if captured.match(re_failed)
107
+ log.warn(PERROR+"Gem install failed mid-process")
108
+ uninstall_needed = true
109
+ break
110
+ elsif captured.match(re_refused)
111
+ log.warn(PERROR+"Gem install refused by server!\n#{captured}")
112
+ break
113
+ elsif captured.match(re_select)
114
+ choice = captured.match(/^ (\d+)\. .+?\(ruby\)\s*$/)[1]
115
+ log.info(PNOTE+"Guessing: #{choice}")
116
+ sin.puts(choice)
117
+ end
118
+ end
119
+ end
120
+ rescue Errno::ENOENT => e
121
+ raise NotImplementedError.new("can't find gem command: #{e}")
122
+ end
123
+
124
+ if uninstall_needed or not exitstruct.exitstatus.zero?
125
+ log.error(PERROR+"Gem install failed, trying to uninstall broken pieces: #{list.inspect}")
126
+ uninstall(list, opts)
127
+
128
+ raise ArgumentError.new("Gem install failed because it's invalid, missing a dependency, or can't talk with Gem server: #{list.inspect}")
129
+ end
130
+ end
131
+ end
132
+
133
+ # See PackageManager#uninstall
134
+ def uninstall(*packages)
135
+ return _uninstall_helper(*packages) do |list, opts|
136
+ # TODO PackageManager::gem#uninstall -- add logic to handle prompts during removal
137
+ =begin
138
+ # idiotic program MAY prompt you like this on uninstall:
139
+
140
+ Gem 0.9.4 generates prompts like this:
141
+ ** gem uninstall -x mongrel < /dev/null 2>&1
142
+
143
+ You have requested to uninstall the gem:
144
+ mongrel-1.0.1
145
+ mongrel_cluster-1.0.2 depends on [mongrel (>= 1.0.1)]
146
+ If you remove this gems, one or more dependencies will not be met.
147
+ Continue with Uninstall? [Yn] Successfully uninstalled mongrel version 1.0.1
148
+ Removing mongrel_rails
149
+
150
+ #-----------------------------------------------------------------------
151
+ Gem 0.9.0 generates prompts like this:
152
+ ** gem uninstall -x mongrel < /dev/null 2>&1
153
+
154
+ Select RubyGem to uninstall:
155
+ 1. mongrel-1.0.1
156
+ 2. mongrel_cluster-1.0.2
157
+ 3. All versions
158
+ > 3
159
+
160
+ You have requested to uninstall the gem:
161
+ mongrel-1.0.1
162
+ mongrel_cluster-1.0.2 depends on [mongrel (>= 1.0.1)]
163
+ If you remove this gems, one or more dependencies will not be met.
164
+ Continue with Uninstall? [Yn] y
165
+ Successfully uninstalled mongrel version 1.0.1
166
+ Successfully uninstalled mongrel_cluster version 1.0.2
167
+ root@ubuntu:/mnt/satori/svnwork/automateit/src/examples/myapp_rails#
168
+ =end
169
+ for package in list
170
+ # gem options:
171
+ # -x : remove installed executables
172
+ cmd = "gem uninstall -x #{package} < /dev/null"
173
+ cmd << " > /dev/null" if opts[:quiet]
174
+ cmd << " 2>&1"
175
+ interpreter.sh(cmd)
176
+ end
177
+ end
178
+ end
179
+ end