mirror of
https://github.com/Homebrew/brew.git
synced 2025-07-14 16:09:03 +08:00

This improves the load time of most brew commands. For an example of one of the simplest commands this speeds up: Without Bootsnap: ``` $ hyperfine 'git checkout master; brew help' 'git checkout optimise_requires; brew help' Benchmark 1: git checkout master; brew help Time (mean ± σ): 525.0 ms ± 35.8 ms [User: 229.9 ms, System: 113.1 ms] Range (min … max): 465.3 ms … 576.6 ms 10 runs Benchmark 2: git checkout optimise_requires; brew help Time (mean ± σ): 383.3 ms ± 25.1 ms [User: 133.0 ms, System: 72.1 ms] Range (min … max): 353.0 ms … 443.6 ms 10 runs Summary git checkout optimise_requires; brew help ran 1.37 ± 0.13 times faster than git checkout master; brew help ``` With Bootsnap: ``` $ hyperfine 'git checkout master; brew help' 'git checkout optimise_requires; brew help' Benchmark 1: git checkout master; brew help Time (mean ± σ): 386.0 ms ± 30.9 ms [User: 130.2 ms, System: 93.8 ms] Range (min … max): 359.5 ms … 469.3 ms 10 runs Benchmark 2: git checkout optimise_requires; brew help Time (mean ± σ): 330.2 ms ± 32.4 ms [User: 93.4 ms, System: 73.0 ms] Range (min … max): 302.9 ms … 413.9 ms 10 runs Summary git checkout optimise_requires; brew help ran 1.17 ± 0.15 times faster than git checkout master; brew help ```
66 lines
2.1 KiB
Ruby
66 lines
2.1 KiB
Ruby
# typed: strong
|
|
# frozen_string_literal: true
|
|
|
|
require "cli/parser"
|
|
|
|
module Homebrew
|
|
# Subclass this to implement a `brew` command. This is preferred to declaring a named function in the `Homebrew`
|
|
# module, because:
|
|
#
|
|
# - Each Command lives in an isolated namespace.
|
|
# - Each Command implements a defined interface.
|
|
# - `args` is available as an instance method and thus does not need to be passed as an argument to helper methods.
|
|
# - Subclasses no longer need to reference `CLI::Parser` or parse args explicitly.
|
|
#
|
|
# To subclass, implement a `run` method and provide a `cmd_args` block to document the command and its allowed args.
|
|
# To generate method signatures for command args, run `brew typecheck --update`.
|
|
class AbstractCommand
|
|
extend T::Helpers
|
|
|
|
abstract!
|
|
|
|
class << self
|
|
sig { returns(T.nilable(T.class_of(CLI::Args))) }
|
|
attr_reader :args_class
|
|
|
|
sig { returns(String) }
|
|
def command_name
|
|
require "utils"
|
|
|
|
Utils.underscore(T.must(name).split("::").fetch(-1))
|
|
.tr("_", "-")
|
|
.delete_suffix("-cmd")
|
|
end
|
|
|
|
# @return the AbstractCommand subclass associated with the brew CLI command name.
|
|
sig { params(name: String).returns(T.nilable(T.class_of(AbstractCommand))) }
|
|
def command(name) = subclasses.find { _1.command_name == name }
|
|
|
|
sig { returns(T::Boolean) }
|
|
def dev_cmd? = T.must(name).start_with?("Homebrew::DevCmd")
|
|
|
|
sig { returns(CLI::Parser) }
|
|
def parser = CLI::Parser.new(self, &@parser_block)
|
|
|
|
private
|
|
|
|
sig { params(block: T.proc.bind(CLI::Parser).void).void }
|
|
def cmd_args(&block)
|
|
@parser_block = T.let(block, T.nilable(T.proc.void))
|
|
@args_class = T.let(const_set(:Args, Class.new(CLI::Args)), T.nilable(T.class_of(CLI::Args)))
|
|
end
|
|
end
|
|
|
|
sig { returns(CLI::Args) }
|
|
attr_reader :args
|
|
|
|
sig { params(argv: T::Array[String]).void }
|
|
def initialize(argv = ARGV.freeze)
|
|
@args = T.let(self.class.parser.parse(argv), CLI::Args)
|
|
end
|
|
|
|
sig { abstract.void }
|
|
def run; end
|
|
end
|
|
end
|