automate-it 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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
+