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,201 @@
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
+ #
6
+ # === Specifying version of gem to use
7
+ #
8
+ # You can specify the command to use with each call using the gem option, e.g., the "gem1.8" below:
9
+ #
10
+ # package_manager.install 'rails', :with => :gem, :gem => "gem1.8"
11
+ #
12
+ # Or set a default and all subsequent calls will use it:
13
+ #
14
+ # package_manager[:gem].setup(:gem => "gem1.8")
15
+ # package_manager.install 'rails', :with => :gem
16
+ class AutomateIt::PackageManager::Gem < AutomateIt::PackageManager::BaseDriver
17
+ attr_accessor :gem
18
+
19
+ # FIXME Can't tell which gem program is used until we can use #which, need a new paradigm for #available?
20
+ depends_on \
21
+ :libraries => %w(expect pty)
22
+ ### :programs => %w(gem),
23
+
24
+ def setup(*args)
25
+ super(*args)
26
+
27
+ args, opts = args_and_opts(*args)
28
+ if opts[:gem]
29
+ @gem = opts[:gem]
30
+ else
31
+ @gem ||= %w(gem gem1.8 gem1.9).inject(nil){|s,v| s ? s : interpreter.which(v)}
32
+ end
33
+ end
34
+
35
+ def suitability(method, *args) # :nodoc:
36
+ # Never select GEM as the default driver
37
+ return 0
38
+ end
39
+
40
+ # See PackageManager#installed?
41
+ def installed?(*packages)
42
+ return _installed_helper?(*packages) do |list, opts|
43
+ gem = opts[:gem] || self.gem
44
+ cmd = "#{gem} list --local 2>&1"
45
+
46
+ log.debug(PEXEC+cmd)
47
+ data = `#{cmd}`
48
+
49
+ # Gem lists packages out of order, which screws up the
50
+ # install/uninstall sequence, so we need to put them back in the
51
+ # order that the user specified.
52
+ present = data.scan(/^([^\s\(]+)\s+\([^\)]+\)\s*$/).flatten
53
+ available = []
54
+ for package in list
55
+ available << package if present.include?(package)
56
+ end
57
+ available
58
+ end
59
+ end
60
+
61
+ # See PackageManager#not_installed?
62
+ def not_installed?(*packages)
63
+ _not_installed_helper?(*packages)
64
+ end
65
+
66
+ # Special options:
67
+ # * :docs -- If set to false, won't install rdoc or ri.
68
+ # * :source -- URL source to retrieve Gems from.
69
+ #
70
+ # See PackageManager#install
71
+ def install(*packages)
72
+ return _install_helper(*packages) do |list, opts|
73
+ gem = opts[:gem] || self.gem
74
+
75
+ # Why is the "gem" utility such a steaming pile of offal? Lameness include:
76
+ # - Requires interactive input to install a package, with no way to prevent this
77
+ # - Repeatedly updates indexes even when there's no reason to, and can't be told to stop
78
+ # - Doesn't cache packages, insists on downloading them again
79
+ # - Installs broken packages, often without giving any indication of failure
80
+ # - Installs broken packages and leaves you to deal with the jagged pieces
81
+ # - Sometimes fails through exit status, sometimes through output, but not both and not consistently
82
+ # - Lacks a proper "is this package installed?" feature
83
+ # - A nightmare to deal with if you want to install your own GEMHOME/GEMPATH
84
+
85
+ # Example of an invalid gem that'll cause the failure I'm trying to avoid below:
86
+ # package_manager.install("sys-cpu", :with => :gem)
87
+
88
+ # gem options:
89
+ # -y : Include dependencies,
90
+ # -E : use /usr/bin/env for installed executables; but only with >= 0.9.4
91
+ cmd = "#{gem} install -y"
92
+ cmd << " --no-ri" if opts[:ri] == false or opts[:docs] == false
93
+ cmd << " --no-rdoc" if opts[:rdoc] == false or opts[:docs] == false
94
+ cmd << " --source #{opts[:source]}" if opts[:source]
95
+ cmd << " "+list.join(" ")
96
+ cmd << " " << opts[:args] if opts[:args]
97
+ cmd << " 2>&1"
98
+
99
+ # XXX Try to warn the user that they won't see any output for a while
100
+ log.info(PNOTE+"Installing Gems, this will take a while...") if writing? and not opts[:quiet]
101
+ log.info(PEXEC+cmd)
102
+ return true if preview?
103
+
104
+ uninstall_needed = false
105
+ begin
106
+ require 'expect'
107
+ require 'open4'
108
+ exitstruct = Open4::popen4(cmd) do |pid, sin, sout, serr|
109
+ $expect_verbose = opts[:quiet] ? false : true
110
+
111
+ re_missing=/Could not find.+in any repository/m
112
+ re_select=/Select which gem to install.+>/m
113
+ re_failed=/Gem files will remain.+for inspection/m
114
+ re_refused=/Errno::ECONNREFUSED reading .+?\.gem/m
115
+ re_all=/#{re_missing}|#{re_select}|#{re_failed}|#{re_refused}/m
116
+
117
+ while true
118
+ begin
119
+ captureded = sout.expect(re_all)
120
+ rescue NoMethodError
121
+ log.debug(PNOTE+"Gem seems to be done")
122
+ break
123
+ end
124
+ ### puts "Captureded %s" % captureded.inspect
125
+ captured = captureded.first
126
+ if captured.match(re_failed)
127
+ log.warn(PERROR+"Gem install failed mid-process")
128
+ uninstall_needed = true
129
+ break
130
+ elsif captured.match(re_refused)
131
+ log.warn(PERROR+"Gem install refused by server!\n#{captured}")
132
+ break
133
+ elsif captured.match(re_select)
134
+ choice = captured.match(/^ (\d+)\. .+?\(ruby\)\s*$/)[1]
135
+ log.info(PNOTE+"Guessing: #{choice}")
136
+ sin.puts(choice)
137
+ end
138
+ end
139
+ end
140
+ rescue Errno::ENOENT => e
141
+ raise NotImplementedError.new("can't find gem command: #{e}")
142
+ end
143
+
144
+ if uninstall_needed or not exitstruct.exitstatus.zero?
145
+ log.error(PERROR+"Gem install failed, trying to uninstall broken pieces: #{list.inspect}")
146
+ uninstall(list, opts)
147
+
148
+ raise ArgumentError.new("Gem install failed because it's invalid, missing a dependency, or can't talk with Gem server: #{list.inspect}")
149
+ end
150
+ end
151
+ end
152
+
153
+ # See PackageManager#uninstall
154
+ def uninstall(*packages)
155
+ return _uninstall_helper(*packages) do |list, opts|
156
+ gem = opts[:gem] || self.gem
157
+
158
+ # TODO PackageManager::gem#uninstall -- add logic to handle prompts during removal
159
+ =begin
160
+ # idiotic program MAY prompt you like this on uninstall:
161
+
162
+ Gem 0.9.4 generates prompts like this:
163
+ ** gem uninstall -x mongrel < /dev/null 2>&1
164
+
165
+ You have requested to uninstall the gem:
166
+ mongrel-1.0.1
167
+ mongrel_cluster-1.0.2 depends on [mongrel (>= 1.0.1)]
168
+ If you remove this gems, one or more dependencies will not be met.
169
+ Continue with Uninstall? [Yn] Successfully uninstalled mongrel version 1.0.1
170
+ Removing mongrel_rails
171
+
172
+ #-----------------------------------------------------------------------
173
+ Gem 0.9.0 generates prompts like this:
174
+ ** gem uninstall -x mongrel < /dev/null 2>&1
175
+
176
+ Select RubyGem to uninstall:
177
+ 1. mongrel-1.0.1
178
+ 2. mongrel_cluster-1.0.2
179
+ 3. All versions
180
+ > 3
181
+
182
+ You have requested to uninstall the gem:
183
+ mongrel-1.0.1
184
+ mongrel_cluster-1.0.2 depends on [mongrel (>= 1.0.1)]
185
+ If you remove this gems, one or more dependencies will not be met.
186
+ Continue with Uninstall? [Yn] y
187
+ Successfully uninstalled mongrel version 1.0.1
188
+ Successfully uninstalled mongrel_cluster version 1.0.2
189
+ root@ubuntu:/mnt/satori/svnwork/automateit/src/examples/myapp_rails#
190
+ =end
191
+ for package in list
192
+ # gem options:
193
+ # -x : remove installed executables
194
+ cmd = "#{gem} uninstall -x #{package} < /dev/null"
195
+ cmd << " > /dev/null" if opts[:quiet]
196
+ cmd << " 2>&1"
197
+ interpreter.sh(cmd)
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,95 @@
1
+ # == PackageManager::PEAR
2
+ #
3
+ # A PackageManager driver for PEAR (PHP Extension and Application Repository),
4
+ # manages software packages using the <tt>pear</tt> command.
5
+ #
6
+ # === Using specific channels
7
+ #
8
+ # To install a package from the default PEAR channel, just specify it's name,
9
+ # e.g. <tt>HTML_QuickForm</tt>.
10
+ #
11
+ # To install a package from another channel, you must specify the name prefixed
12
+ # with the channel's URL, e.g. <tt>pear.symfony-project.com/symfony</tt>, so
13
+ # that the channel can be automatically added as needed.
14
+ #
15
+ # *IMPORTANT*: DO NOT specify a remote channel's alias, e.g.
16
+ # <tt>symfony/symfony</tt>, because this provides no way to discover the
17
+ # channel.
18
+ class ::AutomateIt::PackageManager::PEAR < ::AutomateIt::PackageManager::BaseDriver
19
+ depends_on :programs => %w(pear)
20
+
21
+ def suitability(method, *args) # :nodoc:
22
+ # Never select as default driver
23
+ return 0
24
+ end
25
+
26
+ # Retrieve a hash containing all installed packages, indexed by package
27
+ # name. Each value is a hash containing values for :version and :state.
28
+ def get_installed_packages()
29
+ cmd = "pear list --allchannels 2>&1"
30
+ data = `#{cmd}`
31
+ installed_packages = {}
32
+ data.scan(/^([^(\s]+)\s+([^\s]+)\s+([^\s]+)$/) do |package, version, state|
33
+ next if version.upcase == 'VERSION'
34
+ installed_packages[package] = {:version => version, :state => state}
35
+ end
36
+ return installed_packages
37
+ end
38
+ protected :get_installed_packages
39
+
40
+ # See AutomateIt::PackageManager#installed?
41
+ def installed?(*packages)
42
+ return _installed_helper?(*packages) do |list, opts|
43
+ all_installed = get_installed_packages().keys.collect {|pkg| pkg.downcase}
44
+
45
+ result = []
46
+ list.each do |pkg|
47
+ pkg_without_channel = pkg.gsub(%r{^[^/]+/}, '').downcase
48
+ result.push pkg if all_installed.include?(pkg_without_channel)
49
+ end
50
+
51
+ result
52
+ end
53
+ end
54
+
55
+ # See AutomateIt::PackageManager#not_installed?
56
+ def not_installed?(*packages)
57
+ return _not_installed_helper?(*packages)
58
+ end
59
+
60
+ # *IMPORTANT*: See documentation at the top of this file for how to correctly
61
+ # install packages from a specific channel.
62
+ #
63
+ # Options:
64
+ # * :force -- Force installation, needed when installing unstable packages
65
+ #
66
+ # See AutomateIt::PackageManager#install
67
+ def install(*packages)
68
+ return _install_helper(*packages) do |list, opts|
69
+ # pear options:
70
+ # -a install all required dependencies
71
+ # -f force installation
72
+
73
+ cmd = "(pear config-set auto_discover 1; "
74
+ cmd << "pear install -a"
75
+ cmd << " -f" if opts[:force]
76
+ cmd << " "+list.join(" ")+" < /dev/null)"
77
+ cmd << " > /dev/null" if opts[:quiet]
78
+ cmd << " 2>&1"
79
+
80
+ interpreter.sh(cmd)
81
+ end
82
+ end
83
+
84
+ # See AutomateIt::PackageManager#uninstall
85
+ def uninstall(*packages)
86
+ return _uninstall_helper(*packages) do |list, opts|
87
+
88
+ cmd = "pear uninstall "+list.join(" ")+" < /dev/null"
89
+ cmd << " > /dev/null" if opts[:quiet]
90
+ cmd << " 2>&1"
91
+
92
+ interpreter.sh(cmd)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,80 @@
1
+ # == PackageManager::PECL
2
+ #
3
+ # A PackageManager driver for PECL (PHP Extension Community Library), manages
4
+ # software packages using the <tt>pecl</tt> command.
5
+ class ::AutomateIt::PackageManager::PECL < ::AutomateIt::PackageManager::BaseDriver
6
+ depends_on :programs => %w(pecl)
7
+
8
+ def suitability(method, *args) # :nodoc:
9
+ # Never select as default driver
10
+ return 0
11
+ end
12
+
13
+ # Retrieve a hash containing all installed packages, indexed by package
14
+ # name. Each value is a hash containing values for :channel, :version,
15
+ # and :state.
16
+ def get_installed_packages()
17
+ cmd = "pecl list -a 2>&1"
18
+ data = `#{cmd}`
19
+ installed_packages = {}
20
+ data.scan(/^([^(\s]+)\s+([^\s]+)\s+([^\s]+)$/) do |package, version, state|
21
+ next if version.upcase == 'VERSION'
22
+ installed_packages[package] = {:version => version, :state => state}
23
+ end
24
+ return installed_packages
25
+ end
26
+ protected :get_installed_packages
27
+
28
+ # See AutomateIt::PackageManager#installed?
29
+ def installed?(*packages)
30
+ return _installed_helper?(*packages) do |list, opts|
31
+ all_installed = get_installed_packages().keys.collect {|pkg| pkg.downcase}
32
+
33
+ result = []
34
+ list.each do |pkg|
35
+ pkg_without_channel = pkg.gsub(%r{^[^/]+/}, '').downcase
36
+ result.push pkg if all_installed.include?(pkg_without_channel)
37
+ end
38
+
39
+ result
40
+ end
41
+ end
42
+
43
+
44
+ # See AutomateIt::PackageManager#not_installed?
45
+ def not_installed?(*packages)
46
+ return _not_installed_helper?(*packages)
47
+ end
48
+
49
+ # Options:
50
+ # * :force -- Force installation, needed when installing unstable packages
51
+ #
52
+ # See AutomateIt::PackageManager#install
53
+ def install(*packages)
54
+ return _install_helper(*packages) do |list, opts|
55
+ # pecl options:
56
+ # -a install all required dependencies
57
+ # -f force installation
58
+
59
+ cmd = "pecl install -a"
60
+ cmd << " -f" if opts[:force]
61
+ cmd << " "+list.join(" ")+" < /dev/null"
62
+ cmd << " > /dev/null" if opts[:quiet]
63
+ cmd << " 2>&1"
64
+
65
+ interpreter.sh(cmd)
66
+ end
67
+ end
68
+
69
+ # See AutomateIt::PackageManager#uninstall
70
+ def uninstall(*packages)
71
+ return _uninstall_helper(*packages) do |list, opts|
72
+
73
+ cmd = "pecl uninstall "+list.join(" ")+" < /dev/null"
74
+ cmd << " > /dev/null" if opts[:quiet]
75
+ cmd << " 2>&1"
76
+
77
+ interpreter.sh(cmd)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,69 @@
1
+ # == PackageManager::Portage
2
+ #
3
+ # The Portage driver for the PackageManager provides a way to manage software
4
+ # packages on Gentoo systems using.
5
+ class AutomateIt::PackageManager::Portage < AutomateIt::PackageManager::BaseDriver
6
+ depends_on :programs => %w(emerge)
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
+ # Emerge throws an error when called with invalid packages, so it's
16
+ # necessary to find the invalid packages and re-run the command without
17
+ # them to find out what is actually installed.
18
+ missing = []
19
+ available = []
20
+ while true
21
+ cmd = "emerge --color n --nospinner --tree --usepkg --quiet --pretend " + \
22
+ (list-missing).join(' ') + " < /dev/null 2>&1"
23
+ log.debug(PEXEC+cmd)
24
+ output = `#{cmd}`
25
+
26
+ if output.match(/no ebuilds to satisfy "(.+)"/)
27
+ invalid = $1
28
+ log.debug(PNOTE+"PackageManager::Portage.installed? skipping invalid package '#{invalid}'")
29
+ missing << invalid
30
+ break if (list-missing).size.zero?
31
+ else
32
+ matches = output.scan(%r{^\[\w+\s+R\s*\] .+/(\w+?)-.+$}).flatten
33
+ available = list & matches
34
+ break
35
+ end
36
+ end
37
+
38
+ available
39
+ end
40
+ end
41
+
42
+ # See AutomateIt::PackageManager#not_installed?
43
+ def not_installed?(*packages)
44
+ return _not_installed_helper?(*packages)
45
+ end
46
+
47
+ # See AutomateIt::PackageManager#install
48
+ def install(*packages)
49
+ return _install_helper(*packages) do |list, opts|
50
+ cmd = "emerge --color n --nospinner --tree --usepkg --quiet #{list.join(' ')} < /dev/null"
51
+ cmd << " > /dev/null" if opts[:quiet]
52
+ cmd << " 2>&1"
53
+
54
+ interpreter.sh(cmd)
55
+ end
56
+ end
57
+
58
+ # See AutomateIt::PackageManager#uninstall
59
+ def uninstall(*packages)
60
+ return _uninstall_helper(*packages) do |list, opts|
61
+ cmd = "emerge --color n --nospinner --tree --unmerge --quiet #{list.join(' ')} < /dev/null"
62
+ cmd << " > /dev/null" if opts[:quiet]
63
+ cmd << " 2>&1"
64
+
65
+ interpreter.sh(cmd)
66
+ end
67
+ end
68
+ end
69
+