Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions lib/chef-cli/command/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,35 @@ def initialize(*args)

def run(params)
info = {}
info[ChefCLI::Dist::PRODUCT] = workstation_info
product_name = get_product_info
info[product_name] = workstation_info
info["Ruby"] = ruby_info
info["Path"] = paths
ui.msg YAML.dump(info)
end

def get_product_info
if omnibus_install?
ChefCLI::Dist::PRODUCT
elsif habitat_chef_dke?
ChefCLI::Dist::CHEF_DK_CLI_PACKAGE
elsif habitat_standalone?
ChefCLI::Dist::CHEF_CLI_PACKAGE
else
ChefCLI::Dist::PRODUCT
end
end

def workstation_info
info = {}
info = { "Version" => ChefCLI::VERSION }
if omnibus_install?
info["Version"] = ChefCLI::VERSION
info["Home"] = package_home
info["Install Directory"] = omnibus_root
info["Policyfile Config"] = policyfile_config
elsif habitat_chef_dke? || habitat_standalone?
info["Home"] = package_home
info["Install Directory"] = get_pkg_install_path
info["Policyfile Config"] = policyfile_config
else
info["Version"] = "Not running from within Workstation"
end
Expand All @@ -73,19 +89,27 @@ def ruby_info

def gem_environment
h = {}
h["GEM ROOT"] = omnibus_env["GEM_ROOT"]
h["GEM HOME"] = omnibus_env["GEM_HOME"]
h["GEM PATHS"] = omnibus_env["GEM_PATH"].split(File::PATH_SEPARATOR)
rescue OmnibusInstallNotFound
h["GEM_ROOT"] = ENV["GEM_ROOT"] if ENV.key?("GEM_ROOT")
h["GEM_HOME"] = ENV["GEM_HOME"] if ENV.key?("GEM_HOME")
h["GEM PATHS"] = ENV["GEM_PATH"].split(File::PATH_SEPARATOR) if ENV.key?("GEM_PATH") && !ENV.key?("GEM_PATH").nil?
ensure
if habitat_install?
# Habitat-specific environment variables
h["GEM ROOT"] = habitat_env(show_warning: true)["GEM_ROOT"]
h["GEM HOME"] = habitat_env(show_warning: true)["GEM_HOME"]
h["GEM PATHS"] = habitat_env(show_warning: true)["GEM_PATH"].split(File::PATH_SEPARATOR)
elsif omnibus_install?
# Omnibus-specific environment variables
h["GEM ROOT"] = omnibus_env["GEM_ROOT"]
h["GEM HOME"] = omnibus_env["GEM_HOME"]
h["GEM PATHS"] = omnibus_env["GEM_PATH"].split(File::PATH_SEPARATOR)
else
# Fallback to system environment variables if neither Omnibus nor Habitat
h["GEM_ROOT"] = ENV["GEM_ROOT"] if ENV.key?("GEM_ROOT")
h["GEM_HOME"] = ENV["GEM_HOME"] if ENV.key?("GEM_HOME")
h["GEM PATHS"] = ENV["GEM_PATH"].split(File::PATH_SEPARATOR) if ENV.key?("GEM_PATH") && !ENV["GEM_PATH"].nil?
end
h
end

def paths
env = habitat_install? ? habitat_env : omnibus_env
env = habitat_install? ? habitat_env(show_warning: true) : omnibus_env
env["PATH"].split(File::PATH_SEPARATOR)
rescue OmnibusInstallNotFound
ENV["PATH"].split(File::PATH_SEPARATOR)
Expand Down
3 changes: 3 additions & 0 deletions lib/chef-cli/dist.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class Dist
PRODUCT = "Chef Workstation".freeze
PRODUCT_PKG_HOME = "chef-workstation".freeze

CHEF_DK_CLI_PACKAGE = "Chef Development Kit Enterprise".freeze
CHEF_CLI_PACKAGE = "Chef-Cli".freeze

# the name of the chef-cli gem
CLI_PRODUCT = "Chef CLI".freeze
CLI_GEM = "chef-cli".freeze
Expand Down
72 changes: 53 additions & 19 deletions lib/chef-cli/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,32 @@ def package_home
end
end

# Function to return the Chef CLI path based on standalone or Chef-DKE-enabled package
def get_pkg_install_path
# Check Chef-DKE package path
chef_dk_path = get_pkg_prefix(ChefCLI::Dist::CHEF_DKE_PKG_NAME)
return chef_dk_path if chef_dk_path

# Check Standalone Chef-CLI package path
chef_cli_path = fetch_chef_cli_version_pkg || get_pkg_prefix(ChefCLI::Dist::HAB_PKG_NAME)
chef_cli_path

rescue => e
ChefCLI::UI.new.err("Error fetching Chef-CLI path: #{e.message}")
nil
end

# Check Standalone Chef-cli environment variable for version
def fetch_chef_cli_version_pkg
chef_cli_version = ENV["CHEF_CLI_VERSION"]
return unless chef_cli_version

pkg_path = get_pkg_prefix("#{ChefCLI::Dist::HAB_PKG_NAME}/#{chef_cli_version}")
return pkg_path if pkg_path && Dir.exist?(pkg_path)

nil
end

# Returns the directory that contains our main symlinks.
# On Mac we place all of our symlinks under /usr/local/bin on other
# platforms they are under /usr/bin
Expand Down Expand Up @@ -128,14 +154,27 @@ def git_windows_bin_dir
#
# environment vars for habitat
#
def habitat_env
def habitat_env(show_warning: false)
@habitat_env ||=
begin
# Define the necessary paths for the Habitat environment
# If it is a chef-dke installation, we will use the chef-dke bin path.
# Otherwise, we will use the chef-cli bin path.
bin_pkg_prefix = get_pkg_prefix(habitat_chef_dke? ? ChefCLI::Dist::CHEF_DKE_PKG_NAME : ChefCLI::Dist::HAB_PKG_NAME)
vendor_dir = File.join(get_pkg_prefix(ChefCLI::Dist::HAB_PKG_NAME), "vendor")
if habitat_chef_dke?
bin_pkg_prefix = get_pkg_prefix(ChefCLI::Dist::CHEF_DKE_PKG_NAME)
end
versioned_pkg_prefix = fetch_chef_cli_version_pkg if ENV["CHEF_CLI_VERSION"]

if show_warning && ENV["CHEF_CLI_VERSION"] && !versioned_pkg_prefix
ChefCLI::UI.new.msg("Warning: Habitat package '#{ChefCLI::Dist::HAB_PKG_NAME}' with version '#{ENV["CHEF_CLI_VERSION"]}' not found.")
end
# Use the first available package for bin_pkg_prefix
bin_pkg_prefix ||= versioned_pkg_prefix || get_pkg_prefix(ChefCLI::Dist::HAB_PKG_NAME)
raise "Error: Could not determine the Habitat package prefix. Ensure #{ChefCLI::Dist::HAB_PKG_NAME} is installed and CHEF_CLI_VERSION is set correctly." unless bin_pkg_prefix

# Determine vendor_dir by prioritizing the versioned package first
vendor_pkg_prefix = versioned_pkg_prefix || get_pkg_prefix(ChefCLI::Dist::HAB_PKG_NAME)
raise "Error: Could not determine the vendor package prefix. Ensure #{ChefCLI::Dist::HAB_PKG_NAME} is installed and CHEF_CLI_VERSION is set correctly." unless vendor_pkg_prefix

vendor_dir = File.join(vendor_pkg_prefix, "vendor")
# Construct PATH
path = [
File.join(bin_pkg_prefix, "bin"),
ENV["PATH"].split(File::PATH_SEPARATOR), # Preserve existing PATH
Expand All @@ -144,8 +183,8 @@ def habitat_env
{
"PATH" => path.join(File::PATH_SEPARATOR),
"GEM_ROOT" => Gem.default_dir, # Default directory for gems
"GEM_HOME" => vendor_dir, # GEM_HOME pointing to the vendor directory
"GEM_PATH" => vendor_dir, # GEM_PATH also pointing to the vendor directory
"GEM_HOME" => vendor_dir, # Set only if vendor_dir exists
"GEM_PATH" => vendor_dir, # Set only if vendor_dir exists
}
end
end
Expand All @@ -161,22 +200,17 @@ def omnibus_env
path << git_bin_dir if Dir.exist?(git_bin_dir)
path << git_windows_bin_dir if Dir.exist?(git_windows_bin_dir)
{
"PATH" => path.flatten.uniq.join(File::PATH_SEPARATOR),
"GEM_ROOT" => Gem.default_dir,
"GEM_HOME" => Gem.user_dir,
"GEM_PATH" => Gem.path.join(File::PATH_SEPARATOR),
"PATH" => path.flatten.uniq.join(File::PATH_SEPARATOR),
"GEM_ROOT" => Gem.default_dir,
"GEM_HOME" => Gem.user_dir,
"GEM_PATH" => Gem.path.join(File::PATH_SEPARATOR),
}
end
end

def get_pkg_prefix(pkg_name)
path = `hab pkg path #{pkg_name}`.strip

if $?.success? && !path.empty?
path
else
raise "Failed to get pkg_prefix for #{pkg_name}: #{path}"
end
path = `hab pkg path #{pkg_name} 2>/dev/null`.strip
path if !path.empty? && Dir.exist?(path) # Return path only if it exists
end

def omnibus_expand_path(*paths)
Expand Down
129 changes: 129 additions & 0 deletions spec/unit/command/env_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
allow(command_instance).to receive(:omnibus_install?).and_return true
allow(command_instance).to receive(:omnibus_embedded_bin_dir).and_return(omnibus_embedded_bin_dir)
allow(command_instance).to receive(:omnibus_bin_dir).and_return(omnibus_bin_dir)
allow(command_instance).to receive(:get_product_info).and_return(ChefCLI::Dist::PRODUCT)
command_instance.ui = ui
end

Expand Down Expand Up @@ -81,6 +82,134 @@
end
end
end

describe "when running in a Chef-cli Habitat Standalone package" do
let(:standalone_pkg_base) { "/hab/pkgs/chef/chef-cli" }
let(:standalone_pkg_version) { "1.0.0" }
let(:standalone_pkg_build) { "20240210120000" }
let(:standalone_pkg_path) { "#{standalone_pkg_base}/#{standalone_pkg_version}/#{standalone_pkg_build}" }

let(:ruby_version) { "3.1.0" }
let(:ruby_base) { "/hab/pkgs/core/ruby/#{ruby_version}/20240101000000/lib/ruby/gems" }
let(:cli_gem_home) { "/hab/pkgs/chef/chef-cli/#{standalone_pkg_version}/20240210121000/vendor/bundle/ruby/#{ruby_version}" }

before do
allow(command_instance).to receive(:habitat_install?).and_return(true)
allow(command_instance).to receive(:habitat_standalone?).and_return(true)
allow(command_instance).to receive(:habitat_chef_dke?).and_return(false)
allow(command_instance).to receive(:omnibus_install?).and_return(false)
allow(command_instance).to receive(:get_product_info).and_return(ChefCLI::Dist::CHEF_CLI_PACKAGE)

allow(command_instance).to receive(:get_pkg_install_path).and_return(standalone_pkg_path)

allow(command_instance).to receive(:habitat_env).and_return({
"GEM_ROOT" => ruby_base,
"GEM_HOME" => cli_gem_home,
"GEM_PATH" => cli_gem_home,
"PATH" => "#{standalone_pkg_path}/bin:/usr/local/bin:/usr/bin"
})

command_instance.ui = ui
end

describe "and the env command is run" do
let(:yaml) { YAML.load(ui.output) }

before :each do
run_command
end

it "should include correct chef-cli hab pkg name" do
expect(yaml).to have_key(ChefCLI::Dist::CHEF_CLI_PACKAGE)
end

it "should include correct chef-cli hab pkg version info" do
expect(yaml[ChefCLI::Dist::CHEF_CLI_PACKAGE]["Version"]).to eql ChefCLI::VERSION
end

it "should include correct Habitat installation path" do
expect(yaml[ChefCLI::Dist::CHEF_CLI_PACKAGE]["Install Directory"]).to eql standalone_pkg_path
end

it "should include correct GEM_ROOT path" do
expect(yaml["Ruby"]["RubyGems"]["Gem Environment"]["GEM ROOT"]).to eql ruby_base
end

it "should include correct GEM_HOME path" do
expect(yaml["Ruby"]["RubyGems"]["Gem Environment"]["GEM HOME"]).to eql cli_gem_home
end

it "should include correct GEM_PATH paths" do
expect(yaml["Ruby"]["RubyGems"]["Gem Environment"]["GEM PATHS"]).to eql [cli_gem_home]
end
end
end

describe "when running chef-cli coming with Chef-DKE Habitat package" do
let(:hab_pkg_base) { "/hab/pkgs/chef/chef-development-kit-enterprise" }
let(:hab_pkg_version) { "1.0.0" }
let(:hab_pkg_build) { "20240210120000" }
let(:hab_pkg_path) { "#{hab_pkg_base}/#{hab_pkg_version}/#{hab_pkg_build}" }

let(:ruby_version) { "3.1.0" }
let(:ruby_base) { "/hab/pkgs/core/ruby/#{ruby_version}/20240101000000/lib/ruby/gems" }
let(:cli_gem_home) { "/hab/pkgs/chef/chef-cli/#{hab_pkg_version}/20240210121000/vendor/bundle/ruby/#{ruby_version}" }

before do
# Mock all Habitat-related methods
allow(command_instance).to receive(:habitat_install?).and_return true
allow(command_instance).to receive(:habitat_chef_dke?).and_return true
allow(command_instance).to receive(:habitat_standalone?).and_return false
allow(command_instance).to receive(:omnibus_install?).and_return false
allow(command_instance).to receive(:get_product_info).and_return(ChefCLI::Dist::CHEF_DK_CLI_PACKAGE)

# Mock Habitat package paths
allow(command_instance).to receive(:get_pkg_install_path).and_return(hab_pkg_path)

# Mock habitat_env to reflect correct GEM paths
allow(command_instance).to receive(:habitat_env).and_return({
"GEM_ROOT" => ruby_base,
"GEM_HOME" => cli_gem_home,
"GEM_PATH" => cli_gem_home,
"PATH" => "#{hab_pkg_path}/bin:/usr/local/bin:/usr/bin"
})

command_instance.ui = ui
end

describe "and the env command is run" do
let(:yaml) { YAML.load(ui.output) }

before :each do
run_command
end

it "should include correct product name for Chef-DKE Habitat package" do
expect(yaml).to have_key(ChefCLI::Dist::CHEF_DK_CLI_PACKAGE)
end

it "should include correct version" do
expect(yaml[ChefCLI::Dist::CHEF_DK_CLI_PACKAGE]["Version"]).to eql ChefCLI::VERSION
end

it "should include correct Habitat installation path" do
expect(yaml[ChefCLI::Dist::CHEF_DK_CLI_PACKAGE]["Install Directory"]).to eql hab_pkg_path
end

it "should include correct GEM_ROOT path" do
expect(yaml["Ruby"]["RubyGems"]["Gem Environment"]["GEM ROOT"]).to eql ruby_base
end

it "should include correct GEM_HOME path" do
expect(yaml["Ruby"]["RubyGems"]["Gem Environment"]["GEM HOME"]).to eql cli_gem_home
end

it "should include correct GEM_PATH paths" do
expect(yaml["Ruby"]["RubyGems"]["Gem Environment"]["GEM PATHS"]).to eql [cli_gem_home]
end
end
end

def run_command
command_instance.run_with_default_options(false, command_options)
end
Expand Down
8 changes: 6 additions & 2 deletions spec/unit/helpers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,10 @@
let(:chef_dke_path) { "/hab/pkgs/chef/chef-development-kit-enterprise/1.0.0/123" }
let(:cli_hab_path) { "/hab/pkgs/chef/chef-cli/1.0.0/123" }
let(:expected_gem_root) { Gem.default_dir }
let(:expected_path) { %W{#{chef_dke_path}/bin /usr/bin:/bin} }
let(:expected_path) { [File.join(chef_dke_path, "bin"), "/usr/bin:/bin"].flatten }
let(:expected_env) do
{
"PATH" => expected_path.join(File::PATH_SEPARATOR) ,
"PATH" => expected_path.join(File::PATH_SEPARATOR),
"GEM_ROOT" => expected_gem_root,
"GEM_HOME" => "#{cli_hab_path}/vendor",
"GEM_PATH" => "#{cli_hab_path}/vendor",
Expand All @@ -127,14 +127,18 @@
allow(ChefCLI::Helpers).to receive(:habitat_chef_dke?).and_return true
allow(ChefCLI::Helpers).to receive(:habitat_standalone?).and_return false
allow(ENV).to receive(:[]).with("PATH").and_return("/usr/bin:/bin")
allow(ENV).to receive(:[]).with("CHEF_CLI_VERSION").and_return(nil)
allow(Dir).to receive(:exist?).with("#{cli_hab_path}/vendor").and_return(true) # <-- Add this line
end

it "should return the habitat env" do
allow(ChefCLI::Helpers).to receive(:fetch_chef_cli_version_pkg).and_return(nil) # Ensure no version override
expect(ChefCLI::Helpers).to receive(:get_pkg_prefix).with("chef/chef-development-kit-enterprise").and_return(chef_dke_path)
expect(ChefCLI::Helpers).to receive(:get_pkg_prefix).with("chef/chef-cli").and_return(cli_hab_path)

expect(ChefCLI::Helpers.habitat_env).to eq(expected_env)
end
end

end
end
Loading