diff options
| author | mo khan <mo.khan@gmail.com> | 2020-01-13 12:48:20 -0700 |
|---|---|---|
| committer | mo khan <mo.khan@gmail.com> | 2020-01-15 15:03:07 -0700 |
| commit | e98681be9b19d2a01efdbe14e7e8695b05b60010 (patch) | |
| tree | 86c461a6b6dc27fbd634dccff55e0304921f0b37 | |
| parent | 1c73ad594a26597086b76b4b08ef045247791b5f (diff) | |
Inject the Pipenv package manager
| -rw-r--r-- | lib/license/management.rb | 7 | ||||
| -rw-r--r-- | lib/license_finder/package_managers/pipenv.rb | 60 | ||||
| -rw-r--r-- | lib/license_finder/package_utils/pypi.rb | 41 |
3 files changed, 108 insertions, 0 deletions
diff --git a/lib/license/management.rb b/lib/license/management.rb index a6e0664..a2e0008 100644 --- a/lib/license/management.rb +++ b/lib/license/management.rb @@ -2,7 +2,10 @@ require 'pathname' require 'yaml' +require 'json' require 'license_finder' +require 'license_finder/package_managers/pipenv' +require 'license_finder/package_utils/pypi' require 'license/management/loggable' require 'license/management/verifiable' require 'license/management/repository' @@ -11,6 +14,10 @@ require 'license/management/version' # This applies a monkey patch to the JsonReport found in the `license_finder` gem. LicenseFinder::JsonReport.prepend(License::Management::Report) +LicenseFinder::Scanner.const_set( + :PACKAGE_MANAGERS, + LicenseFinder::Scanner::PACKAGE_MANAGERS + [LicenseFinder::Pipenv] +) # This monkey patch can be removed once we upgrade to license_finder 5.9.2. Details [here](https://gitlab.com/gitlab-org/gitlab/issues/13748#note_235810786). module LicenseFinder diff --git a/lib/license_finder/package_managers/pipenv.rb b/lib/license_finder/package_managers/pipenv.rb new file mode 100644 index 0000000..e35b85d --- /dev/null +++ b/lib/license_finder/package_managers/pipenv.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +module LicenseFinder + class Pipenv < PackageManager + def initialize(options = {}) + super + @lockfile = Pathname('Pipfile.lock') + end + + def current_packages + @current_packages ||= + begin + 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] = build_package_for(name, version) + end + package.groups << group + end + packages.values + end + end + + def possible_package_paths + project_path ? [project_path.join(@lockfile)] : [@lockfile] + end + + private + + def each_dependency(groups: []) + dependencies = JSON.parse(IO.read(detected_package_path)) + groups.each do |group| + dependencies[group].each do |name, data| + yield name, data, group + end + end + end + + def canonicalize(version) + version.sub(/^==/, '') + end + + def build_package_for(name, version) + PipPackage.new(name, version, PyPI.definition(name, version)) + end + + def key_for(name, version) + "#{name}-#{version}" + end + + def allowed_groups + %w[default develop] - ignored_groups.to_a + end + + def ignored_groups + @ignored_groups || [] + end + end +end diff --git a/lib/license_finder/package_utils/pypi.rb b/lib/license_finder/package_utils/pypi.rb new file mode 100644 index 0000000..fac02ec --- /dev/null +++ b/lib/license_finder/package_utils/pypi.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +require 'net/http' +require 'openssl' + +module LicenseFinder + class PyPI + CONNECTION_ERRORS = [ + EOFError, + Errno::ECONNREFUSED, + Errno::ECONNRESET, + Errno::ECONNRESET, + Errno::EHOSTUNREACH, + Errno::EINVAL, + Net::OpenTimeout, + Net::ProtocolError, + Net::ReadTimeout, + OpenSSL::OpenSSLError, + OpenSSL::SSL::SSLError, + SocketError, + Timeout::Error + ].freeze + + class << self + def definition(name, version) + response = request("https://pypi.org/pypi/#{name}/#{version}/json") + response.is_a?(Net::HTTPSuccess) ? JSON.parse(response.body).fetch('info', {}) : {} + rescue *CONNECTION_ERRORS + {} + end + + def request(location, limit = 10) + uri = URI(location) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + response = http.get(uri.request_uri).response + response.is_a?(Net::HTTPRedirection) && limit.positive? ? request(response['location'], limit - 1) : response + end + end + end +end |
