class PoisePython::Resources::PythonRuntimePip::Provider

The default provider for `python_runtime_pip`.

@see Resource @provides python_runtime_pip

Public Instance Methods

action_install() click to toggle source

The `install` action for the `python_runtime_pip` resource.

@return [void]

# File lib/poise_python/resources/python_runtime_pip.rb, line 81
def action_install
  Chef::Log.debug("[#{new_resource}] Installing pip #{new_resource.version || 'latest'}, currently #{current_resource.version || 'not installed'}")
  if new_resource.version && current_resource.version == new_resource.version
    Chef::Log.debug("[#{new_resource}] Pip #{current_resource.version} is already at requested version")
    return # Desired version is installed, even if ancient.
  # If you have older than 7.0.0, we're re-bootstraping because lolno.
  elsif current_resource.version && Gem::Version.create(current_resource.version) >= PIP_INPLACE_VERSION
    install_pip
  else
    bootstrap_pip
  end
end
action_uninstall() click to toggle source

The `uninstall` action for the `python_runtime_pip` resource.

@return [void]

# File lib/poise_python/resources/python_runtime_pip.rb, line 97
def action_uninstall
  notifying_block do
    python_package 'pip' do
      action :uninstall
      parent_python new_resource.parent
    end
  end
end
load_current_resource() click to toggle source

@api private

Calls superclass method
# File lib/poise_python/resources/python_runtime_pip.rb, line 71
def load_current_resource
  super.tap do |current_resource|
    # Try to find the current version if possible.
    current_resource.version(pip_version)
  end
end

Private Instance Methods

bootstrap_pip() click to toggle source

Bootstrap pip using get-pip.py.

@return [void]

# File lib/poise_python/resources/python_runtime_pip.rb, line 111
def bootstrap_pip
  # If we're on Python 2.6 and using the default get_pip_url, we need to
  # switch to a 2.6-compatible version. This kind of sucks because it
  # makes the default a magic value but it seems like the safest option.
  get_pip_url = new_resource.get_pip_url
  if get_pip_url == 'https://bootstrap.pypa.io/get-pip.py'
    python_version_cmd = poise_shell_out!([new_resource.parent.python_binary, '--version'], environment: new_resource.parent.python_environment)
    # Python 2 puts the output on stderr, 3 is on stdout. You can't make this shit up.
    python_version = (python_version_cmd.stdout + python_version_cmd.stderr)[/Python (\S+)/, 1]
    Chef::Log.debug("[#{new_resource}] Checking for Python 2.6 fixup of get-pip URL, found Python version #{python_version || '(unknown)'}")
    if python_version && Gem::Version.create(python_version) < PY26_FIXUP_VERSION
      Chef::Log.debug("[#{new_resource}] Detected old Python, enabling fixup")
      get_pip_url = PY26_FIXUP_GETPIP_URL
    end
  end

  # Always updated if we have hit this point.
  converge_by("Bootstrapping pip #{new_resource.version || 'latest'} from #{get_pip_url}") do
    # Use a temp file to hold the installer.
    # Put `Tempfile.create` back when Chef on Windows has a newer Ruby.
    # Tempfile.create(['get-pip', '.py']) do |temp|
    temp = Tempfile.new(['get-pip', '.py'])
    begin
      # Download the get-pip.py.
      get_pip = Chef::HTTP.new(get_pip_url).get('')
      # Write it to the temp file.
      temp.write(get_pip)
      # Close the file to flush it.
      temp.close
      # Run the install. This probably needs some handling for proxies et
      # al. Disable setuptools and wheel as we will install those later.
      # Use the environment vars instead of CLI arguments so I don't have
      # to deal with bootstrap versions that don't support --no-wheel.
      boostrap_cmd = [new_resource.parent.python_binary, temp.path, '--upgrade', '--force-reinstall']
      boostrap_cmd << "pip==#{new_resource.version}" if new_resource.version
      Chef::Log.debug("[#{new_resource}] Running pip bootstrap command: #{boostrap_cmd.join(' ')}")
      # Gross is_a? hacks but because python_runtime is a container, it
      # gets the full DSL and this has user and group methods from that.
      user = new_resource.parent.is_a?(PoisePython::Resources::PythonVirtualenv::Resource) ? new_resource.parent.user : nil
      group = new_resource.parent.is_a?(PoisePython::Resources::PythonVirtualenv::Resource) ? new_resource.parent.group : nil
      FileUtils.chown(user, group, temp.path) if user || group
      poise_shell_out!(boostrap_cmd, environment: new_resource.parent.python_environment.merge('PIP_NO_SETUPTOOLS' => '1', 'PIP_NO_WHEEL' => '1'), group: group, user: user)
    ensure
      temp.close unless temp.closed?
      temp.unlink
    end
    new_pip_version = pip_version
    if new_resource.version && new_pip_version != new_resource.version
      # We probably want to downgrade, which is silly but ¯\_(ツ)_/¯.
      # Can be removed once https://github.com/pypa/pip/issues/1087 is fixed.
      # That issue is fixed, leaving a bit longer for older vendored scripts.
      Chef::Log.debug("[#{new_resource}] Pip bootstrap installed #{new_pip_version}, trying to install again for #{new_resource.version}")
      current_resource.version(new_pip_version)
      install_pip
    end
  end
end
install_pip() click to toggle source

Upgrade (or downgrade) pip using itself. Should work back at least pip 1.5.

@return [void]

# File lib/poise_python/resources/python_runtime_pip.rb, line 173
def install_pip
  if new_resource.version
    # Already up to date, we're done here.
    return if current_resource.version == new_resource.version
  else
    # We don't wany a specific version, so just make a general check.
    return if current_resource.version
  end

  Chef::Log.debug("[#{new_resource}] Installing pip #{new_resource.version} via itself")
  notifying_block do
    # Use pip to upgrade (or downgrade) itself.
    python_package 'pip' do
      action :upgrade
      parent_python new_resource.parent
      version new_resource.version if new_resource.version
      allow_downgrade true
    end
  end
end
pip_version() click to toggle source

Find the version of pip currently installed in this Python runtime. Returns nil if not installed.

@return [String, nil]

# File lib/poise_python/resources/python_runtime_pip.rb, line 198
def pip_version
  version_cmd = [new_resource.parent.python_binary, '-m', 'pip.__main__', '--version']
  Chef::Log.debug("[#{new_resource}] Running pip version command: #{version_cmd.join(' ')}")
  cmd = poise_shell_out(version_cmd, environment: new_resource.parent.python_environment)
  if cmd.error?
    # Not installed, probably.
    nil
  else
    cmd.stdout[/pip ([\d.a-z]+)/, 1]
  end
end