class RBS::Collection::Sources::Git

Constants

METADATA_FILENAME

Attributes

name[R]
remote[R]
repo_dir[R]
revision[R]

Public Class Methods

new(name:, revision:, remote:, repo_dir:) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 18
def initialize(name:, revision:, remote:, repo_dir:)
  @name = name
  @remote = remote
  @repo_dir = repo_dir || 'gems'
  @revision = revision
  @need_setup = true
end

Public Instance Methods

has?(name, version) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 26
def has?(name, version)
  setup! do
    if version
      (gems_versions[name] || Set[]).include?(version)
    else
      gems_versions.key?(name)
    end
  end
end
install(dest:, name:, version:, stdout:) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 43
def install(dest:, name:, version:, stdout:)
  setup!()

  gem_dir = dest.join(name, version)

  colored_io = CLI::ColoredIO.new(stdout: stdout)

  case
  when gem_dir.symlink?
    colored_io.puts_green("Updating to #{format_config_entry(name, version)} from a local source")
    gem_dir.unlink
    _install(dest: dest, name: name, version: version)
  when gem_dir.directory?
    prev = load_metadata(dir: gem_dir)

    if prev == metadata_content(name: name, version: version)
      colored_io.puts "Using #{format_config_entry(name, version)}"
    else
      colored_io.puts_green("Updating to #{format_config_entry(name, version)} from #{format_config_entry(prev["name"], prev["version"])}")
      FileUtils.remove_entry_secure(gem_dir.to_s)
      _install(dest: dest, name: name, version: version)
    end
  when !gem_dir.exist?
    colored_io.puts_green("Installing #{format_config_entry(name, version)}")
    _install(dest: dest, name: name, version: version)
  else
    raise
  end
end
load_metadata(dir:) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 223
def load_metadata(dir:)
  # @type var content: Hash[String, untyped]
  content = YAML.load_file(dir.join(METADATA_FILENAME).to_s)
  _ = content.slice("name", "version", "source")
end
manifest_of(name, version) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 73
def manifest_of(name, version)
  setup! do
    path = File.join(repo_dir, name, version, 'manifest.yaml')
    content = git('cat-file', '-p', "#{resolved_revision}:#{path}")
    YAML.safe_load(content)
  rescue CommandError
    if has?(name, version)
      nil
    else
      raise
    end
  end
end
metadata_content(name:, version:) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 207
def metadata_content(name:, version:)
  {
    "name" => name,
    "version" => version,
    "source" => to_lockfile
  }
end
resolved_revision() click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 172
def resolved_revision
  @resolved_revision ||=
    begin
      if commit_hash?
        revision
      else
        setup! { git('rev-parse', "refs/remotes/origin/#{revision}").chomp }
      end
    end
end
to_lockfile() click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 113
def to_lockfile
  {
    'type' => 'git',
    'name' => name,
    'revision' => resolved_revision,
    'remote' => remote,
    'repo_dir' => repo_dir,
  }
end
versions(name) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 36
def versions(name)
  setup! do
    versions = gems_versions[name] or raise "Git source `#{name}` doesn't have `#{name}`"
    versions.sort
  end
end
write_metadata(dir:, name:, version:) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 215
def write_metadata(dir:, name:, version:)
  dir.join(METADATA_FILENAME).write(
    YAML.dump(
      metadata_content(name: name, version: version)
    )
  )
end

Private Instance Methods

_install(dest:, name:, version:) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 87
        def _install(dest:, name:, version:)
  # Should checkout that revision to support symlinks
  git("reset", "--hard", resolved_revision)

  dir = dest.join(name, version)
  dir.mkpath
  src = gem_repo_dir.join(name, version)

  cp_r(src, dir)
  write_metadata(dir: dir, name: name, version: version)
end
commit_hash?() click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 183
        def commit_hash?
  revision.match?(/\A[a-f0-9]{40}\z/)
end
cp_r(src, dest) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 99
        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(name, version) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 123
        def format_config_entry(name, version)
  rev = resolved_revision[0..10]
  desc = "#{name}@#{rev}"

  "#{name}:#{version} (#{desc})"
end
gem_repo_dir() click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 168
        def gem_repo_dir
  git_dir.join @repo_dir
end
gems_versions() click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 229
        def gems_versions
  @gems_versions ||= begin
    repo_path = Pathname(repo_dir)

    paths = git('ls-tree', '--full-tree', '-dr', '--name-only', '-z', resolved_revision, File.join(repo_dir, "")).split("\0").map {|line| Pathname(line) }

    # @type var versions: Hash[String, Set[String]]
    versions = {}

    paths.each do |full_path|
      path = full_path.relative_path_from(repo_path)

      gem_name, version = path.descend.take(2)

      if gem_name
        versions[gem_name.to_s] ||= Set[]

        if version && !version.basename.to_s.start_with?('_')
          versions[gem_name.to_s] << version.basename.to_s
        end
      end
    end

    versions
  end
end
git(*cmd, **opt) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 187
        def git(*cmd, **opt)
  sh! 'git', *cmd, **opt
end
git?(*cmd, **opt) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 191
        def git?(*cmd, **opt)
  git(*cmd, **opt)
rescue CommandError
  nil
end
git_dir() click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 158
        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
need_to_fetch?(revision) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 152
        def need_to_fetch?(revision)
  return true unless commit_hash?

  !git?('cat-file', '-e', revision)
end
setup!() { || ... } click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 130
        def setup!
  if @need_setup
    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

    @need_setup = false
  end

  yield if block_given?
end
sh!(*cmd, **opt) click to toggle source
# File rbs-3.6.1/lib/rbs/collection/sources/git.rb, line 197
        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