On Tue, Apr 09, 2024 at 10:17:30PM +0200, Sebastian Reitenbach wrote:
> Since we now have a recent Puppet in ports, I started looking at how packages 
> are handled with Puppet.
> My current trouble is that it wasn't really possible to install banches 
> properly: i.e. can't properly install gimp, 
> or auto* based on branch. Or esp, when want to install multiple of them, it 
> was just not possible.
> For ports where branches conflict, i.e. postfix, this was working, but had to 
> specify exact version, and on every
> upgrade bump the version .... _very_ annoying.
> 
> Currently Puppet allows to install packages of a given version (ensure => 
> "X.Y.Z"), or to follow updates (ensure => "latest").
> 
[...]
> This is just for Puppet 8. Anyone still on Puppet 7? It should be easily 
> ported to Puppet 7 as well. 
> 
I am on Puppet 7 and I do not have time to upgrade to Puppet 8 soon; I
am also using "ensure => latest" syntax but I can change my code to get
rid of it OpenBSD will no more support it.

 Cheers
  Giovanni


> cheers,
> Sebastian
> 
> 
> Index: Makefile
> ===================================================================
> RCS file: /cvs/ports/sysutils/ruby-puppet/8/Makefile,v
> diff -u -r1.2 Makefile
> --- Makefile  20 Mar 2024 21:21:14 -0000      1.2
> +++ Makefile  9 Apr 2024 19:51:40 -0000
> @@ -1,6 +1,7 @@
>  PORTROACH=           limit:^7
>  
>  VERSION=             8.5.1
> +REVISION=            0
>  
>  RUN_DEPENDS+=                
> converters/ruby-multi_json,${MODRUBY_FLAVOR}>=1.13,<2 \
>                       devel/ruby-concurrent-ruby,${MODRUBY_FLAVOR}>=1,<2 \
> Index: patches/patch-lib_puppet_provider_package_openbsd_rb
> ===================================================================
> RCS file: 
> /cvs/ports/sysutils/ruby-puppet/8/patches/patch-lib_puppet_provider_package_openbsd_rb,v
> diff -u -r1.2 patch-lib_puppet_provider_package_openbsd_rb
> --- patches/patch-lib_puppet_provider_package_openbsd_rb      20 Mar 2024 
> 21:21:14 -0000      1.2
> +++ patches/patch-lib_puppet_provider_package_openbsd_rb      9 Apr 2024 
> 19:51:40 -0000
> @@ -1,42 +1,89 @@
> -- Handle errors from pkg_add
> -- Handle uninstall_options being 'nil' by default
> -- If no flavor speficied, force the empty flavor with '--'
> -  but skipping the % un-ambiguity pkg names
> -- Bail out on shortform PKG_PATH (i.e. 'ftp.openbsd.org')
> -- pkg.conf is gone
> -- properly handle packages with multiple versions and flavors,
> -  i.e. postfix-XXX-flavor
> -
> +- get rid of versionable (no ensure => "version X.X.X")
> +- get rid of upgradeable (ensure => latest)
> +- properly support branches
>  
>  Index: lib/puppet/provider/package/openbsd.rb
>  --- lib/puppet/provider/package/openbsd.rb.orig
>  +++ lib/puppet/provider/package/openbsd.rb
> -@@ -24,6 +24,8 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> -   has_feature :upgradeable
> +@@ -6,10 +6,14 @@ require_relative '../../../puppet/provider/package'
> + Puppet::Type.type(:package).provide :openbsd, :parent => 
> Puppet::Provider::Package do
> +   desc "OpenBSD's form of `pkg_add` support.
> + 
> ++    OpenBSD has the concept of package branches, providing multiple 
> versions of the
> ++    same package, i.e. `stable` vs. `snapshot`. To select a specific branch,
> ++    suffix the package name with % sign follwed by the branch name, i.e. 
> `gimp%stable`.
> ++
> +     This provider supports the `install_options` and `uninstall_options`
> +     attributes, which allow command-line flags to be passed to pkg_add and 
> pkg_delete.
> +     These options should be specified as an array where each element is 
> either a
> +-     string or a hash."
> ++    string or a hash."
> + 
> +   commands :pkginfo => "pkg_info",
> +            :pkgadd => "pkg_add",
> +@@ -18,220 +22,94 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> +   defaultfor 'os.name' => :openbsd
> +   confine 'os.name' => :openbsd
> + 
> +-  has_feature :versionable
> +   has_feature :install_options
> +   has_feature :uninstall_options
> +-  has_feature :upgradeable
>     has_feature :supports_flavors
>   
> -+  mk_resource_methods
> -+
>     def self.instances
> -     packages = []
> - 
> -@@ -46,12 +48,6 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> - 
> -             packages << new(hash)
> -             hash = {}
> +-    packages = []
> +-
> ++    final = []
> +     begin
> +-      execpipe(listcmd) do |process|
> +-        # our regex for matching pkg_info output
> +-        regex = /^(.*)-(\d[^-]*)[-]?([\w-]*)(.*)$/
> +-        fields = [:name, :ensure, :flavor]
> +-        hash = {}
> ++      packages = listcmd
> ++      packages.each { |package, value|
> ++        if !package.empty?()
> ++          value[:provider] = self.name
> ++          final << new(value)
> ++        end
> ++      }
> ++      return final
> + 
> +-        # now turn each returned line into a package object
> +-        process.each_line { |line|
> +-          match = regex.match(line.split[0])
> +-          if match
> +-            fields.zip(match.captures) { |field, value|
> +-              hash[field] = value
> +-            }
> +-
> +-            hash[:provider] = self.name
> +-
> +-            packages << new(hash)
> +-            hash = {}
>  -          else
>  -            unless line =~ /Updating the pkgdb/
>  -              # Print a warning on lines we can't match, but move
>  -              # on, since it should be non-fatal
>  -              warning(_("Failed to match line %{line}") % { line: line })
>  -            end
> -           end
> -         }
> -       end
> -@@ -67,26 +63,17 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> +-          end
> +-        }
> +-      end
> +-
> +-      return packages
> +     rescue Puppet::ExecutionFailure
> +-      return nil
> ++      nil
> +     end
>     end
>   
> -   def latest
> +   def self.listcmd
> +-    [command(:pkginfo), "-a"]
> +-  end
> +-
> +-  def latest
>  -    parse_pkgconf
>  -
>  -    if @resource[:source][-1, 1] == ::File::SEPARATOR
> @@ -45,55 +92,51 @@
>  -      e_vars = {}
>  -    end
>  -
> -     if @resource[:flavor]
> -       query = "#{@resource[:name]}--#{@resource[:flavor]}"
> -     else
> +-    if @resource[:flavor]
> +-      query = "#{@resource[:name]}--#{@resource[:flavor]}"
> +-    else
>  -      query = @resource[:name]
> -+      query = @resource[:name] + "--"
> -     end
> - 
> +-    end
> +-
>  -    output = Puppet::Util.withenv(e_vars) { pkginfo "-Q", query }
>  -    version = properties[:ensure]
> -+    output = Puppet::Util.withenv({}) {pkginfo "-Q", query}
> - 
> -     if output.nil? or output.size == 0 or output =~ /Error from /
> -       debug "Failed to query for #{resource[:name]}"
> +-
> +-    if output.nil? or output.size == 0 or output =~ /Error from /
> +-      debug "Failed to query for #{resource[:name]}"
>  -      return version
> -+      return properties[:ensure]
> -     else
> -       # Remove all fuzzy matches first.
> -       output = output.split.select { |p| p =~ 
> /^#{resource[:name]}-(\d[^-]*)[-]?(\w*)/ }.join
> -@@ -95,21 +82,22 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> - 
> -     if output =~ /^#{resource[:name]}-(\d[^-]*)[-]?(\w*) \(installed\)$/
> -       debug "Package is already the latest available"
> +-    else
> +-      # Remove all fuzzy matches first.
> +-      output = output.split.select { |p| p =~ 
> /^#{resource[:name]}-(\d[^-]*)[-]?(\w*)/ }.join
> +-      debug "pkg_info -Q for #{resource[:name]}: #{output}"
> +-    end
> +-
> +-    if output =~ /^#{resource[:name]}-(\d[^-]*)[-]?(\w*) \(installed\)$/
> +-      debug "Package is already the latest available"
>  -      return version
> -+      return properties[:ensure]
> -     else
> -       match = /^(.*)-(\d[^-]*)[-]?(\w*)$/.match(output)
> -       debug "Latest available for #{resource[:name]}: #{match[2]}"
> - 
> +-    else
> +-      match = /^(.*)-(\d[^-]*)[-]?(\w*)$/.match(output)
> +-      debug "Latest available for #{resource[:name]}: #{match[2]}"
> +-
>  -      if version.to_sym == :absent || version.to_sym == :purged
> -+      if properties[:ensure].to_sym == :absent
> -         return match[2]
> -       end
> - 
> -       vcmp = version.split('.').map { |s| s.to_i } <=> 
> match[2].split('.').map { |s| s.to_i }
> -+      vcmp = properties[:ensure].split('.').map{|s|s.to_i} <=> 
> match[2].split('.').map{|s|s.to_i}
> -       if vcmp > 0
> -         # The locally installed package may actually be newer than what a 
> mirror
> -         # has. Log it at debug, but ignore it otherwise.
> +-        return match[2]
> +-      end
> +-
> +-      vcmp = version.split('.').map { |s| s.to_i } <=> 
> match[2].split('.').map { |s| s.to_i }
> +-      if vcmp > 0
> +-        # The locally installed package may actually be newer than what a 
> mirror
> +-        # has. Log it at debug, but ignore it otherwise.
>  -        debug "Package #{resource[:name]} #{version} newer then available 
> #{match[2]}"
>  -        return version
> -+        debug "Package #{resource[:name]} #{properties[:ensure]} newer then 
> available #{match[2]}"
> -+        return properties[:ensure]
> -       else
> -         return match[2]
> -       end
> -@@ -120,57 +108,25 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> -     self.install(true)
> -   end
> - 
> +-      else
> +-        return match[2]
> +-      end
> +-    end
> +-  end
> +-
> +-  def update
> +-    self.install(true)
> +-  end
> +-
>  -  def parse_pkgconf
>  -    unless @resource[:source]
>  -      if Puppet::FileSystem.exist?("/etc/pkg.conf")
> @@ -111,7 +154,20 @@
>  -              end
>  -            end
>  -          end
> --        end
> ++    regex_fuzzy = /^(.*)--([\w-]+)?(%[^w]+)?$/
> ++    f = []
> ++    f = pkginfo("-a", "-z").split("\n")
> ++    packages = {}
> ++    f.each do |line|
> ++        match = regex_fuzzy.match(line.split[0])
> ++        name = match.captures[0]
> ++        flavor = match.captures[1]
> ++        branch = match.captures[2]
> ++        if branch.nil?
> ++                    pname = name
> ++        else
> ++                    pname = name + branch
> +         end
>  -
>  -        unless @resource[:source]
>  -          raise Puppet::Error,
> @@ -121,14 +177,18 @@
>  -        raise Puppet::Error,
>  -              _("You must specify a package source or configure an 
> installpath in /etc/pkg.conf")
>  -      end
> --    end
> --  end
> --
> -   def install(latest = false)
> ++        packages[pname] = { :name => pname, :flavor => flavor, :branch => 
> branch, :ensure => "present" }
> +     end
> ++    packages
> +   end
> + 
> +-  def install(latest = false)
> ++  def install
>       cmd = []
>   
>  -    parse_pkgconf
> --
> ++    full_name = get_full_name(action="install")
> + 
>  -    if @resource[:source][-1, 1] == ::File::SEPARATOR
>  -      e_vars = { 'PKG_PATH' => @resource[:source] }
>  -      full_name = get_full_name(latest)
> @@ -139,27 +199,24 @@
>  -
>  +    cmd << '-r'
>       cmd << install_options
> --    cmd << full_name
> -+    cmd << get_full_name(latest)
> +     cmd << full_name
>   
> -     if latest
> +-    if latest
>  -      cmd.unshift('-rz')
> -+      cmd.unshift('-z')
> -     end
> - 
> --    Puppet::Util.withenv(e_vars) { pkgadd cmd.flatten.compact }
>  +    # pkg_add(1) doesn't set the return value upon failure so we have to 
> peek
>  +    # at it's output to see if something went wrong.
>  +    output = Puppet::Util.withenv({}) { pkgadd cmd.flatten.compact }
> -+    require 'pp'
> -+    pp output
>  +    if output =~ /Can't find /
>  +      self.fail "pkg_add returned: #{output.chomp}"
> -+    end
> +     end
> +-
> +-    Puppet::Util.withenv(e_vars) { pkgadd cmd.flatten.compact }
>     end
>   
> -   def get_full_name(latest = false)
> -@@ -179,11 +135,20 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> +-  def get_full_name(latest = false)
> ++  def get_full_name(action="install")
> +     # In case of a real update (i.e., the package already exists) then
> +     # pkg_add(8) can handle the flavors. However, if we're actually
>       # installing with 'latest', we do need to handle the flavors. This is
>       # done so we can feed pkg_add(8) the full package name to install to
>       # prevent ambiguity.
> @@ -168,53 +225,35 @@
>  -    elsif latest
>  -      # Don't depend on get_version for updates.
>  -      @resource[:name]
> -+    if resource[:flavor]
> -+      # If :ensure contains a version, use that instead of looking it up.
> -+      # This allows for installing packages with the same stem, but multiple
> -+      # version such as postfix-VERSION-flavor.
> -+      if @resource[:ensure].to_s =~ /(\d[^-]*)$/
> -+        use_version = @resource[:ensure]
> -+      else
> -+        use_version = ''
> -+      end      
> -+      "#{resource[:name]}-#{use_version}-#{resource[:flavor]}"
> -+    elsif resource[:name].to_s.match(/[a-z0-9]%[0-9a-z]/i)
> -+        "#{resource[:name]}"
> -+    elsif not latest
> -+      "#{resource[:name]}--"
> -     else
> -       # If :ensure contains a version, use that instead of looking it up.
> -       # This allows for installing packages with the same stem, but multiple
> -@@ -194,33 +159,41 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> -         use_version = get_version
> -       end
> +-    else
> +-      # If :ensure contains a version, use that instead of looking it up.
> +-      # This allows for installing packages with the same stem, but multiple
> +-      # version such as openldap-server.
> +-      if @resource[:ensure].to_s =~ /(\d[^-]*)$/
> +-        use_version = @resource[:ensure]
> +-      else
> +-        use_version = get_version
> +-      end
>   
>  -      [@resource[:name], use_version, 
> @resource[:flavor]].join('-').gsub(/-+$/, '')
> -+      if resource[:flavor]
> -+        [ @resource[:name], use_version, 
> @resource[:flavor]].join('-').gsub(/-+$/, '')
> -+      else
> -+        [ @resource[:name], use_version ]
> -+      end
> ++    name_branch_regex = /^(\S*)(%\w*)$/
> ++    match = name_branch_regex.match(@resource[:name])
> ++    if match
> ++      use_name = match.captures[0]
> ++      use_branch = match.captures[1]
> ++    else
> ++      use_name = @resource[:name]
> ++      use_branch = ''
>       end
> -   end
> +-  end
>   
> -   def get_version
> +-  def get_version
>  -    execpipe([command(:pkginfo), "-I", @resource[:name]]) do |process|
>  -      # our regex for matching pkg_info output
>  -      regex = /^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/
>  -      master_version = 0
>  -      version = -1
> -+    pkg_search_name = @resource[:name]
> -+    unless pkg_search_name.match(/[a-z0-9]%[0-9a-z]/i) and not 
> @resource[:flavor]
> -+      # we are only called when no flavor is specified
> -+      # so append '--' to the :name to avoid patch versions on flavors
> -+      pkg_search_name << "--"
> -+    end
> -+    # our regex for matching pkg_info output
> -+    regex = /^(.*)-(\d[^-]*)[-]?(\w*)(.*)$/
> -+    master_version = 0
> -+    version = -1
> - 
> +-
>  -      process.each_line do |line|
>  -        match = regex.match(line.split[0])
>  -        if match
> @@ -224,29 +263,36 @@
>  -
>  -          master_version = version unless master_version > version
>  -        end
> -+    # pkg_info -I might return multiple lines, i.e. flavors
> -+    matching_pkgs = pkginfo("-I", "pkg_search_name")
> -+    matching_pkgs.each_line do |line|
> -+      if match = regex.match(line.split[0])
> -+        # now we return the first version, unless ensure is latest
> -+        version = match.captures[1]
> -+        return version unless @resource[:ensure] == "latest"
> -+        master_version = version unless master_version > version
> -       end
> -+    end
> - 
> +-      end
> +-
>  -      return master_version unless master_version == 0
>  -      return '' if version == -1
> -+    return master_version unless master_version == 0
> -+    return '' if version == -1
> -+    raise Puppet::Error, _("%{version} is not available for this package") 
> % { version: version }
> - 
> +-
>  -      raise Puppet::Error, _("%{version} is not available for this 
> package") % { version: version }
> --    end
> -   rescue Puppet::ExecutionFailure
> -     return nil
> ++    if @resource[:flavor]
> ++      return "#{use_name}--#{@resource[:flavor]}#{use_branch}"
> ++    else
> ++      return "#{use_name}--#{use_branch}"
> +     end
> +-  rescue Puppet::ExecutionFailure
> +-    return nil
> ++
>     end
> -@@ -239,7 +212,7 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> + 
> +   def query
> +-    # Search for the version info
> +-    if pkginfo(@resource[:name]) =~ /Information for 
> (inst:)?#{@resource[:name]}-(\S+)/
> +-      return { :ensure => $2 }
> +-    else
> +-      return nil
> ++    pkg = self.class.instances.find do |package|
> ++      @resource[:name] == package.name
> +     end
> ++    pkg ? pkg.properties : nil
> +   end
> + 
> +   def install_options
> +@@ -239,15 +117,19 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
>     end
>   
>     def uninstall_options
> @@ -254,4 +300,27 @@
>  +    [join_options(resource[:uninstall_options])]
>     end
>   
> -   def uninstall
> +-  def uninstall
> +-    pkgdelete uninstall_options.flatten.compact, @resource[:name]
> ++  def uninstall(purge = false)
> ++    if purge
> ++      pkgdelete "-c", "-qq", uninstall_options.flatten.compact, 
> get_full_name(action="uninstall")
> ++    else
> ++      pkgdelete uninstall_options.flatten.compact, 
> get_full_name(action="uninstall")
> ++    end
> +   end
> + 
> +   def purge
> +-    pkgdelete "-c", "-q", @resource[:name]
> ++    uninstall(purge=true)
> +   end
> + 
> +   def flavor
> +@@ -256,7 +138,6 @@ Puppet::Type.type(:package).provide :openbsd, :parent 
> + 
> +   def flavor=(value)
> +     if flavor != @resource.should(:flavor)
> +-      uninstall
> +       install
> +     end
> +   end


Attachment: signature.asc
Description: PGP signature

Reply via email to