class Kitchen::Provisioner::Chef::Policyfile

Chef cookbook resolver that uses Policyfiles to calculate dependencies.

@author Fletcher Nichol <fnichol@nichol.ca>

Attributes

always_update[R]

@return [Boolean] If true, always update cookbooks in the policy. @api private

license[R]

@return [String] name of the chef_license @api private

logger[R]

@return [Kitchen::Logger] a logger to use for output @api private

path[R]

@return [String] path in which to vendor the resulting cookbooks @api private

policy_group[R]

@return [String] name of the policy_group, nil results in “local” @api private

policyfile[R]

@return [String] path to a Policyfile @api private

Public Class Methods

load!(logger: Kitchen.logger) click to toggle source

Loads the library code required to use the resolver.

@param logger [Kitchen::Logger] a logger to use for output, defaults

to `Kitchen.logger`
# File lib/kitchen/provisioner/chef/policyfile.rb, line 57
def self.load!(logger: Kitchen.logger)
  # intentionally left blank
end
new(policyfile, path, license: nil, logger: Kitchen.logger, always_update: false, policy_group: nil) click to toggle source

Creates a new cookbook resolver.

@param policyfile [String] path to a Policyfile @param path [String] path in which to vendor the resulting

cookbooks

@param logger [Kitchen::Logger] a logger to use for output, defaults

to `Kitchen.logger`
# File lib/kitchen/provisioner/chef/policyfile.rb, line 44
def initialize(policyfile, path, license: nil, logger: Kitchen.logger, always_update: false, policy_group: nil)
  @policyfile    = policyfile
  @path          = path
  @logger        = logger
  @always_update = always_update
  @policy_group  = policy_group
  @license       = license
end

Public Instance Methods

compile() click to toggle source

Runs `chef install` to determine the correct cookbook set and generate the policyfile lock.

# File lib/kitchen/provisioner/chef/policyfile.rb, line 75
def compile
  if File.exist?(lockfile)
    info("Installing cookbooks for Policyfile #{policyfile} using `#{cli_path} install`")
  else
    info("Policy lock file doesn't exist, running `#{cli_path} install` for Policyfile #{policyfile}...")
  end
  run_command("#{cli_path} install #{escape_path(policyfile)} --chef-license #{license}")

  if always_update
    info("Updating policy lock using `#{cli_path} update`")
    run_command("#{cli_path} update #{escape_path(policyfile)} --chef-license #{license}")
  end
end
lockfile() click to toggle source

Return the path to the lockfile corresponding to this policyfile.

@return [String]

# File lib/kitchen/provisioner/chef/policyfile.rb, line 92
def lockfile
  policyfile.gsub(/\.rb\Z/, ".lock.json")
end
resolve() click to toggle source

Performs the cookbook resolution and vendors the resulting cookbooks in the desired path.

# File lib/kitchen/provisioner/chef/policyfile.rb, line 63
def resolve
  if policy_group
    info("Exporting cookbook dependencies from Policyfile #{path} with policy_group #{policy_group} using `#{cli_path} export`...")
    run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --policy_group #{policy_group} --force --chef-license #{license}")
  else
    info("Exporting cookbook dependencies from Policyfile #{path} using `#{cli_path} export`...")
    run_command("#{cli_path} export #{escape_path(policyfile)} #{escape_path(path)} --force --chef-license #{license}")
  end
end

Private Instance Methods

cli_path() click to toggle source

Find the `chef` or `chef-cli` commands in the path or raise `chef` is present in ChefDK / Workstation releases, but is no longer shipped in any gems now that we use a Go based wrapper for the `chef` command in Workstation. The Ruby CLI has been renamed `chef-cli` under the hood and is shipped in the `chef-cli` gem.

@api private @returns [String]

# File lib/kitchen/provisioner/chef/policyfile.rb, line 152
def cli_path
  @cli_path ||= which("chef-cli") || which("chef") || no_cli_found_error
end
escape_path(path) click to toggle source

Escape spaces in a path in way that works with both Sh (Unix) and Windows.

@param path [String] Path to escape @return [String] @api private

# File lib/kitchen/provisioner/chef/policyfile.rb, line 128
def escape_path(path)
  if /mswin|mingw/.match?(RbConfig::CONFIG["host_os"])
    # I know what you're thinking: "just use Shellwords.escape". That
    # method produces incorrect results on Windows with certain input
    # which would be a metacharacter in Sh but is not for one or more of
    # Windows command line parsing libraries. This covers the 99% case of
    # spaces in the path without breaking other stuff.
    if /[ \t\n\v"]/.match?(path)
      "\"#{path.gsub(/[ \t\n\v\"\\]/) { |m| "\\" + m[0] }}\""
    else
      path
    end
  else
    Shellwords.escape(path)
  end
end
no_cli_found_error() click to toggle source

@api private

# File lib/kitchen/provisioner/chef/policyfile.rb, line 157
def no_cli_found_error
  @logger.fatal("The `chef` or `chef-cli` executables cannot be found in your " \
                "PATH. Ensure you have installed Chef Workstation " \
                "from https://www.chef.io/downloads/ and that your PATH " \
                "setting includes the path to the `chef` or `chef-cli` commands.")
  raise UserError, "Could not find the chef or chef-cli executables in your PATH."
end