# frozen_string_literal: true module LicenseFinder class Pipenv def prepare create_vendor_path within_project_path do return unless pipfile? tool_box.install(tool: :python, version: python_version, env: default_env) shell.execute([:asdf, :exec, :pipenv, '--python', python_version], env: default_env, capture: false) shell.execute([:asdf, :exec, :pipenv, :sync], env: default_env, capture: false) end end def current_packages within_project_path do return legacy_results unless pipfile? dependencies = pip_licenses.map do |dependency| ::LicenseFinder::Dependency.new( 'Pip', dependency['Name'], dependency['Version'], description: dependency['Description'], detection_path: detected_package_path, homepage: dependency['URL'], spec_licenses: [dependency['License']] ) end dependencies.any? ? dependencies : legacy_results end end private def python_version(env: ENV) @python_version ||= begin version = lockfile_hash.dig('_meta', 'requires', 'python_version') version ? tool_box.closest_match_to(tool: :python, version: version) || version : tool_box.version_of(:python, env: env) end end def pipfile? detected_package_path.dirname.join('Pipfile').exist? end def legacy_results packages = {} each_dependency(groups: allowed_groups) do |name, data, group| version = canonicalize(data['version']) package = packages.fetch(key_for(name, version)) do |key| packages[key] = PipPackage.new(name, version, PyPI.definition(name, version)) end package.groups << group end packages.values end def lockfile_hash @lockfile_hash ||= JSON.parse(detected_package_path.read) end def pip_licenses _, _, status = shell.sh([". .venv/bin/activate", '&&', 'pip', 'install', '--no-index', "--find-links /opt/gitlab/.config/virtualenv/app-data", 'pip-licenses'], env: default_env) shell.sh([". .venv/bin/activate", '&&', 'pip', 'install', 'pip-licenses'], env: default_env) unless status.success? stdout, _stderr, status = shell.sh([". .venv/bin/activate", '&&', 'pip-licenses', '--with-description', '--with-urls', '--format=json'], env: default_env) status.success? ? JSON.parse(stdout[stdout.index('[')..-1]) : [] end def default_env @default_env ||= { 'PIPENV_PYPI_MIRROR' => ENV.fetch('PIP_INDEX_URL', 'https://pypi.org/simple/'), 'PIP_CERT' => ENV.fetch('PIP_CERT', shell.default_certificate_path).to_s, 'PIP_DISABLE_PIP_VERSION_CHECK' => '1', 'PIP_NO_PYTHON_VERSION_WARNING' => '1' } end end end