lib/licensed/sources/bundler.rb in licensed-2.0.1 vs lib/licensed/sources/bundler.rb in licensed-2.1.0

- old
+ new

@@ -1,6 +1,7 @@ # frozen_string_literal: true +require "delegate" begin require "bundler" rescue LoadError end @@ -34,10 +35,47 @@ def error "could not find #{name} (#{requirement}) in any sources" end end + class BundlerSpecification < ::SimpleDelegator + def gem_dir + dir = super + return dir if File.exist?(dir) + + File.join(Gem.dir, "gems", full_name) + end + end + + class Dependency < Licensed::Dependency + attr_reader :loaded_from + + def initialize(name:, version:, path:, loaded_from:, errors: [], metadata: {}) + @loaded_from = loaded_from + super name: name, version: version, path: path, errors: errors, metadata: metadata + end + + # Load a package manager file from the base Licensee::Projects::FsProject + # or from a gem specification file. + def package_file + super || spec_file + end + + private + + # Find a package manager file from the given bundler specification's + # `loaded_from` if available. + def spec_file + return @spec_file if defined?(@spec_file) + return @spec_file = nil unless loaded_from && File.exist?(loaded_from) + @spec_file = begin + file = { name: File.basename(loaded_from), dir: File.dirname(loaded_from) } + Licensee::ProjectFiles::PackageManagerFile.new(File.read(loaded_from), file) + end + end + end + GEMFILES = %w{Gemfile gems.rb}.freeze DEFAULT_WITHOUT_GROUPS = %i{development test} def enabled? # running a ruby-packer-built licensed exe when ruby isn't available @@ -48,14 +86,15 @@ def enumerate_dependencies with_local_configuration do specs.map do |spec| error = spec.error if spec.respond_to?(:error) - Licensed::Dependency.new( + Dependency.new( name: spec.name, version: spec.version.to_s, path: spec.gem_dir, + loaded_from: spec.loaded_from, errors: Array(error), metadata: { "type" => Bundler.type, "summary" => spec.summary, "homepage" => spec.homepage @@ -110,11 +149,11 @@ # find a specifiction from the resolved ::Bundler::Definition specs spec = definition.resolve.find { |s| s.satisfies?(dependency) } # a nil spec should be rare, generally only seen from bundler - return bundle_exec_gem_spec(dependency.name) if spec.nil? + return matching_spec(dependency) || bundle_exec_gem_spec(dependency.name) if spec.nil? # try to find a non-lazy specification that matches `spec` # spec.source.specs gives access to specifications with more # information than spec itself, including platform-specific gems. # these objects should have all the information needed to detect license metadata @@ -177,9 +216,24 @@ spec.gem_dir spec end rescue Licensed::Shell::Error # return nil + ensure + ::Bundler.configure + end + end + + # Loads a dependency specification using rubygems' built-in + # `Dependency#matching_specs` and `Dependency#to_spec`, from the original + # gem environment + def matching_spec(dependency) + begin + ::Bundler.with_original_env do + ::Bundler.rubygems.clear_paths + return unless dependency.matching_specs(true).any? + BundlerSpecification.new(dependency.to_spec) + end ensure ::Bundler.configure end end