lib/tapioca/cli.rb in tapioca-0.5.6 vs lib/tapioca/cli.rb in tapioca-0.6.0
- old
+ new
@@ -1,168 +1,292 @@
# typed: true
# frozen_string_literal: true
-require "thor"
-
module Tapioca
class Cli < Thor
- class_option :outdir,
- aliases: ["--out", "-o"],
- banner: "directory",
- desc: "The output directory for generated RBI files"
- class_option :generate_command,
- aliases: ["--cmd", "-c"],
- banner: "command",
- desc: "The command to run to regenerate RBI files"
- class_option :file_header,
- type: :boolean,
- default: true,
- desc: "Add a \"This file is generated\" header on top of each generated RBI file"
+ include CliHelper
+ include ConfigHelper
+
+ FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
+
+ class_option :config,
+ aliases: ["-c"],
+ banner: "<config file path>",
+ type: :string,
+ desc: "Path to the Tapioca configuration file",
+ default: TAPIOCA_CONFIG_FILE
class_option :verbose,
aliases: ["-V"],
type: :boolean,
- default: false,
- desc: "Verbose output for debugging purposes"
+ desc: "Verbose output for debugging purposes",
+ default: false
- map T.unsafe(["--version", "-v"] => :__print_version)
-
desc "init", "initializes folder structure"
def init
generator = Generators::Init.new(
- sorbet_config: Config::SORBET_CONFIG,
- default_postrequire: Config::DEFAULT_POSTREQUIRE,
- default_command: Config::DEFAULT_COMMAND
+ sorbet_config: SORBET_CONFIG_FILE,
+ tapioca_config: TAPIOCA_CONFIG_FILE,
+ default_postrequire: DEFAULT_POSTREQUIRE_FILE,
+ default_command: DEFAULT_COMMAND
)
generator.generate
end
desc "require", "generate the list of files to be required by tapioca"
+ option :postrequire, type: :string, default: DEFAULT_POSTREQUIRE_FILE
def require
generator = Generators::Require.new(
- requires_path: ConfigBuilder.from_options(:require, options).postrequire,
- sorbet_config_path: Config::SORBET_CONFIG,
- default_command: Config::DEFAULT_COMMAND
+ requires_path: options[:postrequire],
+ sorbet_config_path: SORBET_CONFIG_FILE,
+ default_command: DEFAULT_COMMAND
)
Tapioca.silence_warnings do
generator.generate
end
end
desc "todo", "generate the list of unresolved constants"
+ option :todo_file,
+ type: :string,
+ default: DEFAULT_TODO_FILE
+ option :file_header,
+ type: :boolean,
+ desc: FILE_HEADER_OPTION_DESC,
+ default: true
def todo
- current_command = T.must(current_command_chain.first)
- config = ConfigBuilder.from_options(current_command, options)
generator = Generators::Todo.new(
- todos_path: config.todos_path,
- file_header: config.file_header,
- default_command: Config::DEFAULT_COMMAND
+ todo_file: options[:todo_file],
+ file_header: options[:file_header],
+ default_command: DEFAULT_COMMAND
)
Tapioca.silence_warnings do
generator.generate
end
end
desc "dsl [constant...]", "generate RBIs for dynamic methods"
- option :generators,
+ option :outdir,
+ aliases: ["--out", "-o"],
+ banner: "directory",
+ desc: "The output directory for generated DSL RBI files",
+ default: DEFAULT_DSL_DIR
+ option :file_header,
+ type: :boolean,
+ desc: FILE_HEADER_OPTION_DESC,
+ default: true
+ option :only,
type: :array,
- aliases: ["--gen", "-g"],
banner: "generator [generator ...]",
- desc: "Only run supplied DSL generators"
- option :exclude_generators,
+ desc: "Only run supplied DSL generator(s)",
+ default: []
+ option :exclude,
type: :array,
banner: "generator [generator ...]",
- desc: "Exclude supplied DSL generators"
+ desc: "Exclude supplied DSL generator(s)",
+ default: []
option :verify,
type: :boolean,
default: false,
desc: "Verifies RBIs are up-to-date"
option :quiet,
aliases: ["-q"],
type: :boolean,
- desc: "Supresses file creation output"
+ desc: "Supresses file creation output",
+ default: false
+ option :workers,
+ aliases: ["-w"],
+ type: :numeric,
+ desc: "EXPERIMENTAL: Number of parallel workers to use when generating RBIs",
+ default: 1
def dsl(*constants)
- current_command = T.must(current_command_chain.first)
- config = ConfigBuilder.from_options(current_command, options)
generator = Generators::Dsl.new(
requested_constants: constants,
- outpath: config.outpath,
- generators: config.generators,
- exclude_generators: config.exclude_generators,
- file_header: config.file_header,
- compiler_path: Tapioca::Compilers::Dsl::COMPILERS_PATH,
- tapioca_path: Config::TAPIOCA_PATH,
- default_command: Config::DEFAULT_COMMAND,
+ outpath: Pathname.new(options[:outdir]),
+ only: options[:only],
+ exclude: options[:exclude],
+ file_header: options[:file_header],
+ compiler_path: Tapioca::Compilers::Dsl::DSL_COMPILERS_DIR,
+ tapioca_path: TAPIOCA_DIR,
+ default_command: DEFAULT_COMMAND,
should_verify: options[:verify],
quiet: options[:quiet],
- verbose: options[:verbose]
+ verbose: options[:verbose],
+ number_of_workers: options[:workers]
)
+
+ if options[:workers] != 1
+ say(
+ "Using more than one worker is experimental and might produce results that are not deterministic",
+ :red
+ )
+ end
+
Tapioca.silence_warnings do
generator.generate
end
end
desc "gem [gem...]", "generate RBIs from gems"
+ option :outdir,
+ aliases: ["--out", "-o"],
+ banner: "directory",
+ desc: "The output directory for generated gem RBI files",
+ default: DEFAULT_GEM_DIR
+ option :file_header,
+ type: :boolean,
+ desc: FILE_HEADER_OPTION_DESC,
+ default: true
option :all,
type: :boolean,
- default: false,
- desc: "Regenerate RBI files for all gems"
+ desc: "Regenerate RBI files for all gems",
+ default: false
option :prerequire,
aliases: ["--pre", "-b"],
banner: "file",
- desc: "A file to be required before Bundler.require is called"
+ desc: "A file to be required before Bundler.require is called",
+ default: nil
option :postrequire,
aliases: ["--post", "-a"],
banner: "file",
- desc: "A file to be required after Bundler.require is called"
+ desc: "A file to be required after Bundler.require is called",
+ default: DEFAULT_POSTREQUIRE_FILE
option :exclude,
aliases: ["-x"],
type: :array,
banner: "gem [gem ...]",
- desc: "Excludes the given gem(s) from RBI generation"
+ desc: "Exclude the given gem(s) from RBI generation",
+ default: []
option :typed_overrides,
aliases: ["--typed", "-t"],
type: :hash,
banner: "gem:level [gem:level ...]",
- desc: "Overrides for typed sigils for generated gem RBIs"
+ desc: "Override for typed sigils for generated gem RBIs",
+ default: DEFAULT_OVERRIDES
option :verify,
type: :boolean,
- default: false,
- desc: "Verifies RBIs are up-to-date"
+ desc: "Verify RBIs are up-to-date",
+ default: false
option :doc,
type: :boolean,
- desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow"
+ desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow",
+ default: false
+ option :exported_gem_rbis,
+ type: :boolean,
+ desc: "Include RBIs found in the `rbi/` directory of the gem",
+ default: true
+ option :workers,
+ aliases: ["-w"],
+ type: :numeric,
+ desc: "EXPERIMENTAL: Number of parallel workers to use when generating RBIs",
+ default: 1
def gem(*gems)
Tapioca.silence_warnings do
all = options[:all]
verify = options[:verify]
- current_command = T.must(current_command_chain.first)
- config = ConfigBuilder.from_options(current_command, options)
+
generator = Generators::Gem.new(
gem_names: all ? [] : gems,
- gem_excludes: config.exclude,
- prerequire: config.prerequire,
- postrequire: config.postrequire,
- typed_overrides: config.typed_overrides,
- default_command: Config::DEFAULT_COMMAND,
- outpath: config.outpath,
- file_header: config.file_header,
- doc: config.doc
+ exclude: options[:exclude],
+ prerequire: options[:prerequire],
+ postrequire: options[:postrequire],
+ typed_overrides: options[:typed_overrides],
+ default_command: DEFAULT_COMMAND,
+ outpath: Pathname.new(options[:outdir]),
+ file_header: options[:file_header],
+ doc: options[:doc],
+ include_exported_rbis: options[:exported_gem_rbis],
+ number_of_workers: options[:workers]
)
raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify
unless gems.empty?
raise MalformattedArgumentError, "Option '--all' must be provided without any other arguments" if all
raise MalformattedArgumentError, "Option '--verify' must be provided without any other arguments" if verify
end
+ if options[:workers] != 1
+ say(
+ "Using more than one worker is experimental and might produce results that are not deterministic",
+ :red
+ )
+ end
+
if gems.empty? && !all
generator.sync(should_verify: verify)
else
generator.generate
end
end
end
+
+ desc "clean-shims", "clean duplicated definitions in shim RBIs"
+ 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
+ def clean_shims(*files_to_clean)
+ index = RBI::Index.new
+
+ # Index gem RBIs
+ gem_rbi_dir = options[:gem_rbi_dir]
+ say("Loading gem RBIs from #{gem_rbi_dir}... ")
+ gem_rbis_files = Dir.glob("#{gem_rbi_dir}/**/*.rbi").sort
+ gem_rbis_trees = RBI::Parser.parse_files(gem_rbis_files)
+ index.visit_all(gem_rbis_trees)
+ say(" Done", :green)
+
+ # Index dsl RBIs
+ dsl_rbi_dir = options[:dsl_rbi_dir]
+ say("Loading dsl RBIs from #{dsl_rbi_dir}... ")
+ dsl_rbis_files = Dir.glob("#{dsl_rbi_dir}/**/*.rbi").sort
+ dsl_rbis_trees = RBI::Parser.parse_files(dsl_rbis_files)
+ index.visit_all(dsl_rbis_trees)
+ say(" Done", :green)
+
+ # Clean shim RBIs
+ if files_to_clean.empty?
+ shim_rbi_dir = options[:shim_rbi_dir]
+ print("Cleaning shim RBIs from #{shim_rbi_dir}...")
+ files_to_clean = Dir.glob("#{shim_rbi_dir}/*.rbi")
+ else
+ print("Cleaning shim RBIs...")
+ end
+
+ done_something = T.let(false, T::Boolean)
+ files_to_clean.sort.each do |path|
+ original = RBI::Parser.parse_file(path)
+ cleaned, operations = RBI::Rewriters::RemoveKnownDefinitions.remove(original, index)
+
+ next if operations.empty?
+ done_something = true
+
+ operations.each do |operation|
+ print("\n #{operation}")
+ end
+
+ if cleaned.empty?
+ print("\n Deleted empty file #{path}")
+ FileUtils.rm(path)
+ else
+ File.write(path, cleaned.string)
+ end
+ end
+
+ if done_something
+ say("\nDone", :green)
+ else
+ say(" Done ", :green)
+ say("(nothing to do)", :yellow)
+ end
+ rescue Errno::ENOENT => e
+ say_error("\nCan't read RBI: #{e}")
+ exit(1)
+ rescue RBI::ParseError => e
+ say_error("\nCan't parse RBI: #{e} (#{e.location})")
+ exit(1)
+ end
+
+ map T.unsafe(["--version", "-v"] => :__print_version)
desc "--version, -v", "show version"
def __print_version
puts "Tapioca v#{Tapioca::VERSION}"
end