lib/license_finder/package.rb
# frozen_string_literal: true
require 'license_finder/package_utils/licensing'
require 'license_finder/package_utils/license_files'
require 'license_finder/package_utils/notice_files'
module LicenseFinder
# Super-class that adapts data from different package management
# systems (gems, npm, pip, etc.) to a common interface.
#
# Guidance on adding a new system
#
# - subclass Package, and initialize based on the data you receive from the
# package manager
# - if the package specs will report license names, pass :spec_licenses in the
# constructor options
# - if the package's files can be searched for licenses pass :install_path in
# the constructor options
# - otherwise, override #licenses_from_spec or #license_files
class Package
attr_reader :logger, :name, :version, :authors, :summary, :description, :children, :parents, :groups, :manual_approval, :license_names_from_spec, :install_path
def self.license_names_from_standard_spec(spec)
licenses = spec['licenses'] || [spec['license']].compact
licenses = [licenses] unless licenses.is_a?(Array)
licenses = licenses.flatten
licenses.map do |license|
if license.is_a? Hash
license['type']
else
license
end
end
end
def initialize(name, version = nil, options = {})
@logger = options[:logger] || Core.default_logger
## DESCRIPTION
@name = name
@version = version || ''
@authors = options[:authors] || ''
@summary = options[:summary] || ''
@description = options[:description] || ''
@homepage = options[:homepage] || ''
@package_url = options[:package_url].to_s
@children = options[:children] || []
@parents = Set.new # will be figured out later by package manager
@groups = options[:groups] || []
## APPROVAL
@permitted = false
@restricted = false
@manual_approval = nil
## LICENSING
@license_names_from_spec = options[:spec_licenses] || []
@install_path = options[:install_path]
@missing = options[:missing] || false
@decided_licenses = Set.new
end
## DESCRIPTION
attr_accessor :homepage, :package_url
## APPROVAL
def approved_manually!(approval)
@manual_approval = approval
end
def approved_manually?
!@manual_approval.nil?
end
def approved?
# Question: is `!restricted?` redundant?
# DecisionApplier does not call `permitted!` or `approved_manually!`
# if a Package has been restricted.
(approved_manually? || permitted?) && !restricted?
end
def permitted!
@permitted = true
end
def permitted?
@permitted
end
def restricted!
@restricted = true
end
def restricted?
@restricted
end
## EQUALITY
def <=>(other)
eq_name = name <=> other.name
return eq_name unless eq_name.zero?
version <=> other.version
end
def eql?(other)
name == other.name && version == other.version
end
def hash
[name, version].hash
end
## LICENSING # stubbed in tests, otherwise private # checked in tests, otherwise private
def licenses
@licenses ||= activations.map(&:license).sort_by(&:name).to_set
end
def activations
licensing.activations.tap do |activations|
activations.each { |activation| log_activation activation }
end
end
def licensing
Licensing.new(self, @decided_licenses, licenses_from_spec, license_files)
end
def decide_on_license(license)
@decided_licenses << license
end
def licenses_from_spec
license_names_from_spec
.map { |name| License.find_by_name(name) }
.to_set
end
def license_files
LicenseFiles.find(install_path, logger: logger)
end
def notice_files
NoticeFiles.find(install_path, logger: logger)
end
def package_manager
'unknown'
end
def missing?
@missing
end
def log_activation(activation)
preamble = format('package %s:', activation.package.name)
if activation.sources.empty?
logger.debug activation.package.class, format('%s no licenses found', preamble)
else
activation.sources.each do |source|
logger.debug activation.package.class, format("%s found license '%s' %s", preamble, activation.license.name, source)
end
end
end
end
end
require 'license_finder/packages/manual_package'
require 'license_finder/packages/bower_package'
require 'license_finder/packages/go_package'
require 'license_finder/packages/bundler_package'
require 'license_finder/packages/pip_package'
require 'license_finder/packages/npm_package'
require 'license_finder/packages/maven_package'
require 'license_finder/packages/gradle_package'
require 'license_finder/packages/cocoa_pods_package'
require 'license_finder/packages/carthage_package'
require 'license_finder/packages/spm_package'
require 'license_finder/packages/rebar_package'
require 'license_finder/packages/erlangmk_package'
require 'license_finder/packages/mix_package'
require 'license_finder/packages/merged_package'
require 'license_finder/packages/nuget_package'
require 'license_finder/packages/conan_package'
require 'license_finder/packages/yarn_package'
require 'license_finder/packages/pnpm_package'
require 'license_finder/packages/sbt_package'
require 'license_finder/packages/cargo_package'
require 'license_finder/packages/composer_package'
require 'license_finder/packages/conda_package'
require 'license_finder/packages/pubspec_package'