diff --git a/binstub_patch.rb b/binstub_patch.rb index 00599425f..02a1aabdb 100644 --- a/binstub_patch.rb +++ b/binstub_patch.rb @@ -1,4 +1,18 @@ unless ENV["APPBUNDLER_ALLOW_RVM"] ENV["APPBUNDLER_ALLOW_RVM"] = "true" - ENV["GEM_PATH"] = [File.expand_path(File.join(__dir__, "..", "vendor")), ENV["GEM_PATH"]].compact.join(File::PATH_SEPARATOR) end + +# Prepend the package vendor dir, the current user's gem dir, and the Chef gem dir to +# GEM_PATH so that: +# 1. Ohai's vendored dependencies are always found. +# 2. Plugins installed via `gem install ` are discoverable on both +# Linux (~/.gem/ruby/VERSION) and Windows (%USERPROFILE%\.gem\ruby\VERSION). +# 3. Gems installed via `chef gem install` (~/.chef/ruby/VERSION/gems) are immediately available. +# +# This block runs before appbundler's env_sanitizer (which calls Gem.clear_paths and +# re-reads GEM_PATH from ENV), so these additions are always picked up correctly. +ohai_vendor = File.expand_path(File.join(__dir__, "..", "vendor")) +# chef-cli gem install places gems under ~/.chef/ruby/RUBY_API_VERSION/gems +chef_gem_dir = File.join(Dir.home, ".chef", "ruby", RbConfig::CONFIG["ruby_version"], "gems") +existing_paths = ENV["GEM_PATH"]&.split(File::PATH_SEPARATOR) || [] +ENV["GEM_PATH"] = ([ohai_vendor, Gem.user_dir, chef_gem_dir] + existing_paths).uniq.join(File::PATH_SEPARATOR) diff --git a/habitat/aarch64-darwin/plan.sh b/habitat/aarch64-darwin/plan.sh index 70341303b..695bf7760 100644 --- a/habitat/aarch64-darwin/plan.sh +++ b/habitat/aarch64-darwin/plan.sh @@ -1,6 +1,15 @@ export HAB_BLDR_CHANNEL="base-2025" export HAB_REFRESH_CHANNEL="base-2025" ruby_pkg="core/ruby3_4" +# Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout +# rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can +# silently fail (its runtime library paths aren't set up here), which would leave +# ruby_gem_version empty and corrupt every GEM_PATH entry that uses it. +ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" +if [[ -z "$ruby_gem_version" ]]; then + build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" + ruby_gem_version="3.4.0" +fi pkg_name="ohai" pkg_origin="chef" pkg_maintainer="The Chef Maintainers " @@ -117,7 +126,12 @@ set -e export PATH="$(pkg_path_for ${ruby_pkg})/bin:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:$pkg_prefix/vendor/bin:\$PATH" export DYLD_LIBRARY_PATH="$(pkg_path_for core/libarchive)/lib:\$DYLD_LIBRARY_PATH" export GEM_HOME="$pkg_prefix/vendor" -export GEM_PATH="$pkg_prefix/vendor" +# GEM_PATH includes the flat vendor tree, the bundler-nested vendor tree +# (vendor/ruby/VERSION, where train-core and other runtime deps are installed), the +# standard user gem dir (~/.gem/ruby/VERSION), and the Chef gem dir +# (~/.chef/ruby/VERSION/gems) so that both ohai's own runtime deps and plugins installed +# via 'gem install' or 'chef gem install' are found at runtime. +export GEM_PATH="$pkg_prefix/vendor:$pkg_prefix/vendor/ruby/${ruby_gem_version}:\${HOME}/.gem/ruby/${ruby_gem_version}:\${HOME}/.chef/ruby/${ruby_gem_version}/gems" exec $(pkg_path_for ${ruby_pkg})/bin/ruby $pkg_prefix/libexec/ohai "\$@" EOF diff --git a/habitat/plan.ps1 b/habitat/plan.ps1 index 47299d532..445a60dcf 100644 --- a/habitat/plan.ps1 +++ b/habitat/plan.ps1 @@ -85,6 +85,19 @@ function Invoke-Install { Write-BuildLine "** generating binstubs for ohai with precise version pins $project_root $pkg_prefix/bin " Invoke-Expression -Command "appbundler.bat $project_root $pkg_prefix/bin ohai" If ($lastexitcode -ne 0) { Exit $lastexitcode } + + Write-BuildLine "** patching binstubs for direct execution and dynamic plugin loading" + $binstubPatch = Get-Content -Path "$project_root\binstub_patch.rb" + Get-ChildItem "$pkg_prefix\bin" | Where-Object { $_.Extension -notin @(".bat", ".ps1") } | ForEach-Object { + $lines = Get-Content -Path $_.FullName + $matchLine = $lines | Select-String -Pattern 'require "rubygems"' | Select-Object -First 1 + if ($matchLine) { + $lineNum = $matchLine.LineNumber # 1-based; insert patch after this line + $newLines = $lines[0..($lineNum - 1)] + $binstubPatch + $lines[$lineNum..($lines.Count - 1)] + Set-Content -Path $_.FullName -Value $newLines + } + } + Write-BuildLine " ** Running the ohai project's 'rake install' to install the path-based gems so they look like any other installed gem." If ($lastexitcode -ne 0) { Exit $lastexitcode } diff --git a/habitat/plan.sh b/habitat/plan.sh index 36c0e8804..417e84808 100644 --- a/habitat/plan.sh +++ b/habitat/plan.sh @@ -1,6 +1,15 @@ export HAB_BLDR_CHANNEL="base-2025" export HAB_REFRESH_CHANNEL="base-2025" ruby_pkg="core/ruby3_4" +# Derive the Ruby API version (e.g. 3.4.0) from the packaged Ruby's on-disk gem layout +# rather than executing `ruby -e`. Invoking the hab-provided ruby during the build can +# silently fail (its runtime library paths aren't set up here), which would leave +# ruby_gem_version empty and corrupt every GEM_PATH entry that uses it. +ruby_gem_version="$(basename "$(pkg_path_for "${ruby_pkg}")/lib/ruby/gems/"*)" +if [[ -z "$ruby_gem_version" ]]; then + build_line "WARNING: unable to determine Ruby API version from ${ruby_pkg}; falling back to 3.4.0" + ruby_gem_version="3.4.0" +fi pkg_name="ohai" pkg_origin="chef" pkg_maintainer="The Chef Maintainers " @@ -99,7 +108,12 @@ set -e export PATH="$(pkg_path_for ${ruby_pkg})/bin:/sbin:/usr/sbin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:\$PATH" export LD_LIBRARY_PATH="$(pkg_path_for core/libarchive)/lib:\$LD_LIBRARY_PATH" export GEM_HOME="$pkg_prefix/vendor" -export GEM_PATH="$pkg_prefix/vendor" +# GEM_PATH includes the flat vendor tree, the bundler-nested vendor tree +# (vendor/ruby/VERSION, where train-core and other runtime deps are installed), the +# standard user gem dir (~/.gem/ruby/VERSION), and the Chef gem dir +# (~/.chef/ruby/VERSION/gems) so that both ohai's own runtime deps and plugins installed +# via 'gem install' or 'chef gem install' are found at runtime. +export GEM_PATH="$pkg_prefix/vendor:$pkg_prefix/vendor/ruby/${ruby_gem_version}:\${HOME}/.gem/ruby/${ruby_gem_version}:\${HOME}/.chef/ruby/${ruby_gem_version}/gems" exec $(pkg_path_for ${ruby_pkg})/bin/ruby $pkg_prefix/libexec/ohai "\$@" EOF