Skip to content

Commit

Permalink
Rearrange requires
Browse files Browse the repository at this point in the history
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
```
  • Loading branch information
MikeMcQuaid committed Jul 14, 2024
1 parent 0f9ca1d commit c5dbd3c
Show file tree
Hide file tree
Showing 39 changed files with 133 additions and 84 deletions.
2 changes: 2 additions & 0 deletions Library/Homebrew/PATH.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# typed: true
# frozen_string_literal: true

require "forwardable"

# Representation of a `*PATH` environment variable.
class PATH
include Enumerable
Expand Down
8 changes: 7 additions & 1 deletion Library/Homebrew/abstract_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ class << self
attr_reader :args_class

sig { returns(String) }
def command_name = Utils.underscore(T.must(name).split("::").fetch(-1)).tr("_", "-").delete_suffix("-cmd")
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))) }
Expand Down
1 change: 0 additions & 1 deletion Library/Homebrew/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
Warnings.ignore :default_gems do
require "base64" # TODO: Add this to the Gemfile or remove it before moving to Ruby 3.4.
end
require "extend/cachable"

module Homebrew
# Helper functions for using Homebrew's formulae.brew.sh API.
Expand Down
12 changes: 10 additions & 2 deletions Library/Homebrew/brew.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
help_flag = true
help_cmd_index = i
elsif !cmd && help_flag_list.exclude?(arg)
require "commands"
cmd = ARGV.delete_at(i)
cmd = Commands::HOMEBREW_INTERNAL_COMMAND_ALIASES.fetch(cmd, cmd)
end
Expand All @@ -59,13 +60,13 @@

ENV["PATH"] = path.to_s

require "abstract_command"
require "commands"
require "settings"

internal_cmd = Commands.valid_internal_cmd?(cmd) || Commands.valid_internal_dev_cmd?(cmd) if cmd

unless internal_cmd
require "tap"

# Add contributed commands to PATH before checking.
homebrew_path.append(Tap.cmd_directories)

Expand All @@ -88,6 +89,8 @@
cmd_class = Homebrew::AbstractCommand.command(cmd)
if cmd_class
command_instance = cmd_class.new

require "utils/analytics"
Utils::Analytics.report_command_run(command_instance)
command_instance.run
else
Expand All @@ -102,6 +105,8 @@
end
exec "brew-#{cmd}", *ARGV
else
require "tap"

possible_tap = OFFICIAL_CMD_TAPS.find { |_, cmds| cmds.include?(cmd) }
possible_tap = Tap.fetch(possible_tap.first) if possible_tap

Expand Down Expand Up @@ -142,6 +147,7 @@
Homebrew::Help.help cmd, remaining_args: args&.remaining, usage_error: e.message
rescue SystemExit => e
onoe "Kernel.exit" if args&.debug? && !e.success?
require "utils/backtrace"
$stderr.puts Utils::Backtrace.clean(e) if args&.debug? || ARGV.include?("--debug")
raise
rescue Interrupt
Expand Down Expand Up @@ -179,13 +185,15 @@
raise if e.message.empty?

onoe e
require "utils/backtrace"
$stderr.puts Utils::Backtrace.clean(e) if args&.debug? || ARGV.include?("--debug")

exit 1
rescue Exception => e # rubocop:disable Lint/RescueException
onoe e

method_deprecated_error = e.is_a?(MethodDeprecatedError)
require "utils/backtrace"

Check warning on line 196 in Library/Homebrew/brew.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/brew.rb#L196

Added line #L196 was not covered by tests
$stderr.puts Utils::Backtrace.clean(e) if args&.debug? || ARGV.include?("--debug") || !method_deprecated_error

if OS.unsupported_configuration?
Expand Down
1 change: 1 addition & 0 deletions Library/Homebrew/build.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
require "fcntl"
require "socket"
require "cmd/install"
require "json/add/exception"

# A formula build.
class Build
Expand Down
1 change: 1 addition & 0 deletions Library/Homebrew/cask/audit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require "livecheck/livecheck"
require "source_location"
require "system_command"
require "utils/backtrace"
require "utils/curl"
require "utils/git"
require "utils/shared_audits"
Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/cask/info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ def self.get_info(cask)

def self.info(cask)
puts get_info(cask)

require "utils/analytics"
::Utils::Analytics.cask_output(cask, args: Homebrew::CLI::Args.new)
end

Expand Down
7 changes: 0 additions & 7 deletions Library/Homebrew/cli/named_args.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
# frozen_string_literal: true

require "delegate"
require "api"
require "cli/args"

module Homebrew
Expand All @@ -29,12 +28,6 @@ def initialize(
cask_options: false,
without_api: false
)
require "cask/cask"
require "cask/cask_loader"
require "formulary"
require "keg"
require "missing_formula"

@args = args
@override_spec = override_spec
@force_bottle = force_bottle
Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/cli/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
require "env_config"
require "cask/config"
require "cli/args"
require "commands"
require "optparse"
require "utils/tty"
require "utils/formatter"

module Homebrew
module CLI
Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/cmd/tap-info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class TapInfo < AbstractCommand

sig { override.void }
def run
require "tap"

taps = if args.installed?
Tap
else
Expand Down
16 changes: 14 additions & 2 deletions Library/Homebrew/commands.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# typed: true
# frozen_string_literal: true

require "completions"

# Helper functions for commands.
module Commands
HOMEBREW_CMD_PATH = (HOMEBREW_LIBRARY_PATH/"cmd").freeze
Expand Down Expand Up @@ -72,16 +70,22 @@ def self.internal_dev_cmd_path(cmd)

# Ruby commands which can be `require`d without being run.
def self.external_ruby_v2_cmd_path(cmd)
require "tap"

path = which("#{cmd}.rb", Tap.cmd_directories)
path if require?(path)
end

# Ruby commands which are run by being `require`d.
def self.external_ruby_cmd_path(cmd)
require "tap"

which("brew-#{cmd}.rb", PATH.new(ENV.fetch("PATH")).append(Tap.cmd_directories))
end

def self.external_cmd_path(cmd)
require "tap"

which("brew-#{cmd}", PATH.new(ENV.fetch("PATH")).append(Tap.cmd_directories))
end

Expand Down Expand Up @@ -112,6 +116,8 @@ def self.internal_developer_commands_paths
end

def self.official_external_commands_paths(quiet:)
require "tap"

Check warning on line 119 in Library/Homebrew/commands.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/commands.rb#L119

Added line #L119 was not covered by tests

OFFICIAL_CMD_TAPS.flat_map do |tap_name, cmds|
tap = Tap.fetch(tap_name)
tap.install(quiet:) unless tap.installed?
Expand All @@ -137,6 +143,8 @@ def self.find_internal_commands(path)
end

def self.external_commands
require "tap"

Tap.cmd_directories.flat_map do |path|
find_commands(path).select(&:executable?)
.map { basename_without_extension(_1) }
Expand All @@ -156,6 +164,8 @@ def self.find_commands(path)
end

def self.rebuild_internal_commands_completion_list
require "completions"

Check warning on line 167 in Library/Homebrew/commands.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/commands.rb#L167

Added line #L167 was not covered by tests

cmds = internal_commands + internal_developer_commands + internal_commands_aliases
cmds.reject! { |cmd| Homebrew::Completions::COMPLETIONS_EXCLUSION_LIST.include? cmd }

Expand All @@ -164,6 +174,8 @@ def self.rebuild_internal_commands_completion_list
end

def self.rebuild_commands_completion_list
require "completions"

# Ensure that the cache exists so we can build the commands list
HOMEBREW_CACHE.mkpath

Expand Down
2 changes: 2 additions & 0 deletions Library/Homebrew/dependency_collector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def gcc_dep_if_needed(related_formula_names); end
def glibc_dep_if_needed(related_formula_names); end

def git_dep_if_needed(tags)
require "utils/git"
return if Utils::Git.available?

Dependency.new("git", [*tags, :implicit])
Expand All @@ -97,6 +98,7 @@ def curl_dep_if_needed(tags)
end

def subversion_dep_if_needed(tags)
require "utils/svn"

Check warning on line 101 in Library/Homebrew/dependency_collector.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/dependency_collector.rb#L101

Added line #L101 was not covered by tests
return if Utils::Svn.available?

Dependency.new("subversion", [*tags, :implicit])
Expand Down
3 changes: 3 additions & 0 deletions Library/Homebrew/dev-cmd/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def run

require "formula_assertions"
require "formula_free_port"
require "utils/fork"

args.named.to_resolved_formulae.each do |f|
# Cannot test uninstalled formulae
Expand Down Expand Up @@ -100,6 +101,8 @@ def run
end
rescue Exception => e # rubocop:disable Lint/RescueException
retry if retry_test?(f)

require "utils/backtrace"
ofail "#{f.full_name}: failed"
$stderr.puts e, Utils::Backtrace.clean(e)
ensure
Expand Down
4 changes: 4 additions & 0 deletions Library/Homebrew/download_strategy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,8 @@ def fetch(timeout: nil)
# @api public
sig { returns(Time) }
def source_modified_time
require "utils/svn"

Check warning on line 740 in Library/Homebrew/download_strategy.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/download_strategy.rb#L740

Added line #L740 was not covered by tests

time = if Version.new(T.must(Utils::Svn.version)) >= Version.new("1.9")
out, = silent_command("svn", args: ["info", "--show-item", "last-changed-date"], chdir: cached_location)
out
Expand Down Expand Up @@ -789,6 +791,7 @@ def fetch_repo(target, url, revision = nil, ignore_externals: false, timeout: ni

args << "--ignore-externals" if ignore_externals

require "utils/svn"
args.concat Utils::Svn.invalid_cert_flags if meta[:trust_cert] == true

if target.directory?
Expand Down Expand Up @@ -921,6 +924,7 @@ def submodules?
def partial_clone_sparse_checkout?
return false if @only_path.blank?

require "utils/git"

Check warning on line 927 in Library/Homebrew/download_strategy.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/download_strategy.rb#L927

Added line #L927 was not covered by tests
Utils::Git.supports_partial_clone_sparse_checkout?
end

Expand Down
5 changes: 2 additions & 3 deletions Library/Homebrew/exceptions.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# typed: true
# frozen_string_literal: true

require "shellwords"
require "utils"

# Raised when a command is used wrong.
#
# @api internal
Expand Down Expand Up @@ -554,6 +551,8 @@ def dump(verbose: false)
# installed in a situation where a bottle is required.
class UnbottledError < RuntimeError
def initialize(formulae)
require "utils"

msg = +<<~EOS
The following #{Utils.pluralize("formula", formulae.count, plural: "e")} cannot be installed from #{Utils.pluralize("bottle", formulae.count)} and must be
built from source.
Expand Down
6 changes: 6 additions & 0 deletions Library/Homebrew/extend/kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

# Contains shorthand Homebrew utility methods like `ohai`, `opoo`, `odisabled`.
# TODO: move these out of `Kernel`.

module Kernel
def require?(path)
return false if path.nil?
Expand Down Expand Up @@ -74,6 +75,9 @@ def opoo(message)
# @api public
sig { params(message: T.any(String, Exception)).void }
def onoe(message)
require "utils/formatter"
require "utils/github/actions"

Tty.with($stderr) do |stderr|
stderr.puts Formatter.error(message, label: "Error")
GitHub::Actions.puts_annotation_if_env_set(:error, message.to_s)
Expand Down Expand Up @@ -150,6 +154,8 @@ def odeprecated(method, replacement = nil,
backtrace.each do |line|
next unless (match = line.match(HOMEBREW_TAP_PATH_REGEX))

require "tap"

tap = Tap.fetch(match[:user], match[:repo])
tap_message = +"\nPlease report this issue to the #{tap.full_name} tap"
tap_message += " (not Homebrew/brew or Homebrew/homebrew-core)" unless tap.official?
Expand Down
15 changes: 8 additions & 7 deletions Library/Homebrew/extend/pathname.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
# typed: true
# frozen_string_literal: true

require "context"
require "resource"
require "metafiles"
require "extend/file/atomic"
require "system_command"

module DiskUsageExtension
sig { returns(Integer) }
def disk_usage
Expand Down Expand Up @@ -75,6 +69,8 @@ def compute_disk_usage
end
end

require "system_command"

# Homebrew extends Ruby's `Pathname` to make our code more readable.
# @see https://ruby-doc.org/stdlib-2.6.3/libdoc/pathname/rdoc/Pathname.html Ruby's Pathname API
class Pathname
Expand Down Expand Up @@ -186,6 +182,8 @@ def append_lines(content, **open_args)
# @api public
sig { params(content: String).void }
def atomic_write(content)
require "extend/file/atomic"

old_stat = stat if exist?
File.atomic_write(self) do |file|
file.write(content)
Expand Down Expand Up @@ -433,6 +431,8 @@ def write_jar_script(target_jar, script_name, java_opts = "", java_version: nil)
end

def install_metafiles(from = Pathname.pwd)
require "metafiles"

Check warning on line 434 in Library/Homebrew/extend/pathname.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/extend/pathname.rb#L434

Added line #L434 was not covered by tests

Pathname(from).children.each do |p|
next if p.directory?
next if File.empty?(p)
Expand Down Expand Up @@ -514,9 +514,10 @@ def rmtree(noop: nil, verbose: nil, secure: nil)
nil
end
end

require "extend/os/pathname"

require "context"

module ObserverPathnameExtension
class << self
include Context
Expand Down
1 change: 1 addition & 0 deletions Library/Homebrew/formula.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require "lock_file"
require "formula_pin"
require "hardware"
require "utils"
require "utils/bottles"
require "utils/shebang"
require "utils/shell"
Expand Down
Loading

0 comments on commit c5dbd3c

Please sign in to comment.