Skip to content

Commit dd48c0e

Browse files
committed
unbreak OpenBSD package handling.
The stock package handling was already broken since years in Puppet, and it needed patches. Those were reworked about two years ago by myself.
1 parent 357585d commit dd48c0e

File tree

6 files changed

+89
-464
lines changed

6 files changed

+89
-464
lines changed

lib/puppet/provider/package/openbsd.rb

Lines changed: 39 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@
66
Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Package do
77
desc "OpenBSD's form of `pkg_add` support.
88
9+
OpenBSD has the concept of package branches, providing multiple versions of the
10+
same package, i.e. `stable` vs. `snapshot`. To select a specific branch,
11+
suffix the package name with % sign follwed by the branch name, i.e. `gimp%stable`.
12+
913
This provider supports the `install_options` and `uninstall_options`
1014
attributes, which allow command-line flags to be passed to pkg_add and pkg_delete.
1115
These options should be specified as an array where each element is either a
1216
string or a hash."
1317

14-
commands :pkginfo => "pkg_info",
15-
:pkgadd => "pkg_add",
18+
commands :pkgadd => "pkg_add",
19+
:pkginfo => "pkg_info",
1620
:pkgdelete => "pkg_delete"
1721

1822
defaultfor 'os.name' => :openbsd
1923
confine 'os.name' => :openbsd
2024

21-
has_feature :versionable
2225
has_feature :install_options
2326
has_feature :uninstall_options
24-
has_feature :upgradeable
2527
has_feature :supports_flavors
2628

2729
def self.instances
@@ -30,20 +32,21 @@ def self.instances
3032
begin
3133
execpipe(listcmd) do |process|
3234
# our regex for matching pkg_info output
33-
regex = /^(.*)-(\d[^-]*)-?([\w-]*)(.*)$/
34-
fields = [:name, :ensure, :flavor]
35+
regex = /^(.*)--([\w-]+)?(%[^w]+)?$/
36+
fields = [:name, :flavor, :branch]
3537
hash = {}
3638

3739
# now turn each returned line into a package object
3840
process.each_line { |line|
39-
match = regex.match(line.split[0])
41+
match = regex.match(line.split("\n")[0])
4042
if match
4143
fields.zip(match.captures) { |field, value|
4244
hash[field] = value
4345
}
4446

45-
hash[:provider] = name
47+
hash[:name] = "#{hash[:name]}#{hash[:branch]}" if hash[:branch]
4648

49+
hash[:provider] = name
4750
packages << new(hash)
4851
hash = {}
4952
else
@@ -63,191 +66,71 @@ def self.instances
6366
end
6467

6568
def self.listcmd
66-
[command(:pkginfo), "-a"]
67-
end
68-
69-
def latest
70-
parse_pkgconf
71-
72-
if @resource[:source][-1, 1] == ::File::SEPARATOR
73-
e_vars = { 'PKG_PATH' => @resource[:source] }
74-
else
75-
e_vars = {}
76-
end
77-
78-
if @resource[:flavor]
79-
query = "#{@resource[:name]}--#{@resource[:flavor]}"
80-
else
81-
query = @resource[:name]
82-
end
83-
84-
output = Puppet::Util.withenv(e_vars) { pkginfo "-Q", query }
85-
version = properties[:ensure]
86-
87-
if output.nil? or output.size == 0 or output =~ /Error from /
88-
debug "Failed to query for #{resource[:name]}"
89-
return version
90-
else
91-
# Remove all fuzzy matches first.
92-
output = output.split.select { |p| p =~ /^#{resource[:name]}-(\d[^-]*)-?(\w*)/ }.join
93-
debug "pkg_info -Q for #{resource[:name]}: #{output}"
94-
end
95-
96-
if output =~ /^#{resource[:name]}-(\d[^-]*)-?(\w*) \(installed\)$/
97-
debug "Package is already the latest available"
98-
version
99-
else
100-
match = /^(.*)-(\d[^-]*)-?(\w*)$/.match(output)
101-
debug "Latest available for #{resource[:name]}: #{match[2]}"
102-
103-
if version.to_sym == :absent || version.to_sym == :purged
104-
return match[2]
105-
end
106-
107-
vcmp = version.split('.').map(&:to_i) <=> match[2].split('.').map(&:to_i)
108-
if vcmp > 0
109-
# The locally installed package may actually be newer than what a mirror
110-
# has. Log it at debug, but ignore it otherwise.
111-
debug "Package #{resource[:name]} #{version} newer then available #{match[2]}"
112-
version
113-
else
114-
match[2]
115-
end
116-
end
69+
[command(:pkginfo), "-a", "-z"]
11770
end
11871

119-
def update
120-
install(true)
121-
end
122-
123-
def parse_pkgconf
124-
unless @resource[:source]
125-
if Puppet::FileSystem.exist?("/etc/pkg.conf")
126-
File.open("/etc/pkg.conf", "rb").readlines.each do |line|
127-
matchdata = line.match(/^installpath\s*=\s*(.+)\s*$/i)
128-
if matchdata
129-
@resource[:source] = matchdata[1]
130-
else
131-
matchdata = line.match(/^installpath\s*\+=\s*(.+)\s*$/i)
132-
if matchdata
133-
if @resource[:source].nil?
134-
@resource[:source] = matchdata[1]
135-
else
136-
@resource[:source] += ":" + matchdata[1]
137-
end
138-
end
139-
end
140-
end
141-
142-
unless @resource[:source]
143-
raise Puppet::Error,
144-
_("No valid installpath found in /etc/pkg.conf and no source was set")
145-
end
146-
else
147-
raise Puppet::Error,
148-
_("You must specify a package source or configure an installpath in /etc/pkg.conf")
149-
end
150-
end
151-
end
152-
153-
def install(latest = false)
72+
def install
15473
cmd = []
15574

156-
parse_pkgconf
157-
158-
if @resource[:source][-1, 1] == ::File::SEPARATOR
159-
e_vars = { 'PKG_PATH' => @resource[:source] }
160-
full_name = get_full_name(latest)
161-
else
162-
e_vars = {}
163-
full_name = @resource[:source]
164-
end
75+
full_name = get_full_name
16576

77+
cmd << '-r'
16678
cmd << install_options
16779
cmd << full_name
16880

169-
if latest
170-
cmd.unshift('-rz')
81+
# pkg_add(1) doesn't set the return value upon failure so we have to peek
82+
# at it's output to see if something went wrong.
83+
output = Puppet::Util.withenv({}) { pkgadd cmd.flatten.compact }
84+
if output =~ /Can't find /
85+
self.fail "pkg_add returned: #{output.chomp}"
17186
end
172-
173-
Puppet::Util.withenv(e_vars) { pkgadd cmd.flatten.compact }
17487
end
17588

176-
def get_full_name(latest = false)
89+
def get_full_name
17790
# In case of a real update (i.e., the package already exists) then
17891
# pkg_add(8) can handle the flavors. However, if we're actually
17992
# installing with 'latest', we do need to handle the flavors. This is
18093
# done so we can feed pkg_add(8) the full package name to install to
18194
# prevent ambiguity.
182-
if latest && resource[:flavor]
183-
"#{resource[:name]}--#{resource[:flavor]}"
184-
elsif latest
185-
# Don't depend on get_version for updates.
186-
@resource[:name]
187-
else
188-
# If :ensure contains a version, use that instead of looking it up.
189-
# This allows for installing packages with the same stem, but multiple
190-
# version such as openldap-server.
191-
if @resource[:ensure].to_s =~ /(\d[^-]*)$/
192-
use_version = @resource[:ensure]
193-
else
194-
use_version = get_version
195-
end
19695

197-
[@resource[:name], use_version, @resource[:flavor]].join('-').gsub(/-+$/, '')
96+
name_branch_regex = /^(\S*)(%\w*)$/
97+
match = name_branch_regex.match(@resource[:name])
98+
if match
99+
use_name = match.captures[0]
100+
use_branch = match.captures[1]
101+
else
102+
use_name = @resource[:name]
103+
use_branch = ''
198104
end
199-
end
200-
201-
def get_version
202-
execpipe([command(:pkginfo), "-I", @resource[:name]]) do |process|
203-
# our regex for matching pkg_info output
204-
regex = /^(.*)-(\d[^-]*)-?(\w*)(.*)$/
205-
master_version = 0
206-
version = -1
207-
208-
process.each_line do |line|
209-
match = regex.match(line.split[0])
210-
next unless match
211-
212-
# now we return the first version, unless ensure is latest
213-
version = match.captures[1]
214-
return version unless @resource[:ensure] == "latest"
215-
216-
master_version = version unless master_version > version
217-
end
218-
219-
return master_version unless master_version == 0
220-
return '' if version == -1
221105

222-
raise Puppet::Error, _("%{version} is not available for this package") % { version: version }
106+
if @resource[:flavor]
107+
"#{use_name}--#{@resource[:flavor]}#{use_branch}"
108+
else
109+
"#{use_name}--#{use_branch}"
223110
end
224-
rescue Puppet::ExecutionFailure
225-
nil
226111
end
227112

228113
def query
229-
# Search for the version info
230-
if pkginfo(@resource[:name]) =~ /Information for (inst:)?#{@resource[:name]}-(\S+)/
231-
{ :ensure => Regexp.last_match(2) }
232-
else
233-
nil
114+
pkg = self.class.instances.find do |package|
115+
@resource[:name] == package.name
234116
end
117+
pkg ? pkg.properties : nil
235118
end
236119

237120
def install_options
238121
join_options(resource[:install_options])
239122
end
240123

241124
def uninstall_options
242-
join_options(resource[:uninstall_options])
125+
join_options(resource[:uninstall_options]) || []
243126
end
244127

245128
def uninstall
246-
pkgdelete uninstall_options.flatten.compact, @resource[:name]
129+
pkgdelete uninstall_options.flatten.compact, get_full_name
247130
end
248131

249132
def purge
250-
pkgdelete "-c", "-q", @resource[:name]
133+
pkgdelete "-c", "-qq", uninstall_options.flatten.compact, get_full_name
251134
end
252135

253136
def flavor
@@ -256,7 +139,6 @@ def flavor
256139

257140
def flavor=(value)
258141
if flavor != @resource.should(:flavor)
259-
uninstall
260142
install
261143
end
262144
end
Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +0,0 @@
1-
Information for bash-3.1.17
2-
3-
Comment:
4-
GNU Bourne Again Shell
5-
6-
Description:
7-
Bash is the GNU Project's Bourne Again SHell, an sh-compatible
8-
command language interpreter that executes commands read from the
9-
standard input or from a file. Bash also incorporates useful
10-
features from the Korn and C shells (ksh and csh).
11-
12-
Bash is intended to be a conformant implementation of the IEEE POSIX
13-
Shell and Tools specification (IEEE Working Group 1003.2).
14-
15-
Maintainer: Christian Weisgerber <naddy@openbsd.org>
16-
17-
WWW: http://cnswww.cns.cwru.edu/~chet/bash/bashtop.html
18-
19-
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
bash-3.1.17 GNU Bourne Again Shell
2-
bzip2-1.0.3 block-sorting file compressor, unencumbered
3-
expat-2.0.0 XML 1.0 parser written in C
4-
gettext-0.14.5p1 GNU gettext
5-
libiconv-1.9.2p3 character set conversion library
6-
lzo-1.08p1 portable speedy lossless data compression library
7-
openvpn-2.0.6 easy-to-use, robust, and highly configurable VPN
8-
python-2.4.3p0 interpreted object-oriented programming language
9-
vim-7.0.42-no_x11 vi clone, many additional features
10-
wget-1.10.2p0 retrieve files from the web via HTTP, HTTPS and FTP
1+
autoconf--%2.13
2+
autoconf--%2.56
3+
bash--
4+
postfix--ldap%stable
5+
puppet--%8
6+
zstd--
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-
bash-3.1.17 GNU Bourne Again Shell
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +0,0 @@
1-
bash-3.1.17-static GNU Bourne Again Shell
2-
vim-7.0.42-no_x11 vi clone, many additional features

0 commit comments

Comments
 (0)