lib/tapioca/generator.rb in tapioca-0.4.19 vs lib/tapioca/generator.rb in tapioca-0.4.20
- old
+ new
@@ -118,42 +118,56 @@
sig do
params(
requested_constants: T::Array[String],
should_verify: T::Boolean,
+ quiet: T::Boolean
).void
end
- def build_dsl(requested_constants, should_verify: false)
+ def build_dsl(requested_constants, should_verify: false, quiet: false)
load_application(eager_load: requested_constants.empty?)
load_dsl_generators
if should_verify
say("Checking for out-of-date RBIs...")
else
say("Compiling DSL RBI files...")
end
say("")
- outpath = should_verify ? Dir.mktmpdir : config.outpath
+ outpath = should_verify ? Pathname.new(Dir.mktmpdir) : config.outpath
rbi_files_to_purge = existing_rbi_filenames(requested_constants)
compiler = Compilers::DslCompiler.new(
requested_constants: constantize(requested_constants),
requested_generators: config.generators,
error_handler: ->(error) {
say_error(error, :bold, :red)
}
)
+ constant_lookup = {}
+
compiler.run do |constant, contents|
- filename = compile_dsl_rbi(constant, contents, outpath: Pathname.new(outpath))
- rbi_files_to_purge.delete(filename) if filename
+ constant_name = Module.instance_method(:name).bind(constant).call
+
+ filename = compile_dsl_rbi(
+ constant_name,
+ contents,
+ outpath: outpath,
+ quiet: should_verify || quiet
+ )
+
+ if filename
+ rbi_files_to_purge.delete(filename)
+ constant_lookup[filename.relative_path_from(outpath)] = constant_name
+ end
end
say("")
if should_verify
- perform_dsl_verification(outpath)
+ perform_dsl_verification(outpath, constant_lookup)
else
purge_stale_dsl_rbi_files(rbi_files_to_purge)
say("Done", :green)
@@ -504,63 +518,105 @@
T.unsafe(Pathname).glob((config.outpath / "#{gem.name}@*.rbi").to_s) do |file|
remove(file) unless file.basename.to_s == gem.rbi_file_name
end
end
- sig { params(constant: Module, contents: String, outpath: Pathname).returns(T.nilable(Pathname)) }
- def compile_dsl_rbi(constant, contents, outpath: config.outpath)
+ sig do
+ params(constant_name: String, contents: String, outpath: Pathname, quiet: T::Boolean)
+ .returns(T.nilable(Pathname))
+ end
+ def compile_dsl_rbi(constant_name, contents, outpath: config.outpath, quiet: false)
return if contents.nil?
- constant_name = Module.instance_method(:name).bind(constant).call
rbi_name = constant_name.underscore + ".rbi"
filename = outpath / rbi_name
out = String.new
out << rbi_header(
"#{Config::DEFAULT_COMMAND} dsl #{constant_name}",
- reason: "dynamic methods in `#{constant.name}`"
+ reason: "dynamic methods in `#{constant_name}`"
)
out << contents
FileUtils.mkdir_p(File.dirname(filename))
File.write(filename, out)
- say("Wrote: ", [:green])
- say(filename)
+ unless quiet
+ say("Wrote: ", [:green])
+ say(filename)
+ end
+
filename
end
- sig { params(tmp_dir: Pathname).returns(T.nilable(String)) }
+ sig { params(tmp_dir: Pathname).returns(T::Hash[String, Symbol]) }
def verify_dsl_rbi(tmp_dir:)
- existing_rbis = existing_rbi_filenames([]).sort
- new_rbis = existing_rbi_filenames([], path: tmp_dir).grep_v(/gem|shim/).sort
+ diff = {}
- return "New file(s) introduced." if existing_rbis.length != new_rbis.length
+ existing_rbis = rbi_files_in(config.outpath)
+ new_rbis = rbi_files_in(tmp_dir)
- desynced_files = []
+ added_files = (new_rbis - existing_rbis)
- (0..existing_rbis.length - 1).each do |i|
- desynced_files << new_rbis[i] unless FileUtils.identical?(existing_rbis[i], new_rbis[i])
+ added_files.each do |file|
+ diff[file] = :added
end
- unless desynced_files.empty?
- filenames = desynced_files.map { |f| f.to_s.sub!(tmp_dir.to_s, "sorbet/rbi/dsl") }.join("\n - ")
+ removed_files = (existing_rbis - new_rbis)
- return "File(s) updated:\n - #{filenames}"
+ removed_files.each do |file|
+ diff[file] = :removed
end
- nil
+ common_files = (existing_rbis & new_rbis)
+
+ changed_files = common_files.map do |filename|
+ filename unless FileUtils.identical?(config.outpath / filename, tmp_dir / filename)
+ end.compact
+
+ changed_files.each do |file|
+ diff[file] = :changed
+ end
+
+ diff
end
- sig { params(dir: String).void }
- def perform_dsl_verification(dir)
- if (error = verify_dsl_rbi(tmp_dir: Pathname.new(dir)))
- say("RBI files are out-of-date, please run `#{Config::DEFAULT_COMMAND} dsl` to update.")
- say("Reason: ", [:red])
- say(error)
- exit(1)
- else
+ sig { params(cause: Symbol, files: T::Array[String]).returns(String) }
+ def build_error_for_files(cause, files)
+ filenames = files.map do |file|
+ config.outpath / file
+ end.join("\n - ")
+
+ " File(s) #{cause}:\n - #{filenames}"
+ end
+
+ sig { params(path: Pathname).returns(T::Array[Pathname]) }
+ def rbi_files_in(path)
+ Pathname.glob(path / "**/*.rbi").map do |file|
+ file.relative_path_from(path)
+ end.sort
+ end
+
+ sig { params(dir: Pathname, constant_lookup: T::Hash[String, String]).void }
+ def perform_dsl_verification(dir, constant_lookup)
+ diff = verify_dsl_rbi(tmp_dir: dir)
+
+ if diff.empty?
say("Nothing to do, all RBIs are up-to-date.")
+ else
+ constants = T.unsafe(constant_lookup).values_at(*diff.keys).join(" ")
+
+ say("RBI files are out-of-date, please run:")
+ say(" `#{Config::DEFAULT_COMMAND} dsl #{constants}`")
+
+ say("")
+
+ say("Reason:", [:red])
+ diff.group_by(&:last).sort.each do |cause, diff_for_cause|
+ say(build_error_for_files(cause, diff_for_cause.map(&:first)))
+ end
+
+ exit(1)
end
ensure
FileUtils.remove_entry(dir)
end