class Diffend::LocalContext::Packages

Module responsible for building packages information from local context

Constants

DEPENDENCIES_TYPES

List of dependency types

GEM_SOURCES_TYPES

List of gem sources types

ME_PATH

Definition of a local path, if it matches it means that we are the source

ME_SOURCES

Sources that we expect to match ourselves too

SOURCES_TYPES

List of sources types

Public Class Methods

call(command, definition) click to toggle source

@param command [String] command executed via bundler @param definition [::Bundler::Definition] definition for your source

# File lib/diffend/local_context/packages.rb, line 36
def call(command, definition)
  instance = new(command, definition)

  ::Bundler.ui.silence { instance.resolve }

  case command
  when Commands::INSTALL, Commands::EXEC, Commands::SECURE, Commands::UPDATE, Commands::ADD then instance.build
  else
    raise ArgumentError, "invalid command: #{command}"
  end
end
new(command, definition) click to toggle source

@param command [String] command executed via bundler @param definition [::Bundler::Definition] definition for your source

@return [Hash] local dependencies

# File lib/diffend/local_context/packages.rb, line 53
def initialize(command, definition)
  @command = command
  @definition = definition
  @direct_dependencies = Hash[definition.dependencies.map { |val| [val.name, val] }]
  # Support case without Gemfile.lock
  @locked_specs = @definition.locked_gems ? @definition.locked_gems.specs : []
  @cached = command == Commands::EXEC
end

Public Instance Methods

build() click to toggle source

Build specification

@return [Hash]

# File lib/diffend/local_context/packages.rb, line 74
def build
  hash = build_main

  @definition.resolve.each do |spec|
    # Skip metadata
    next if spec.instance_variable_get(:@specification).nil?
    next if skip?(spec.source)

    locked_spec = @locked_specs.find { |s| s.name == spec.name }

    hash['dependencies'][spec.name] = {
      'platform' => build_spec_platform(spec, locked_spec),
      'source' => build_spec_source(spec),
      'type' => build_dependency_type(spec.name),
      'versions' => build_versions(spec, locked_spec)
    }
  end

  hash
end
resolve() click to toggle source

Resolve definition

# File lib/diffend/local_context/packages.rb, line 63
def resolve
  @cached ? @definition.resolve_with_cache! : @definition.resolve_remotely!

  # Despite bundler not materializing resolution, we always need to do so to get all the
  # gems details
  @definition.specs
end

Private Instance Methods

build_dependency_type(name) click to toggle source

@param specs [Array] specs that are direct dependencies @param name [String] spec name

@return [Boolean] dependency type

# File lib/diffend/local_context/packages.rb, line 127
def build_dependency_type(name)
  if @direct_dependencies.key?(name)
    DEPENDENCIES_TYPES[:direct]
  else
    DEPENDENCIES_TYPES[:dependency]
  end
end
build_main() click to toggle source

Build default specification

@return [Hash]

# File lib/diffend/local_context/packages.rb, line 100
def build_main
  {
    'dependencies' => {},
    'plugins' => {},
    'sources' => build_sources,
    'platforms' => @definition.platforms.map(&:to_s)
  }
end
build_source_type(remotes) click to toggle source

Build gem source type

@param remotes [Array<::Bundler::URI>]

@return [Integer] internal source type

# File lib/diffend/local_context/packages.rb, line 261
def build_source_type(remotes)
  remotes.count > 1 ? SOURCES_TYPES[:multiple_primary] : SOURCES_TYPES[:valid]
end
build_sources() click to toggle source

Build sources used in the Gemfile

@return [Array<Hash>]

# File lib/diffend/local_context/packages.rb, line 241
def build_sources
  sources = @definition.send(:sources).rubygems_sources
  hash = {}

  sources.each do |source|
    type = build_source_type(source.remotes)

    source.remotes.each do |src|
      hash[source_name(src)] = type
    end
  end

  hash.map { |name, type| { 'name' => name, 'type' => type } }
end
build_spec_gem_source_type(source) click to toggle source

Build gem source type

@param source [::Bundler::Source] gem source type

@return [Integer] internal gem source type

# File lib/diffend/local_context/packages.rb, line 164
def build_spec_gem_source_type(source)
  case source
  when ::Bundler::Source::Metadata
    GEM_SOURCES_TYPES[:local]
  when ::Bundler::Source::Rubygems, ::Bundler::Source::Rubygems::Remote
    GEM_SOURCES_TYPES[:gemfile_source]
  when ::Bundler::Source::Git
    GEM_SOURCES_TYPES[:gemfile_git]
  when ::Bundler::Source::Path
    GEM_SOURCES_TYPES[:gemfile_path]
  else
    raise ArgumentError, "unknown source #{source.class}"
  end
end
build_spec_platform(spec, locked_spec) click to toggle source

Build gem platform

@param spec [::Bundler::StubSpecification, ::Bundler::LazySpecification, Gem::Specification] @param locked_spec [::Bundler::LazySpecification, Gem::Specification, NilClass]

@return [String]

# File lib/diffend/local_context/packages.rb, line 141
def build_spec_platform(spec, locked_spec)
  parse_platform(
    spec.platform || locked_spec&.platform || spec.send(:generic_local_platform)
  )
end
build_spec_source(spec) click to toggle source

Build gem source

@param spec [::Bundler::StubSpecification, ::Bundler::LazySpecification, Gem::Specification]

@return [Hash]

# File lib/diffend/local_context/packages.rb, line 184
def build_spec_source(spec)
  source = source_for_spec(spec)

  {
    'type' => build_spec_gem_source_type(source),
    'value' => source_name_from_source(source)
  }
end
build_versions(spec, locked_spec = nil) click to toggle source

Build gem versions

@param spec [::Bundler::StubSpecification, ::Bundler::LazySpecification, Gem::Specification] @param locked_spec [::Bundler::LazySpecification, Gem::Specification, NilClass]

@return [Array<String>]

# File lib/diffend/local_context/packages.rb, line 115
def build_versions(spec, locked_spec = nil)
  if locked_spec && locked_spec.version.to_s != spec.version.to_s
    [locked_spec.version.to_s, spec.version.to_s]
  else
    [spec.version.to_s]
  end
end
me?(source) click to toggle source

Checks if it's a self source, this happens for repositories that are a gem

@param source [::Bundler::Source] gem source type

@return [Boolean] true if it's a self source, false otherwise

# File lib/diffend/local_context/packages.rb, line 281
def me?(source)
  return false unless ME_SOURCES.include?(source.class)

  source.path.to_s == ME_PATH
end
parse_platform(platform) click to toggle source

Parse gem platform

@param platform [String, Gem::Platform]

@return [String]

# File lib/diffend/local_context/packages.rb, line 152
def parse_platform(platform)
  case platform
  when String then platform
  when Gem::Platform then platform.to_s
  end
end
skip?(source) click to toggle source

Checks if we should skip a source

@param source [::Bundler::Source] gem source type

@return [Boolean] true if we should skip this source, false otherwise

# File lib/diffend/local_context/packages.rb, line 270
def skip?(source)
  return true if me?(source)

  false
end
source_for_spec(spec) click to toggle source

Figure out source for gem

@param spec [::Bundler::StubSpecification, ::Bundler::LazySpecification, Gem::Specification]

@return [::Bundler::Source] gem source type

# File lib/diffend/local_context/packages.rb, line 198
def source_for_spec(spec)
  return spec.remote if spec.remote

  case spec.source
  when ::Bundler::Source::Rubygems
    ::Bundler::Source::Rubygems::Remote.new(spec.source.remotes.last)
  when ::Bundler::Source::Metadata, ::Bundler::Source::Git, ::Bundler::Source::Path
    spec.source
  else
    raise ArgumentError, "unknown source #{spec.source.class}"
  end
end
source_name(uri) click to toggle source

@param uri [::Bundler::URI]

@return [String]

# File lib/diffend/local_context/packages.rb, line 234
def source_name(uri)
  uri.to_s[0...-1]
end
source_name_from_source(source) click to toggle source

Build gem source name

@param source [::Bundler::Source] gem source type

@return [String]

# File lib/diffend/local_context/packages.rb, line 216
def source_name_from_source(source)
  case source
  when ::Bundler::Source::Metadata
    ''
  when ::Bundler::Source::Rubygems::Remote
    source_name(source.anonymized_uri)
  when ::Bundler::Source::Git
    source.instance_variable_get(:@safe_uri)
  when ::Bundler::Source::Path
    source.path
  else
    raise ArgumentError, "unknown source #{source.class}"
  end
end