123456789_123456789_123456789_123456789_123456789_

Class: RBS::Collection::Sources::Git

Relationships & Source Files
Namespace Children
Exceptions:
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, Base
Inherits: Object
Defined in: lib/rbs/collection/sources/git.rb

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(name:, revision:, remote:, repo_dir:) ⇒ Git

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 18

def initialize(name:, revision:, remote:, repo_dir:)
  @name = name
  @remote = remote
  @repo_dir = repo_dir || 'gems'

  setup!(revision: revision)
end

Instance Attribute Details

#name (readonly)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 16

attr_reader :name, :remote, :repo_dir

#remote (readonly)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 16

attr_reader :name, :remote, :repo_dir

#repo_dir (readonly)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 16

attr_reader :name, :remote, :repo_dir

Instance Method Details

#_install(dest:, config_entry:) (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 65

private def _install(dest:, config_entry:)
  gem_name = config_entry['name']
  version = config_entry['version'] or raise
  dest = dest.join(gem_name, version)
  dest.mkpath
  src = gem_repo_dir.join(gem_name, version)

  cp_r(src, dest)
  dest.join(METADATA_FILENAME).write(YAML.dump(config_entry))
end

#cp_r(src, dest) (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 76

private def cp_r(src, dest)
  Find.find(src) do |file_src|
    file_src = Pathname(file_src)

    # Skip file if it starts with _, such as _test/
    Find.prune if file_src.basename.to_s.start_with?('_')

    file_src_relative = file_src.relative_path_from(src)
    file_dest = dest.join(file_src_relative)
    file_dest.dirname.mkpath
    FileUtils.copy_entry(file_src, file_dest, false, true) unless file_src.directory?
  end
end

#format_config_entry(config_entry) (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 100

private def format_config_entry(config_entry)
  name = config_entry['name']
  v = config_entry['version']

  rev = resolved_revision[0..10]
  desc = "#{name}@#{rev}"

  "#{name}:#{v} (#{desc})"
end

#gem_repo_dir (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 153

private def gem_repo_dir
  git_dir.join @repo_dir
end

#git(*cmd, **opt) (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 165

private def git(*cmd, **opt)
  sh! 'git', *cmd, **opt
end

#git_dir (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 143

private def git_dir
  @git_dir ||= (
    base = Pathname(ENV['XDG_CACHE_HOME'] || File.expand_path("~/.cache"))
    cache_key = remote.start_with?('.') ? "#{remote}\0#{Dir.pwd}" : remote
    dir = base.join('rbs', Digest::SHA256.hexdigest(cache_key))
    dir.mkpath
    dir
  )
end

#has?(config_entry) ⇒ Boolean

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 26

def has?(config_entry)
  gem_name = config_entry['name']
  gem_repo_dir.join(gem_name).directory?
end

#install(dest:, config_entry:, stdout:)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 36

def install(dest:, config_entry:, stdout:)
  gem_name = config_entry['name']
  version = config_entry['version'] or raise
  gem_dir = dest.join(gem_name, version)

  if gem_dir.directory?
    if (prev = YAML.load_file(gem_dir.join(METADATA_FILENAME))) == config_entry
      stdout.puts "Using #{format_config_entry(config_entry)}"
    else
      # @type var prev: RBS::Collection::Config::gem_entry
      stdout.puts "Updating to #{format_config_entry(config_entry)} from #{format_config_entry(prev)}"
      FileUtils.remove_entry_secure(gem_dir.to_s)
      _install(dest: dest, config_entry: config_entry)
    end
  else
    stdout.puts "Installing #{format_config_entry(config_entry)}"
    _install(dest: dest, config_entry: config_entry)
  end
end

#manifest_of(config_entry)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 56

def manifest_of(config_entry)
  gem_name = config_entry['name']
  version = config_entry['version'] or raise
  gem_dir = gem_repo_dir.join(gem_name, version)

  manifest_path = gem_dir.join('manifest.yaml')
  YAML.safe_load(manifest_path.read) if manifest_path.exist?
end

#need_to_fetch?(revision) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 132

private def need_to_fetch?(revision)
  return true unless revision.match?(/\A[a-f0-9]{40}\z/)

  begin
    git('cat-file', '-e', revision)
    false
  rescue CommandError
    true
  end
end

#resolve_revision (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 161

private def resolve_revision
  git('rev-parse', 'HEAD').chomp
end

#resolved_revision (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 157

private def resolved_revision
  @resolved_revision ||= resolve_revision
end

#setup!(revision:) (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 110

private def setup!(revision:)
  git_dir.mkpath
  if git_dir.join('.git').directory?
    if need_to_fetch?(revision)
      git 'fetch', 'origin'
    end
  else
    begin
      # git v2.27.0 or greater
      git 'clone', '--filter=blob:none', remote, git_dir.to_s, chdir: nil
    rescue CommandError
      git 'clone', remote, git_dir.to_s, chdir: nil
    end
  end

  begin
    git 'checkout', "origin/#{revision}" # for branch name as `revision`
  rescue CommandError
    git 'checkout', revision
  end
end

#sh!(*cmd, **opt) (private)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 169

private def sh!(*cmd, **opt)
  RBS.logger.debug "$ #{cmd.join(' ')}"
  opt = { chdir: git_dir }.merge(opt).compact
  (__skip__ = Open3.capture3(*cmd, **opt)).then do |out, err, status|
    raise CommandError, "Unexpected status #{status.exitstatus}\n\n#{err}" unless status.success?

    out
  end
end

#to_lockfile

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 90

def to_lockfile
  {
    'type' => 'git',
    'name' => name,
    'revision' => resolved_revision,
    'remote' => remote,
    'repo_dir' => repo_dir,
  }
end

#versions(config_entry)

[ GitHub ]

  
# File 'lib/rbs/collection/sources/git.rb', line 31

def versions(config_entry)
  gem_name = config_entry['name']
  gem_repo_dir.join(gem_name).glob('*/').map { |path| path.basename.to_s }
end