Skip to content

Commit

Permalink
Merge pull request #879 from Shopify/group-check-rbi-payload
Browse files Browse the repository at this point in the history
Check duplicates between shims and Sorbet's RBI payload
  • Loading branch information
Morriar committed Apr 7, 2022
2 parents 67e27d5 + 91dcde9 commit cdaf17a
Show file tree
Hide file tree
Showing 6 changed files with 453 additions and 327 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -257,6 +257,7 @@ check_shims:
gem_rbi_dir: sorbet/rbi/gems
dsl_rbi_dir: sorbet/rbi/dsl
shim_rbi_dir: sorbet/rbi/shims
payload: true
```
<!-- END_CONFIG_TEMPLATE -->
Expand Down
32 changes: 31 additions & 1 deletion lib/tapioca/cli.rb
Expand Up @@ -5,6 +5,7 @@ module Tapioca
class Cli < Thor
include CliHelper
include ConfigHelper
include SorbetHelper
include ShimsHelper

FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
Expand Down Expand Up @@ -242,6 +243,7 @@ def gem(*gems)
option :gem_rbi_dir, type: :string, desc: "Path to gem RBIs", default: DEFAULT_GEM_DIR
option :dsl_rbi_dir, type: :string, desc: "Path to DSL RBIs", default: DEFAULT_DSL_DIR
option :shim_rbi_dir, type: :string, desc: "Path to shim RBIs", default: DEFAULT_SHIM_DIR
option :payload, type: :boolean, desc: "Check shims against Sorbet's payload", default: true
def check_shims
index = RBI::Index.new

Expand All @@ -251,6 +253,30 @@ def check_shims
exit(0)
end

payload_path = T.let(nil, T.nilable(String))

if options[:payload]
if sorbet_supports?(:print_payload_sources)
Dir.mktmpdir do |dir|
payload_path = dir
result = sorbet("--no-config --print=payload-sources:#{payload_path}")

unless result.status
say_error("Sorbet failed to dump payload")
say_error(result.err)
exit(1)
end

index_payload(index, payload_path)
end
else
say_error("The version of Sorbet used in your Gemfile.lock does not support `--print=payload-sources`")
say_error("Current: v#{SORBET_GEM_SPEC.version}")
say_error("Required: #{FEATURE_REQUIREMENTS[:print_payload_sources]}")
exit(1)
end
end

index_rbis(index, "shim", shim_rbi_dir)
index_rbis(index, "gem", options[:gem_rbi_dir])
index_rbis(index, "dsl", options[:dsl_rbi_dir])
Expand All @@ -260,7 +286,11 @@ def check_shims
duplicates.each do |key, nodes|
say_error("\nDuplicated RBI for #{key}:", :red)
nodes.each do |node|
say_error(" * #{node.loc}", :red)
node_loc = node.loc
next unless node_loc

loc_string = location_to_payload_url(node_loc, path_prefix: payload_path)
say_error(" * #{loc_string}", :red)
end
end
say_error("\nPlease remove the duplicated definitions from the #{shim_rbi_dir} directory.", :red)
Expand Down
43 changes: 35 additions & 8 deletions lib/tapioca/helpers/shims_helper.rb
Expand Up @@ -8,20 +8,25 @@ module ShimsHelper

requires_ancestor { Thor::Shell }

SORBET_PAYLOAD_URL = "https://github.com/sorbet/sorbet/tree/master/rbi"

sig { params(index: RBI::Index, dir: String).void }
def index_payload(index, dir)
return unless Dir.exist?(dir)

say("Loading Sorbet payload... ")
files = Dir.glob("#{dir}/**/*.rbi").sort
parse_and_index_files(index, files)
say(" Done", :green)
end

sig { params(index: RBI::Index, kind: String, dir: String).void }
def index_rbis(index, kind, dir)
return unless Dir.exist?(dir) && !Dir.empty?(dir)

say("Loading #{kind} RBIs from #{dir}... ")
files = Dir.glob("#{dir}/**/*.rbi").sort

trees = files.map do |file|
RBI::Parser.parse_file(file)
rescue RBI::ParseError => e
say_error("\nWarning: #{e} (#{e.location})", :yellow)
end.compact

index.visit_all(trees)
parse_and_index_files(index, files)
say(" Done", :green)
end

Expand All @@ -39,8 +44,30 @@ def duplicated_nodes_from_index(index, shim_rbi_dir)
duplicates
end

sig { params(loc: RBI::Loc, path_prefix: T.nilable(String)).returns(String) }
def location_to_payload_url(loc, path_prefix:)
return loc.to_s unless path_prefix

url = loc.file || ""
return loc.to_s unless url.start_with?(path_prefix)

url = url.sub(path_prefix, SORBET_PAYLOAD_URL)
url = "#{url}#L#{loc.begin_line}"
url
end

private

sig { params(index: RBI::Index, files: T::Array[String]).void }
def parse_and_index_files(index, files)
trees = files.map do |file|
RBI::Parser.parse_file(file)
rescue RBI::ParseError => e
say_error("\nWarning: #{e} (#{e.location})", :yellow)
end.compact
index.visit_all(trees)
end

sig { params(nodes: T::Array[RBI::Node], shim_rbi_dir: String).returns(T::Boolean) }
def shims_have_duplicates?(nodes, shim_rbi_dir)
return false if nodes.size == 1
Expand Down
4 changes: 2 additions & 2 deletions lib/tapioca/helpers/sorbet_helper.rb
Expand Up @@ -21,8 +21,8 @@ module SorbetHelper
SORBET_EXE_PATH_ENV_VAR = "TAPIOCA_SORBET_EXE"

FEATURE_REQUIREMENTS = T.let({
# First tag that includes https://github.com/sorbet/sorbet/pull/4706
to_ary_nil_support: ::Gem::Requirement.new(">= 0.5.9220"),
to_ary_nil_support: ::Gem::Requirement.new(">= 0.5.9220"), # https://github.com/sorbet/sorbet/pull/4706
print_payload_sources: ::Gem::Requirement.new(">= 0.5.9818"), # https://github.com/sorbet/sorbet/pull/5504
}.freeze, T::Hash[Symbol, ::Gem::Requirement])

sig { params(sorbet_args: String).returns(Spoom::ExecResult) }
Expand Down
6 changes: 0 additions & 6 deletions sorbet/rbi/shims/bundler.rbi

This file was deleted.

0 comments on commit cdaf17a

Please sign in to comment.