Subject: [bug#65131] [PATCH 23/32] gnu: Add vagrant.

From: Hartmut Goebel <[email-masked]>
Date: Mon, 7 Aug 2023 20:26:27 +0200

* gnu/packages/virtualization.scm (vagrant): New variable.
* gnu/packages/patches/vagrant-Support-system-installed-plugins.patch,
  gnu/packages/patches/vagrant-Use-a-private-temporary-dir.patch
  gnu/packages/patches/vagrant-bin-vagrant-silence-warning-about-installer.patch:
  New files.
* gnu/local.mk(dist_patch_DATA): Add them
---
 gnu/local.mk                                  |   3 +
 ...ant-Support-system-installed-plugins.patch | 172 ++++++++++++++++++
 .../vagrant-Use-a-private-temporary-dir.patch | 119 ++++++++++++
 ...rant-silence-warning-about-installer.patch |  24 +++
 gnu/packages/virtualization.scm               | 104 +++++++++++
 5 files changed, 422 insertions(+)
 create mode 100644 gnu/packages/patches/vagrant-Support-system-installed-plugins.patch
 create mode 100644 gnu/packages/patches/vagrant-Use-a-private-temporary-dir.patch
 create mode 100644 gnu/packages/patches/vagrant-bin-vagrant-silence-warning-about-installer.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 6dcacd3d6e..cecef27827 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -2067,6 +2067,9 @@ dist_patch_DATA =						\
   %D%/packages/patches/unzip-32bit-zipbomb-fix.patch    \
   %D%/packages/patches/ustr-fix-build-with-gcc-5.patch		\
   %D%/packages/patches/util-linux-tests.patch			\
+  %D%/packages/patches/vagrant-bin-vagrant-silence-warning-about-installer.patch	\
+  %D%/packages/patches/vagrant-Support-system-installed-plugins.patch	\
+  %D%/packages/patches/vagrant-Use-a-private-temporary-dir.patch	\
   %D%/packages/patches/vboot-utils-fix-format-load-address.patch	\
   %D%/packages/patches/vboot-utils-fix-tests-show-contents.patch	\
   %D%/packages/patches/vboot-utils-skip-test-workbuf.patch	\
diff --git a/gnu/packages/patches/vagrant-Support-system-installed-plugins.patch b/gnu/packages/patches/vagrant-Support-system-installed-plugins.patch
new file mode 100644
index 0000000000..3d57993921
--- /dev/null
+++ b/gnu/packages/patches/vagrant-Support-system-installed-plugins.patch
@@ -0,0 +1,172 @@
+From: Hartmut Goebel <[email-masked]>
+Date: Mon, 07 Aug 2023 18:09:09 +0200
+Subject: Support system-installed plugins
+
+Plugins must be installed as regular Ruby libraries, and they must
+contain share/vagrant-plugins/plugins.d/$PLUGINNAME.json with the
+following content:
+
+{
+  "${PLUGINNAME}": {
+    "ruby_version":"$(ruby -e 'puts RUBY_VERSION')",
+    "vagrant_version":"$(cat /usr/share/vagrant/version.txt)",
+    "gem_version":"",
+    "require":"",
+    "sources":[]
+  }
+}
+
+This patch was based on the respective patch from Debian, anyhow heavily
+adjusted to Guix and to support GUIX_VAGRANT_PLUGINS_PATH.
+
+Orignal-Author: Antonio Terceiro <[email-masked]>
+Co-authored-by: Antonio Terceiro <[email-masked]>
+---
+ bin/vagrant                      | 15 +++++++++++++++
+ lib/vagrant/bundler.rb           |  2 +-
+ lib/vagrant/plugin/manager.rb    |  4 ++--
+ lib/vagrant/plugin/state_file.rb | 30 ++++++++++++++++++++++++++++--
+ lib/vagrant/shared_helpers.rb    |  8 ++++++++
+ 5 files changed, 54 insertions(+), 5 deletions(-)
+
+diff --git a/bin/vagrant b/bin/vagrant
+index d3f4ea6..cc00efa 100755
+--- a/bin/vagrant
++++ b/bin/vagrant
+@@ -86,6 +86,21 @@ $stderr.sync = true
+ # so we can provide correct resolutions later
+ builtin_specs = []
+ 
++# Add the gem paths of vagrant plugins to the Gem search path
++# TODO: find a better way to add paths to the Gem search path
++gempath = []
++if ENV['GEM_PATH']
++  gempath.append(ENV['GEM_PATH'])
++end
++ENV['GUIX_VAGRANT_PLUGINS_PATH'].split(File::PATH_SEPARATOR).each do |pluginsdir|
++  gemdir = File.absolute_path(File.join(pluginsdir, "../../lib/ruby/vendor_ruby"))
++  gempath.append(gemdir)
++end
++ENV['GEM_PATH'] = gempath.join(':')
++gemdir = nil
++gempath = nil
++Gem.clear_paths()  # make GEM_PATH be reevaluated
++
+ vagrant_spec = Gem::Specification.find_all_by_name("vagrant").detect do |spec|
+   spec.version == Gem::Version.new(Vagrant::VERSION)
+ end
+diff --git a/lib/vagrant/bundler.rb b/lib/vagrant/bundler.rb
+index 46ef69f..27979b9 100644
+--- a/lib/vagrant/bundler.rb
++++ b/lib/vagrant/bundler.rb
+@@ -665,7 +665,7 @@ module Vagrant
+         spec_dir = Gem::Specification.default_specifications_dir
+       end
+       directories = [spec_dir]
+-      if Vagrant.in_bundler?
++      if Vagrant.in_bundler? || Vagrant.in_guix_package?
+         Gem::Specification.find_all{true}.each do |spec|
+           list[spec.full_name] = spec
+         end
+diff --git a/lib/vagrant/plugin/manager.rb b/lib/vagrant/plugin/manager.rb
+index b73f07f..94cd609 100644
+--- a/lib/vagrant/plugin/manager.rb
++++ b/lib/vagrant/plugin/manager.rb
+@@ -18,7 +18,7 @@ module Vagrant
+ 
+       # Returns the path to the [StateFile] for system plugins.
+       def self.system_plugins_file
+-        dir = Vagrant.installer_embedded_dir
++        dir = nil
+         return nil if !dir
+         Pathname.new(dir).join("plugins.json")
+       end
+@@ -38,7 +38,7 @@ module Vagrant
+ 
+         system_path  = self.class.system_plugins_file
+         @system_file = nil
+-        @system_file = StateFile.new(system_path) if system_path && system_path.file?
++        @system_file = StateFile.new(system_path, true) #if system_path && system_path.file?
+ 
+         @local_file = nil
+         @globalized = @localized = false
+diff --git a/lib/vagrant/plugin/state_file.rb b/lib/vagrant/plugin/state_file.rb
+index c6872d4..b927fd8 100644
+--- a/lib/vagrant/plugin/state_file.rb
++++ b/lib/vagrant/plugin/state_file.rb
+@@ -11,11 +11,17 @@ module Vagrant
+       # @return [Pathname] path to file
+       attr_reader :path
+ 
+-      def initialize(path)
++      def initialize(path, system = false)
+         @path = path
++        @system = system
+ 
+         @data = {}
+-        if @path.exist?
++        if system
++          if  ENV.has_key?('GUIX_VAGRANT_PLUGINS_PATH')
++            @data["installed"] = {}
++            load_system_plugins
++          end
++        elsif @path.exist?
+           begin
+             @data = JSON.parse(@path.read)
+           rescue JSON::ParserError => e
+@@ -30,6 +36,22 @@ module Vagrant
+         @data["installed"] ||= {}
+       end
+ 
++      def load_system_plugins
++        ENV['GUIX_VAGRANT_PLUGINS_PATH'].split(File::PATH_SEPARATOR).each do |pluginsdir|
++          extra_plugins = Dir.glob(File.join(pluginsdir, 'plugins.d', '*.json'))
++          extra_plugins.each do |filename|
++            json = File.read(filename)
++            begin
++              plugin_data = JSON.parse(json)
++              @data["installed"].merge!(plugin_data)
++            rescue JSON::ParserError => e
++              raise Vagrant::Errors::PluginStateFileParseError,
++                path: filename, message: e.message
++            end
++          end
++        end
++      end
++
+       # Add a plugin that is installed to the state file.
+       #
+       # @param [String] name The name of the plugin
+@@ -107,6 +129,10 @@ module Vagrant
+           f.close
+           FileUtils.mv(f.path, @path)
+         end
++      rescue Errno::EACCES
++        # Ignore permission denied against system-installed plugins; regular
++        # users are not supposed to write there.
++        raise unless @system
+       end
+ 
+       protected
+diff --git a/lib/vagrant/shared_helpers.rb b/lib/vagrant/shared_helpers.rb
+index 7b0b87c..eb9a21e 100644
+--- a/lib/vagrant/shared_helpers.rb
++++ b/lib/vagrant/shared_helpers.rb
+@@ -43,6 +43,14 @@ module Vagrant
+       !defined?(::Bundler).nil?
+   end
+ 
++  # This returns a true/false if we are running from a Guix package
++  #
++  # @return [Boolean]
++  def self.in_guix_package?
++    # FIXME write a proper check if this ever goes upstream
++    true
++  end
++
+   # Returns the path to the embedded directory of the Vagrant installer,
+   # if there is one (if we're running in an installer).
+   #
+-- 
+2.30.9
+
diff --git a/gnu/packages/patches/vagrant-Use-a-private-temporary-dir.patch b/gnu/packages/patches/vagrant-Use-a-private-temporary-dir.patch
new file mode 100644
index 0000000000..8d0012e888
--- /dev/null
+++ b/gnu/packages/patches/vagrant-Use-a-private-temporary-dir.patch
@@ -0,0 +1,119 @@
+From: Antonio Terceiro <[email-masked]>
+Date: Wed, 22 Oct 2014 09:40:14 -0200
+Subject: Use a private temporary directory that is cleanup up on exit
+
+This avoids vagrant from cluttering $TMPDIR with dozens of even hundreds
+of temporary files (~4 per vagrant invocation).
+---
+ lib/vagrant/box.rb           |  3 ++-
+ lib/vagrant/util.rb          |  1 +
+ lib/vagrant/util/caps.rb     |  2 +-
+ lib/vagrant/util/platform.rb |  2 +-
+ lib/vagrant/util/tempfile.rb | 39 +++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 44 insertions(+), 3 deletions(-)
+ create mode 100644 lib/vagrant/util/tempfile.rb
+
+diff --git a/lib/vagrant/box.rb b/lib/vagrant/box.rb
+index 90dc69d..4ee79b9 100644
+--- a/lib/vagrant/box.rb
++++ b/lib/vagrant/box.rb
+@@ -9,6 +9,7 @@ require "vagrant/util/downloader"
+ require "vagrant/util/platform"
+ require "vagrant/util/safe_chdir"
+ require "vagrant/util/subprocess"
++require "vagrant/util/tempfile"
+ 
+ module Vagrant
+   # Represents a "box," which is a package Vagrant environment that is used
+@@ -142,7 +143,7 @@ module Vagrant
+     # @param [Hash] download_options Options to pass to the downloader.
+     # @return [BoxMetadata]
+     def load_metadata(download_options={})
+-      tf = Tempfile.new("vagrant-load-metadata")
++      tf = Util::Tempfile.new("vagrant-load-metadata")
+       tf.close
+ 
+       url = @metadata_url
+diff --git a/lib/vagrant/util.rb b/lib/vagrant/util.rb
+index 4b3e0ff..36eb671 100644
+--- a/lib/vagrant/util.rb
++++ b/lib/vagrant/util.rb
+@@ -53,6 +53,7 @@ module Vagrant
+     autoload :SilenceWarnings,           'vagrant/util/silence_warnings'
+     autoload :SSH,                       'vagrant/util/ssh'
+     autoload :StackedProcRunner,         'vagrant/util/stacked_proc_runner'
++    autoload :Tempfile,                  'vagrant/util/tempfile'
+     autoload :StringBlockEditor,         'vagrant/util/string_block_editor'
+     autoload :Subprocess,                'vagrant/util/subprocess'
+     autoload :TemplateRenderer,          'vagrant/util/template_renderer'
+diff --git a/lib/vagrant/util/caps.rb b/lib/vagrant/util/caps.rb
+index 310add3..55afc49 100644
+--- a/lib/vagrant/util/caps.rb
++++ b/lib/vagrant/util/caps.rb
+@@ -28,7 +28,7 @@ module Vagrant
+ 
+         def ensure_output_iso(file_destination)
+           if file_destination.nil?
+-            tmpfile = Tempfile.new(["vagrant", ".iso"])
++            tmpfile = Util::Tempfile.new(["vagrant", ".iso"])
+             file_destination = Pathname.new(tmpfile.path)
+             tmpfile.close
+             tmpfile.unlink
+diff --git a/lib/vagrant/util/platform.rb b/lib/vagrant/util/platform.rb
+index c8658e1..0421c70 100644
+--- a/lib/vagrant/util/platform.rb
++++ b/lib/vagrant/util/platform.rb
+@@ -356,7 +356,7 @@ module Vagrant
+ 
+           if wsl?
+             # Mark our filesystem with a temporary file having an unique name.
+-            marker = Tempfile.new(Time.now.to_i.to_s)
++            marker = Util::Tempfile.new(Time.now.to_i.to_s)
+             logger = Log4r::Logger.new("vagrant::util::platform::wsl")
+ 
+             # Check for lxrun installation first
+diff --git a/lib/vagrant/util/tempfile.rb b/lib/vagrant/util/tempfile.rb
+new file mode 100644
+index 0000000..0cbbb53
+--- /dev/null
++++ b/lib/vagrant/util/tempfile.rb
+@@ -0,0 +1,39 @@
++require 'fileutils'
++require 'tmpdir'
++
++module Vagrant
++  module Util
++    class Tempfile < ::Tempfile
++
++      def initialize(basename)
++        super(basename, private_tmpdir)
++      end
++
++      def private_tmpdir
++        self.class.private_tmpdir
++      end
++
++      def self.private_tmpdir
++        @private_tmpdir ||=
++          begin
++            user = Etc.getpwuid.name
++            pid = Process.pid
++            tmpdir = File.join(Dir.tmpdir, "vagrant-#{user}-#{pid}")
++            FileUtils.mkdir_p(tmpdir)
++            FileUtils.chmod(0700, tmpdir)
++            tmpdir
++          end
++      end
++
++      def self.mktmpdir(prefix_suffix)
++        Dir.mktmpdir(prefix_suffix, private_tmpdir)
++      end
++
++
++    end
++  end
++end
++
++at_exit do
++  FileUtils.rm_rf(Vagrant::Util::Tempfile.private_tmpdir)
++end
diff --git a/gnu/packages/patches/vagrant-bin-vagrant-silence-warning-about-installer.patch b/gnu/packages/patches/vagrant-bin-vagrant-silence-warning-about-installer.patch
new file mode 100644
index 0000000000..4d4fed273c
--- /dev/null
+++ b/gnu/packages/patches/vagrant-bin-vagrant-silence-warning-about-installer.patch
@@ -0,0 +1,24 @@
+From: Antonio Terceiro <[email-masked]>
+Date: Sat, 11 Oct 2014 16:54:58 -0300
+Subject: bin/vagrant: silence warning about installer
+
+---
+ bin/vagrant | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/bin/vagrant b/bin/vagrant
+index 7ca30b3..d3f4ea6 100755
+--- a/bin/vagrant
++++ b/bin/vagrant
+@@ -221,11 +221,6 @@ begin
+       end
+     end
+ 
+-    if !Vagrant.in_installer? && !Vagrant.very_quiet?
+-      # If we're not in the installer, warn.
+-      env.ui.warn(I18n.t("vagrant.general.not_in_installer") + "\n", prefix: false)
+-    end
+-
+     # Acceptable experimental flag values include:
+     #
+     # Unset  - Disables experimental features
diff --git a/gnu/packages/virtualization.scm b/gnu/packages/virtualization.scm
index 68beeb88d3..d0b51a960d 100644
--- a/gnu/packages/virtualization.scm
+++ b/gnu/packages/virtualization.scm
@@ -2220,6 +2220,110 @@ helpers that let you write your own unit and acceptance tests for Vagrant.")
     (home-page "https://github.com/hashicorp/vagrant-spec")
     (license license:mpl2.0)))
 
+(define-public vagrant
+  (package
+    (name "vagrant")
+    (version "2.3.7")
+    (source (origin
+              (method git-fetch)
+              (uri (git-reference
+                    (url "https://github.com/hashicorp/vagrant")
+                    (commit "1f904866b568d9980daef4401c08b92cb3d1cda4")))
+              (file-name (git-file-name name version))
+              (sha256
+               (base32
+                "0c674c5v70skh38lpydz8cdmcp8wgr9h7rn00rxdpgizrzbfxl82"))
+              (patches (search-patches
+                        "vagrant-bin-vagrant-silence-warning-about-installer.patch"
+                        "vagrant-Support-system-installed-plugins.patch"
+                        "vagrant-Use-a-private-temporary-dir.patch"))))
+    (build-system ruby-build-system)
+    (arguments
+     (list
+      #:tests? #f  ; test require ruby-grpc-tools which are not packaged yet
+      #:phases
+      #~(modify-phases %standard-phases
+          (add-after 'unpack 'patch-gemfile
+            (lambda _
+              (substitute* "Gemfile"
+                ((", git:.*") "\n"))))
+          (add-after 'unpack 'pin-executables
+            (lambda* (#:key inputs outputs #:allow-other-keys)
+              (let* ((bsdtar (search-input-file inputs "/bin/bsdtar"))
+                     (curl (search-input-file inputs "/bin/curl"))
+                     (grep (search-input-file inputs "/bin/grep"))
+                     (modinfo (search-input-file inputs "/bin/modinfo"))
+                     (ps (search-input-file inputs "/bin/ps")))
+                ;; bsdtar
+                (for-each
+                 (lambda (rbfile)
+                   (substitute* rbfile
+                     (("\"bsdtar\",") (string-append "\"" bsdtar "\","))))
+                 (find-files "lib/vagrant/" "\\.rb$"))
+                ;; curl
+                (substitute* "lib/vagrant/util/downloader.rb"
+                  (("\"curl\",") (string-append "\"" curl "\",")))
+                (substitute* "lib/vagrant/util/uploader.rb"
+                  (("\"curl\",") (string-append "\"" curl "\",")))
+                (substitute* "plugins/hosts/linux/cap/nfs.rb"
+                  ;; grep
+                  (("\\| grep #\\{nfs_service")
+                   (string-append "| " grep " #{nfs_service"))
+                  (("\"grep\",") (string-append "\"" grep "\","))
+                  ;; modinfo
+                  (("Vagrant::Util::Which.which\\(\"modinfo\"\\)")
+                   (string-append "\"" modinfo "\"")))
+                ;; ssh, rsync:
+                ;; Don't pin ssh to allow different clients and to avoid
+                ;; configuration conflicts when running on a foreign distro.
+                ;; (substitute* "lib/vagrant/util/ssh.rb"
+                ;;   (("Which.which\\(\"ssh\", original_path: true\\)")
+                ;;    (string-append "\"" ssh "\"")))
+                ;; ps
+                (substitute* "lib/vagrant/util/platform.rb"
+                  (("\"ps\",") (string-append "\"" ps "\","))))))
+          (add-after 'extract-gemspec 'relax-requirements
+            (lambda _
+              (substitute* "vagrant.gemspec"
+                ;; Relax some version specification.
+                (("dependency \"rgl\", \"~> 0.5.10\"")
+                 "dependency \"rgl\"")
+                ;; Remove Windows specific dependencies
+                ((".*dependency \"(wdm|winrm(|-elevated|-fs))\".*") "")
+                ;; Remove BSD dependency
+                ((".*dependency \"rb-kqueue\".*") "")
+                ;; Remove cyclic inclusion of gem
+                (("^  gitignore_path = " line)
+                 (string-append
+                  "all_files.reject! { |file| file.match?(\"vagrant-.*\\.gem\") }\n"
+                  line))))))))
+    (native-search-paths
+     (list (search-path-specification
+            (variable "GUIX_VAGRANT_PLUGINS_PATH")
+            (files '("share/vagrant-plugins")))))
+    ;; TODO: install bash/zsh completions, man-page, etc.
+    ;; see http://svnweb.mageia.org/packages/cauldron/vagrant/current/SPECS/vagrant.spec
+    (native-inputs (list ruby-fake-ftp ruby-webrick bundler ruby-vagrant-spec))
+    (inputs (list curl grep kmod libarchive openssh procps))
+    (propagated-inputs
+     (list ruby-bcrypt-pbkdf ruby-childprocess ruby-ed25519 ruby-erubi
+           ruby-googleapis-common-protos-types ruby-grpc
+           ruby-hashicorp-checkpoint ruby-i18n ruby-listen ruby-log4r
+           ruby-mime-types ruby-net-ftp ruby-net-ssh ruby-net-sftp
+           ruby-net-scp ruby-ipaddr ruby-rexml ruby-rgl ruby-rubyzip
+           ruby-vagrant-cloud ruby-vagrant-spec))
+    (synopsis "Build and distribute virtualized development environments")
+    (description "Vagrant is the command line utility for managing the
+lifecycle of virtual machines.  Isolate dependencies and their configuration
+within a single disposable and consistent environment.
+
+Note: Make sure to have @code{ssh} and @code{rsync} installed — if you use the
+respective Vagrant functions. This package does not link to any specific
+implementation of these to allow different clients and to avoid configuration
+conflicts when running on a `foreign distribution'.")
+    (home-page "https://www.vagrantup.com")
+    (license license:bsd-3)))
+
 (define-public python-vagrant
   (package
     (name "python-vagrant")
-- 
2.30.9