Class: Licensed::Source::Bundler
- Inherits:
-
Object
- Object
- Licensed::Source::Bundler
- Defined in:
- lib/licensed/source/bundler.rb
Constant Summary collapse
- GEMFILES =
%w{Gemfile gems.rb}.freeze
- DEFAULT_WITHOUT_GROUPS =
i{development test}
Class Method Summary collapse
Instance Method Summary collapse
-
#bundler_spec ⇒ Object
Returns a gemspec for bundler, found and loaded by running ‘gem specification bundler` This is a hack to work around bundler not placing it’s own spec at ‘::Bundler.specs_path` when it’s an explicit dependency.
-
#definition ⇒ Object
Build the bundler definition.
- #dependencies ⇒ Object
- #enabled? ⇒ Boolean
-
#exclude_development_dependencies? ⇒ Boolean
Returns whether development dependencies should be excluded.
-
#exclude_groups ⇒ Object
Returns any groups to exclude specified from both licensed configuration and bundler configuration.
-
#gem_spec(dependency) ⇒ Object
Returns a Gem::Specification for the provided gem argument.
-
#gemfile_path ⇒ Object
Returns the path to the Bundler Gemfile.
-
#groups ⇒ Object
Returns the bundle definition groups, removing “without” groups, and including “with” groups.
-
#include?(dependency, source) ⇒ Boolean
Returns whether a dependency should be included in the final.
-
#initialize(config) ⇒ Bundler
constructor
A new instance of Bundler.
-
#lockfile_path ⇒ Object
Returns the path to the Bundler Gemfile.lock.
-
#recursive_specs(specs, results = Set.new) ⇒ Object
Recursively finds the dependencies for Gem specifications.
-
#specs ⇒ Object
Returns an array of Gem::Specifications for all gem dependencies.
-
#specs_for_dependencies(dependencies, source) ⇒ Object
Returns the specs for dependencies that pass the checks in ‘include?` Raises an error if the specification isn’t found.
Constructor Details
#initialize(config) ⇒ Bundler
Returns a new instance of Bundler.
17 18 19 |
# File 'lib/licensed/source/bundler.rb', line 17 def initialize(config) @config = config end |
Class Method Details
.type ⇒ Object
13 14 15 |
# File 'lib/licensed/source/bundler.rb', line 13 def self.type "rubygem" end |
Instance Method Details
#bundler_spec ⇒ Object
Returns a gemspec for bundler, found and loaded by running ‘gem specification bundler` This is a hack to work around bundler not placing it’s own spec at ‘::Bundler.specs_path` when it’s an explicit dependency
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/licensed/source/bundler.rb', line 142 def bundler_spec # cache this so we run CLI commands as few times as possible return @bundler_spec if defined?(@bundler_spec) # finding the bundler gem is dependent on having `gem` available unless Licensed::Shell.tool_available?("gem") @bundler_spec = nil return end # Bundler is always used from the default gem install location. # we can use `gem specification bundler` with a clean ENV to # get the system bundler gem as YAML yaml = ::Bundler.with_original_env { Licensed::Shell.execute("gem", "specification", "bundler") } @bundler_spec = Gem::Specification.from_yaml(yaml) end |
#definition ⇒ Object
Build the bundler definition
160 161 162 |
# File 'lib/licensed/source/bundler.rb', line 160 def definition @definition ||= ::Bundler::Definition.build(gemfile_path, lockfile_path, nil) end |
#dependencies ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/licensed/source/bundler.rb', line 25 def dependencies @dependencies ||= with_local_configuration do specs.map do |spec| Licensed::Dependency.new(spec.gem_dir, { "type" => Bundler.type, "name" => spec.name, "version" => spec.version.to_s, "summary" => spec.summary, "homepage" => spec.homepage }) end end end |
#enabled? ⇒ Boolean
21 22 23 |
# File 'lib/licensed/source/bundler.rb', line 21 def enabled? defined?(::Bundler) && lockfile_path && lockfile_path.exist? end |
#exclude_development_dependencies? ⇒ Boolean
Returns whether development dependencies should be excluded
130 131 132 133 134 135 136 137 |
# File 'lib/licensed/source/bundler.rb', line 130 def exclude_development_dependencies? @include_development ||= begin # check whether the development dependency group is explicitly removed # or added via bundler and licensed configurations groups = [:development] - Array(::Bundler.settings[:without]) + Array(::Bundler.settings[:with]) - exclude_groups !groups.include?(:development) end end |
#exclude_groups ⇒ Object
Returns any groups to exclude specified from both licensed configuration and bundler configuration. Defaults to [:development, :test] + ::Bundler.settings
173 174 175 176 177 178 179 |
# File 'lib/licensed/source/bundler.rb', line 173 def exclude_groups @exclude_groups ||= begin exclude = Array(@config.dig("rubygems", "without")) exclude.push(*DEFAULT_WITHOUT_GROUPS) if exclude.empty? exclude.uniq.map(&:to_sym) end end |
#gem_spec(dependency) ⇒ Object
Returns a Gem::Specification for the provided gem argument. If a Gem::Specification isn’t found, an error will be raised.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/licensed/source/bundler.rb', line 80 def gem_spec(dependency) return unless dependency # bundler specifications aren't put in ::Bundler.specs_path, even if the # gem is a runtime dependency. it needs to be handled specially return bundler_spec if dependency.name == "bundler" # find a specifiction from the resolved ::Bundler::Definition specs spec = definition.resolve.find { |s| s.satisfies?(dependency) } return spec unless spec.is_a?(::Bundler::LazySpecification) # if the specification is coming from a gemspec source, # we can get a non-lazy specification straight from the source if spec.source.is_a?(::Bundler::Source::Gemspec) || spec.source.is_a?(::Bundler::Source::Path) return spec.source.specs.first end # spec.source.specs gives access to specifications with more # information than spec itself, including platform-specific gems. # try to find a specification that matches `spec` if source_spec = spec.source.specs.find { |s| s.name == spec.name && s.version == spec.version } spec = source_spec end # look for a specification at the bundler specs path spec_path = ::Bundler.specs_path.join("#{spec.full_name}.gemspec") return unless File.exist?(spec_path.to_s) Gem::Specification.load(spec_path.to_s) end |
#gemfile_path ⇒ Object
Returns the path to the Bundler Gemfile
182 183 184 185 |
# File 'lib/licensed/source/bundler.rb', line 182 def gemfile_path @gemfile_path ||= GEMFILES.map { |g| @config.pwd.join g } .find { |f| f.exist? } end |
#groups ⇒ Object
Returns the bundle definition groups, removing “without” groups, and including “with” groups
166 167 168 |
# File 'lib/licensed/source/bundler.rb', line 166 def groups definition.groups - Array(::Bundler.settings[:without]) + Array(::Bundler.settings[:with]) - exclude_groups end |
#include?(dependency, source) ⇒ Boolean
Returns whether a dependency should be included in the final
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/licensed/source/bundler.rb', line 111 def include?(dependency, source) # ::Bundler::Dependency has an extra `should_include?` return false unless dependency.should_include? if dependency.respond_to?(:should_include?) # Don't return gems added from `add_development_dependency` in a gemspec # if the :development group is excluded gemspec_source = source.is_a?(::Bundler::Source::Gemspec) return false if dependency.type == :development && (!gemspec_source || exclude_development_dependencies?) # Gem::Dependency don't have groups - in our usage these objects always # come as child-dependencies and are never directly from a Gemfile. # We assume that all Gem::Dependencies are ok at this point return true if dependency.groups.nil? # check if the dependency is in any groups we're interested in (dependency.groups & groups).any? end |
#lockfile_path ⇒ Object
Returns the path to the Bundler Gemfile.lock
188 189 190 191 |
# File 'lib/licensed/source/bundler.rb', line 188 def lockfile_path return unless gemfile_path @lockfile_path ||= gemfile_path.dirname.join("#{gemfile_path.basename}.lock") end |
#recursive_specs(specs, results = Set.new) ⇒ Object
Recursively finds the dependencies for Gem specifications. Returns a ‘Set` containing the package names for all dependencies
54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/licensed/source/bundler.rb', line 54 def recursive_specs(specs, results = Set.new) return [] if specs.nil? || specs.empty? new_specs = Set.new(specs) - results.to_a return [] if new_specs.empty? results.merge new_specs dependency_specs = new_specs.flat_map { |s| specs_for_dependencies(s.dependencies, s.source) } return results if dependency_specs.empty? results.merge recursive_specs(dependency_specs, results) end |
#specs ⇒ Object
Returns an array of Gem::Specifications for all gem dependencies
40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/licensed/source/bundler.rb', line 40 def specs # get the specifications for all dependencies in a Gemfile root_dependencies = definition.dependencies.select { |d| include?(d, nil) } root_specs = specs_for_dependencies(root_dependencies, nil).compact # recursively find the remaining specifications all_specs = recursive_specs(root_specs) # delete any specifications loaded from a gemspec all_specs.delete_if { |s| s.source.is_a?(::Bundler::Source::Gemspec) } end |
#specs_for_dependencies(dependencies, source) ⇒ Object
Returns the specs for dependencies that pass the checks in ‘include?` Raises an error if the specification isn’t found
71 72 73 74 75 76 |
# File 'lib/licensed/source/bundler.rb', line 71 def specs_for_dependencies(dependencies, source) included_dependencies = dependencies.select { |d| include?(d, source) } included_dependencies.map do |dep| gem_spec(dep) || raise("Unable to find a specification for #{dep.name} (#{dep.requirement}) in any sources") end end |