Class: Sorbet::Private::FetchRBIs

Inherits:
Object
  • Object
show all
Includes:
StepInterface
Defined in:
lib/fetch-rbis.rb

Constant Summary collapse

SORBET_DIR =
'sorbet'
SORBET_CONFIG_FILE =
"#{SORBET_DIR}/config"
SORBET_RBI_LIST =
"#{SORBET_DIR}/rbi_list"
SORBET_RBI_SORBET_TYPED =
"#{SORBET_DIR}/rbi/sorbet-typed/"
XDG_CACHE_HOME =
ENV['XDG_CACHE_HOME'] || "#{ENV['HOME']}/.cache"
RBI_CACHE_DIR =
"#{XDG_CACHE_HOME}/sorbet/sorbet-typed"
SORBET_TYPED_REPO =
ENV['SRB_SORBET_TYPED_REPO'] || 'https://github.com/sorbet/sorbet-typed.git'
SORBET_TYPED_REVISION =
ENV['SRB_SORBET_TYPED_REVISION'] || 'origin/master'
HEADER =
Sorbet::Private::Serialize.header(false, 'sorbet-typed')

Class Method Summary collapse

Class Method Details

.fetch_sorbet_typedObject



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/fetch-rbis.rb', line 31

def self.fetch_sorbet_typed
  if File.directory?(RBI_CACHE_DIR)
    cached_remote = IO.popen(["git", "-C", RBI_CACHE_DIR, "config", "--get", "remote.origin.url"]) {|pipe| pipe.read}.strip

    # Compare the <owner>/<repo>.git to be agnostic of https vs ssh urls
    cached_remote_repo = cached_remote.split(%r{github.com[:/]}).last
    requested_remote_repo = SORBET_TYPED_REPO.split(%r{github.com[:/]}).last

    if cached_remote_repo != requested_remote_repo
      raise "Cached remote #{cached_remote_repo} does not match requested remote #{requested_remote_repo}. Delete #{RBI_CACHE_DIR} and try again."
    end
  else
    IO.popen(["git", "clone", SORBET_TYPED_REPO, RBI_CACHE_DIR]) {|pipe| pipe.read}
    raise "Failed to git pull" if $?.exitstatus != 0
  end

  FileUtils.cd(RBI_CACHE_DIR) do
    IO.popen(%w{git fetch --all}) {|pipe| pipe.read}
    raise "Failed to git fetch" if $?.exitstatus != 0
    IO.popen(%w{git checkout -q} + [SORBET_TYPED_REVISION]) {|pipe| pipe.read}
    raise "Failed to git checkout" if $?.exitstatus != 0
  end
end

.mainObject



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/fetch-rbis.rb', line 114

def self.main
  fetch_sorbet_typed

  gemspecs = Bundler.load.specs.sort_by(&:name)

  vendor_paths = T.let([], T::Array[String])
  vendor_paths += paths_for_ruby_version(Gem::Version.create(RUBY_VERSION))
  gemspecs.each do |gemspec|
    vendor_paths += paths_for_gem_version(gemspec)
  end

  # Remove the sorbet-typed directory before repopulating it.
  FileUtils.rm_r(SORBET_RBI_SORBET_TYPED) if Dir.exist?(SORBET_RBI_SORBET_TYPED)
  if vendor_paths.length > 0
    vendor_rbis_within_paths(vendor_paths)
  end
end

.matching_version_directories(root, version) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/fetch-rbis.rb', line 63

def self.matching_version_directories(root, version)
  paths = Dir.glob("#{root}/*/").select do |dir|
    basename = File.basename(dir.chomp('/'))
    requirements = basename.split(/[,&-]/) # split using ',', '-', or '&'
    requirements.all? do |requirement|
      Gem::Requirement::PATTERN =~ requirement &&
        Gem::Requirement.create(requirement).satisfied_by?(version)
    end
  end
  paths = paths.map {|dir| dir.chomp('/')}
  all_dir = "#{root}/all"
  paths << all_dir if Dir.exist?(all_dir)
  paths
end

.output_fileObject



132
133
134
# File 'lib/fetch-rbis.rb', line 132

def self.output_file
  SORBET_RBI_SORBET_TYPED
end

.paths_for_gem_version(gemspec) ⇒ Object



87
88
89
90
# File 'lib/fetch-rbis.rb', line 87

def self.paths_for_gem_version(gemspec)
  local_dir = "#{RBI_CACHE_DIR}/lib/#{gemspec.name}"
  matching_version_directories(local_dir, gemspec.version)
end

.paths_for_ruby_version(ruby_version) ⇒ Object



80
81
82
83
# File 'lib/fetch-rbis.rb', line 80

def self.paths_for_ruby_version(ruby_version)
  ruby_dir = "#{RBI_CACHE_DIR}/lib/ruby"
  matching_version_directories(ruby_dir, ruby_version)
end

.vendor_rbis_within_paths(vendor_paths) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/fetch-rbis.rb', line 94

def self.vendor_rbis_within_paths(vendor_paths)
  vendor_paths.each do |vendor_path|
    relative_vendor_path = vendor_path.sub(RBI_CACHE_DIR, '')

    dest = "#{SORBET_RBI_SORBET_TYPED}/#{relative_vendor_path}"
    FileUtils.mkdir_p(dest)

    Dir.glob("#{vendor_path}/*.rbi").each do |rbi|
      extra_header = "#
# If you would like to make changes to this file, great! Please upstream any changes you make here:
#
#   https://github.com/sorbet/sorbet-typed/edit/master#{relative_vendor_path}/#{File.basename(rbi)}
#
"
      File.write("#{dest}/#{File.basename(rbi)}", HEADER + extra_header + File.read(rbi))
    end
  end
end