Merge pull request #9268 from reitermarkus/type-signatures

Add more type signatures.
This commit is contained in:
Markus Reiter 2020-11-30 15:16:05 +01:00 committed by GitHub
commit fe2c201d00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 433 additions and 142 deletions

View File

@ -213,7 +213,7 @@ begin
args = Homebrew.install_args.parse args = Homebrew.install_args.parse
Context.current = args.context Context.current = args.context
error_pipe = UNIXSocket.open(ENV["HOMEBREW_ERROR_PIPE"], &:recv_io) error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
trap("INT", old_trap) trap("INT", old_trap)

View File

@ -23,7 +23,7 @@ module Cask
def run def run
require "diagnostic" require "diagnostic"
success = true success = T.let(true, T::Boolean)
checks = Homebrew::Diagnostic::Checks.new(verbose: true) checks = Homebrew::Diagnostic::Checks.new(verbose: true)
checks.cask_checks.each do |check| checks.cask_checks.each do |check|

View File

@ -1,7 +1,6 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "cli/named_args"
require "ostruct" require "ostruct"
module Homebrew module Homebrew
@ -16,6 +15,8 @@ module Homebrew
sig { void } sig { void }
def initialize def initialize
require "cli/named_args"
super() super()
@processed_options = [] @processed_options = []
@ -55,6 +56,7 @@ module Homebrew
sig { returns(NamedArgs) } sig { returns(NamedArgs) }
def named def named
require "formula"
self[:named] self[:named]
end end

View File

@ -59,6 +59,164 @@ module Homebrew
sig { returns(T.nilable(T::Boolean)) } sig { returns(T.nilable(T::Boolean)) }
def formula?; end def formula?; end
sig { returns(T.nilable(T::Boolean)) }
def zap?; end
sig { returns(T.nilable(T::Boolean)) }
def ignore_dependencies?; end
sig { returns(T.nilable(T::Boolean)) }
def aliases?; end
sig { returns(T.nilable(T::Boolean)) }
def fix?; end
sig { returns(T.nilable(T::Boolean)) }
def keep_tmp?; end
sig { returns(T.nilable(T::Boolean)) }
def overwrite?; end
sig { returns(T.nilable(T::Boolean)) }
def silent?; end
sig { returns(T.nilable(T::Boolean)) }
def repair?; end
sig { returns(T.nilable(T::Boolean)) }
def prune_prefix?; end
sig { returns(T.nilable(T::Boolean)) }
def upload?; end
sig { returns(T.nilable(T::Boolean)) }
def total?; end
sig { returns(T.nilable(T::Boolean)) }
def dependents?; end
sig { returns(T.nilable(T::Boolean)) }
def installed?; end
sig { returns(T.nilable(T::Boolean)) }
def all?; end
sig { returns(T.nilable(T::Boolean)) }
def full?; end
sig { returns(T.nilable(T::Boolean)) }
def list_pinned?; end
sig { returns(T.nilable(T::Boolean)) }
def display_cop_names?; end
sig { returns(T.nilable(T::Boolean)) }
def syntax?; end
sig { returns(T.nilable(T::Boolean)) }
def ignore_non_pypi_packages?; end
sig { returns(T.nilable(T::Boolean)) }
def test?; end
sig { returns(T.nilable(T::Boolean)) }
def reverse?; end
sig { returns(T.nilable(T::Boolean)) }
def print_only?; end
sig { returns(T.nilable(T::Boolean)) }
def markdown?; end
sig { returns(T.nilable(String)) }
def tag; end
sig { returns(T.nilable(String)) }
def tap; end
sig { returns(T.nilable(String)) }
def macos; end
sig { returns(T.nilable(T::Array[String])) }
def hide; end
sig { returns(T.nilable(String)) }
def version; end
sig { returns(T.nilable(String)) }
def name; end
sig { returns(T.nilable(T::Boolean)) }
def no_publish?; end
sig { returns(T.nilable(T::Boolean)) }
def shallow?; end
sig { returns(T.nilable(T::Boolean)) }
def fail_if_not_changed?; end
sig { returns(T.nilable(String)) }
def limit; end
sig { returns(T.nilable(String)) }
def message; end
sig { returns(T.nilable(String)) }
def issue; end
sig { returns(T.nilable(String)) }
def workflow; end
sig { returns(T.nilable(String)) }
def bintray_org; end
sig { returns(T.nilable(String)) }
def bintray_repo; end
sig { returns(T.nilable(String)) }
def package_name; end
sig { returns(T.nilable(String)) }
def prune; end
sig { returns(T.nilable(T::Array[String])) }
def only_cops; end
sig { returns(T.nilable(T::Array[String])) }
def except_cops; end
sig { returns(T.nilable(T::Array[String])) }
def only; end
sig { returns(T.nilable(T::Array[String])) }
def except; end
sig { returns(T.nilable(T::Array[String])) }
def mirror; end
sig { returns(T.nilable(T::Array[String])) }
def without_labels; end
sig { returns(T.nilable(T::Array[String])) }
def workflows; end
sig { returns(T.nilable(T::Array[String])) }
def ignore_missing_artifacts; end
sig { returns(T.nilable(T::Array[String])) }
def language; end
sig { returns(T.nilable(T::Array[String])) }
def extra_packages; end
sig { returns(T.nilable(T::Array[String])) }
def exclude_packages; end
sig { returns(T.nilable(T::Array[String])) }
def update; end
sig { returns(T.nilable(T::Boolean)) }
def s?; end
end end
end end
end end

View File

@ -3,11 +3,7 @@
require "delegate" require "delegate"
require "cask/cask_loader"
require "cli/args" require "cli/args"
require "formulary"
require "keg"
require "missing_formula"
module Homebrew module Homebrew
module CLI module CLI
@ -18,6 +14,12 @@ module Homebrew
extend T::Sig extend T::Sig
def initialize(*args, parent: Args.new, override_spec: nil, force_bottle: false, flags: []) def initialize(*args, parent: Args.new, override_spec: nil, force_bottle: false, flags: [])
require "cask/cask"
require "cask/cask_loader"
require "formulary"
require "keg"
require "missing_formula"
@args = args @args = args
@override_spec = override_spec @override_spec = override_spec
@force_bottle = force_bottle @force_bottle = force_bottle
@ -99,6 +101,7 @@ module Homebrew
end end
private :resolve_formula private :resolve_formula
sig { returns(T::Array[Formula]) }
def to_resolved_formulae def to_resolved_formulae
@to_resolved_formulae ||= to_formulae_and_casks(only: :formula, method: :resolve) @to_resolved_formulae ||= to_formulae_and_casks(only: :formula, method: :resolve)
.freeze .freeze
@ -157,7 +160,7 @@ module Homebrew
@to_kegs ||= begin @to_kegs ||= begin
to_formulae_and_casks(only: :formula, method: :keg).freeze to_formulae_and_casks(only: :formula, method: :keg).freeze
rescue NoSuchKegError => e rescue NoSuchKegError => e
if (reason = Homebrew::MissingFormula.suggest_command(e.name, "uninstall")) if (reason = MissingFormula.suggest_command(e.name, "uninstall"))
$stderr.puts reason $stderr.puts reason
end end
raise e raise e

View File

@ -264,6 +264,7 @@ module Homebrew
[remaining, non_options] [remaining, non_options]
end end
sig { params(argv: T::Array[String], ignore_invalid_options: T::Boolean).returns(Args) }
def parse(argv = ARGV.freeze, ignore_invalid_options: false) def parse(argv = ARGV.freeze, ignore_invalid_options: false)
raise "Arguments were already parsed!" if @args_parsed raise "Arguments were already parsed!" if @args_parsed

View File

@ -35,6 +35,7 @@ module Homebrew
end end
end end
sig { void }
def __cache def __cache
args = __cache_args.parse args = __cache_args.parse
@ -60,6 +61,7 @@ module Homebrew
end end
end end
sig { params(formula: Formula, args: CLI::Args).void }
def print_formula_cache(formula, args:) def print_formula_cache(formula, args:)
if fetch_bottle?(formula, args: args) if fetch_bottle?(formula, args: args)
puts formula.bottle.cached_download puts formula.bottle.cached_download
@ -68,6 +70,7 @@ module Homebrew
end end
end end
sig { params(cask: Cask::Cask).void }
def print_cask_cache(cask) def print_cask_cache(cask)
puts Cask::Download.new(cask).downloader.cached_location puts Cask::Download.new(cask).downloader.cached_location
end end

View File

@ -30,6 +30,7 @@ module Homebrew
end end
end end
sig { void }
def __env def __env
args = __env_args.parse args = __env_args.parse
@ -51,7 +52,7 @@ module Homebrew
BuildEnvironment.dump ENV BuildEnvironment.dump ENV
else else
BuildEnvironment.keys(ENV).each do |key| BuildEnvironment.keys(ENV).each do |key|
puts Utils::Shell.export_value(key, ENV[key], shell) puts Utils::Shell.export_value(key, ENV.fetch(key), shell)
end end
end end
end end

View File

@ -1,4 +1,4 @@
# typed: true # typed: false
# frozen_string_literal: true # frozen_string_literal: true
require "cleanup" require "cleanup"
@ -37,11 +37,18 @@ module Homebrew
def cleanup def cleanup
args = cleanup_args.parse args = cleanup_args.parse
if args.prune.present? && !Integer(args.prune, exception: false) && args.prune != "all" days = args.prune.presence&.yield_self do |prune|
raise UsageError, "--prune= expects an integer or 'all'." case prune
when /\A\d+\Z/
prune.to_i
when "all"
0
else
raise UsageError, "--prune= expects an integer or 'all'."
end
end end
cleanup = Cleanup.new(*args.named, dry_run: args.dry_run?, scrub: args.s?, days: args.prune&.to_i) cleanup = Cleanup.new(*args.named, dry_run: args.dry_run?, scrub: args.s?, days: days)
if args.prune_prefix? if args.prune_prefix?
cleanup.prune_prefix_symlinks_and_directories cleanup.prune_prefix_symlinks_and_directories
return return

View File

@ -45,6 +45,7 @@ module Homebrew
end end
end end
sig { void }
def tap def tap
args = tap_args.parse args = tap_args.parse

View File

@ -61,13 +61,13 @@ module Homebrew
) )
if args.zap? if args.zap?
Cask::Cmd::Zap.zap_casks( T.unsafe(Cask::Cmd::Zap).zap_casks(
*casks, *casks,
verbose: args.verbose?, verbose: args.verbose?,
force: args.force?, force: args.force?,
) )
else else
Cask::Cmd::Uninstall.uninstall_casks( T.unsafe(Cask::Cmd::Uninstall).uninstall_casks(
*casks, *casks,
binaries: EnvConfig.cask_opts_binaries?, binaries: EnvConfig.cask_opts_binaries?,
verbose: args.verbose?, verbose: args.verbose?,

View File

@ -261,8 +261,8 @@ module Homebrew
formula_and_runtime_deps_names = [f.name] + f.runtime_dependencies.map(&:name) formula_and_runtime_deps_names = [f.name] + f.runtime_dependencies.map(&:name)
keg = Keg.new(f.prefix) keg = Keg.new(f.prefix)
relocatable = false relocatable = T.let(false, T::Boolean)
skip_relocation = false skip_relocation = T.let(false, T::Boolean)
keg.lock do keg.lock do
original_tab = nil original_tab = nil
@ -472,7 +472,7 @@ module Homebrew
if args.write? if args.write?
path = Pathname.new((HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]).to_s) path = Pathname.new((HOMEBREW_REPOSITORY/bottle_hash["formula"]["path"]).to_s)
update_or_add = nil update_or_add = T.let(nil, T.nilable(String))
Utils::Inreplace.inreplace(path) do |s| Utils::Inreplace.inreplace(path) do |s|
if s.inreplace_string.include? "bottle do" if s.inreplace_string.include? "bottle do"

View File

@ -35,14 +35,14 @@ module Homebrew
def dispatch_build_bottle def dispatch_build_bottle
args = dispatch_build_bottle_args.parse args = dispatch_build_bottle_args.parse
odie "Must specify --macos option" unless args.macos macos = args.macos&.yield_self do |s|
MacOS::Version.from_symbol(s.to_sym)
macos = begin
MacOS::Version.from_symbol(args.macos.to_sym)
rescue MacOSVersionError rescue MacOSVersionError
MacOS::Version.new(args.macos) MacOS::Version.new(s)
end end
raise UsageError, "Must specify --macos option" unless macos
tap = Tap.fetch(args.tap || CoreTap.instance.name) tap = Tap.fetch(args.tap || CoreTap.instance.name)
user, repo = tap.full_name.split("/") user, repo = tap.full_name.split("/")

View File

@ -57,7 +57,7 @@ module Homebrew
options[:only_cops] = only_cops options[:only_cops] = only_cops
elsif except_cops elsif except_cops
options[:except_cops] = except_cops options[:except_cops] = except_cops
elsif only_cops.nil? && except_cops.nil? else
options[:except_cops] = %w[FormulaAuditStrict] options[:except_cops] = %w[FormulaAuditStrict]
end end

View File

@ -93,7 +93,14 @@ module Homebrew
srb_exec = %w[bundle exec srb tc] srb_exec = %w[bundle exec srb tc]
srb_exec << "--error-black-list" << "5061" srb_exec << "--error-black-list" << "5061"
srb_exec << "--quiet" if args.quiet? srb_exec << "--quiet" if args.quiet?
srb_exec << "--autocorrect" if args.fix?
if args.fix?
# Auto-correcting method names is almost always wrong.
srb_exec << "--error-black-list" << "7003"
srb_exec << "--autocorrect"
end
srb_exec += ["--ignore", args.ignore] if args.ignore.present? srb_exec += ["--ignore", args.ignore] if args.ignore.present?
if args.file.present? || args.dir.present? if args.file.present? || args.dir.present?
cd("sorbet") cd("sorbet")

View File

@ -33,11 +33,7 @@ module Homebrew
Formulary.enable_factory_cache! Formulary.enable_factory_cache!
@bottle_tag = if args.tag.present? @bottle_tag = args.tag.presence&.to_sym || Utils::Bottles.tag
args.tag.to_sym
else
Utils::Bottles.tag
end
if args.named.blank? if args.named.blank?
ohai "Getting formulae..." ohai "Getting formulae..."

View File

@ -1,7 +1,6 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "formula"
require "os/linux/glibc" require "os/linux/glibc"
require "system_command" require "system_command"
@ -48,7 +47,7 @@ module SystemConfig
out.puts "/usr/bin/gcc: #{host_gcc_version}" out.puts "/usr/bin/gcc: #{host_gcc_version}"
out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH out.puts "/usr/bin/ruby: #{host_ruby_version}" if RUBY_PATH != HOST_RUBY_PATH
["glibc", "gcc", "xorg"].each do |f| ["glibc", "gcc", "xorg"].each do |f|
out.puts "#{f}: #{formula_linked_version f}" out.puts "#{f}: #{formula_linked_version(f)}"
end end
end end
end end

View File

@ -1,4 +1,4 @@
# typed: false # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "resource" require "resource"
@ -7,15 +7,17 @@ require "metafiles"
module DiskUsageExtension module DiskUsageExtension
extend T::Sig extend T::Sig
sig { returns(Integer) }
def disk_usage def disk_usage
return @disk_usage if @disk_usage return @disk_usage if defined?(@disk_usage)
compute_disk_usage compute_disk_usage
@disk_usage @disk_usage
end end
sig { returns(Integer) }
def file_count def file_count
return @file_count if @file_count return @file_count if defined?(@file_count)
compute_disk_usage compute_disk_usage
@file_count @file_count
@ -32,6 +34,7 @@ module DiskUsageExtension
private private
sig { void }
def compute_disk_usage def compute_disk_usage
if symlink? && !exist? if symlink? && !exist?
@file_count = 1 @file_count = 1
@ -82,6 +85,12 @@ class Pathname
BOTTLE_EXTNAME_RX = /(\.[a-z0-9_]+\.bottle\.(\d+\.)?tar\.gz)$/.freeze BOTTLE_EXTNAME_RX = /(\.[a-z0-9_]+\.bottle\.(\d+\.)?tar\.gz)$/.freeze
# Moves a file from the original location to the {Pathname}'s. # Moves a file from the original location to the {Pathname}'s.
sig do
params(sources: T.any(
Resource, Resource::Partial, String, Pathname,
T::Array[T.any(String, Pathname)], T::Hash[T.any(String, Pathname), String]
)).void
end
def install(*sources) def install(*sources)
sources.each do |src| sources.each do |src|
case src case src
@ -107,6 +116,7 @@ class Pathname
end end
end end
sig { params(src: T.any(String, Pathname), new_basename: String).void }
def install_p(src, new_basename) def install_p(src, new_basename)
raise Errno::ENOENT, src.to_s unless File.symlink?(src) || File.exist?(src) raise Errno::ENOENT, src.to_s unless File.symlink?(src) || File.exist?(src)
@ -130,6 +140,11 @@ class Pathname
private :install_p private :install_p
# Creates symlinks to sources in this folder. # Creates symlinks to sources in this folder.
sig do
params(
sources: T.any(String, Pathname, T::Array[T.any(String, Pathname)], T::Hash[T.any(String, Pathname), String]),
).void
end
def install_symlink(*sources) def install_symlink(*sources)
sources.each do |src| sources.each do |src|
case src case src
@ -156,21 +171,25 @@ class Pathname
alias old_write write alias old_write write
# We assume this pathname object is a file, obviously. # We assume this pathname object is a file, obviously.
def write(content, *open_args) sig { params(content: String, offset: Integer, open_args: T::Hash[Symbol, T.untyped]).returns(Integer) }
def write(content, offset = 0, open_args = {})
raise "Will not overwrite #{self}" if exist? raise "Will not overwrite #{self}" if exist?
dirname.mkpath dirname.mkpath
open("w", *open_args) { |f| f.write(content) }
old_write(content, offset, open_args)
end end
# Only appends to a file that is already created. # Only appends to a file that is already created.
def append_lines(content, *open_args) sig { params(content: String, open_args: T.untyped).void }
def append_lines(content, **open_args)
raise "Cannot append file that doesn't exist: #{self}" unless exist? raise "Cannot append file that doesn't exist: #{self}" unless exist?
open("a", *open_args) { |f| f.puts(content) } T.unsafe(self).open("a", **open_args) { |f| f.puts(content) }
end end
# @note This always overwrites. # @note This always overwrites.
sig { params(content: String).void }
def atomic_write(content) def atomic_write(content)
old_stat = stat if exist? old_stat = stat if exist?
File.atomic_write(self) do |file| File.atomic_write(self) do |file|
@ -220,8 +239,9 @@ class Pathname
alias extname_old extname alias extname_old extname
# Extended to support common double extensions. # Extended to support common double extensions.
def extname(path = to_s) sig { returns(String) }
basename = File.basename(path) def extname
basename = File.basename(self)
bottle_ext = basename[BOTTLE_EXTNAME_RX, 1] bottle_ext = basename[BOTTLE_EXTNAME_RX, 1]
return bottle_ext if bottle_ext return bottle_ext if bottle_ext
@ -236,14 +256,16 @@ class Pathname
end end
# For filetypes we support, returns basename without extension. # For filetypes we support, returns basename without extension.
sig { returns(String) }
def stem def stem
File.basename((path = to_s), extname(path)) File.basename(self, extname)
end end
# I don't trust the children.length == 0 check particularly, not to mention # I don't trust the children.length == 0 check particularly, not to mention
# it is slow to enumerate the whole directory just to see if it is empty, # it is slow to enumerate the whole directory just to see if it is empty,
# instead rely on good ol' libc and the filesystem # instead rely on good ol' libc and the filesystem
# @private # @private
sig { returns(T::Boolean) }
def rmdir_if_possible def rmdir_if_possible
rmdir rmdir
true true
@ -259,21 +281,25 @@ class Pathname
end end
# @private # @private
sig { returns(Version) }
def version def version
require "version" require "version"
Version.parse(basename) Version.parse(basename)
end end
# @private # @private
sig { returns(T::Boolean) }
def text_executable? def text_executable?
/^#!\s*\S+/ =~ open("r") { |f| f.read(1024) } /^#!\s*\S+/.match?(open("r") { |f| f.read(1024) })
end end
sig { returns(String) }
def sha256 def sha256
require "digest/sha2" require "digest/sha2"
Digest::SHA256.file(self).hexdigest Digest::SHA256.file(self).hexdigest
end end
sig { params(expected: T.nilable(Checksum)).void }
def verify_checksum(expected) def verify_checksum(expected)
raise ChecksumMissingError if expected.nil? || expected.empty? raise ChecksumMissingError if expected.nil? || expected.empty?
@ -283,7 +309,12 @@ class Pathname
alias to_str to_s alias to_str to_s
def cd sig do
type_parameters(:U).params(
_block: T.proc.params(path: Pathname).returns(T.type_parameter(:U)),
).returns(T.type_parameter(:U))
end
def cd(&_block)
Dir.chdir(self) { yield self } Dir.chdir(self) { yield self }
end end
@ -382,6 +413,14 @@ class Pathname
end end
# Writes an exec script that invokes a Java jar. # Writes an exec script that invokes a Java jar.
sig do
params(
target_jar: T.any(String, Pathname),
script_name: T.any(String, Pathname),
java_opts: String,
java_version: T.nilable(String),
).returns(Integer)
end
def write_jar_script(target_jar, script_name, java_opts = "", java_version: nil) def write_jar_script(target_jar, script_name, java_opts = "", java_version: nil)
(self/script_name).write <<~EOS (self/script_name).write <<~EOS
#!/bin/bash #!/bin/bash
@ -431,11 +470,14 @@ require "extend/os/pathname"
# @private # @private
module ObserverPathnameExtension module ObserverPathnameExtension
extend T::Sig
class << self class << self
extend T::Sig extend T::Sig
include Context include Context
sig { returns(Integer) }
attr_accessor :n, :d attr_accessor :n, :d
sig { void } sig { void }
@ -444,16 +486,21 @@ module ObserverPathnameExtension
@put_verbose_trimmed_warning = false @put_verbose_trimmed_warning = false
end end
sig { returns(Integer) }
def total def total
n + d n + d
end end
sig { returns([Integer, Integer]) }
def counts def counts
[n, d] [n, d]
end end
MAXIMUM_VERBOSE_OUTPUT = 100 MAXIMUM_VERBOSE_OUTPUT = 100
private_constant :MAXIMUM_VERBOSE_OUTPUT
sig { returns(T::Boolean) }
def verbose? def verbose?
return super unless ENV["CI"] return super unless ENV["CI"]
return false unless super return false unless super
@ -470,34 +517,40 @@ module ObserverPathnameExtension
end end
end end
sig { void }
def unlink def unlink
super super
puts "rm #{self}" if ObserverPathnameExtension.verbose? puts "rm #{self}" if ObserverPathnameExtension.verbose?
ObserverPathnameExtension.n += 1 ObserverPathnameExtension.n += 1
end end
sig { void }
def mkpath def mkpath
super super
puts "mkdir -p #{self}" if ObserverPathnameExtension.verbose? puts "mkdir -p #{self}" if ObserverPathnameExtension.verbose?
end end
sig { void }
def rmdir def rmdir
super super
puts "rmdir #{self}" if ObserverPathnameExtension.verbose? puts "rmdir #{self}" if ObserverPathnameExtension.verbose?
ObserverPathnameExtension.d += 1 ObserverPathnameExtension.d += 1
end end
sig { params(src: Pathname).void }
def make_relative_symlink(src) def make_relative_symlink(src)
super super
puts "ln -s #{src.relative_path_from(dirname)} #{basename}" if ObserverPathnameExtension.verbose? puts "ln -s #{src.relative_path_from(dirname)} #{basename}" if ObserverPathnameExtension.verbose?
ObserverPathnameExtension.n += 1 ObserverPathnameExtension.n += 1
end end
sig { void }
def install_info def install_info
super super
puts "info #{self}" if ObserverPathnameExtension.verbose? puts "info #{self}" if ObserverPathnameExtension.verbose?
end end
sig { void }
def uninstall_info def uninstall_info
super super
puts "uninfo #{self}" if ObserverPathnameExtension.verbose? puts "uninfo #{self}" if ObserverPathnameExtension.verbose?

View File

@ -0,0 +1,19 @@
# typed: strict
module DiskUsageExtension
include Kernel
def exist?; end
def symlink?; end
def resolved_path; end
end
module ObserverPathnameExtension
include Kernel
def dirname; end
def basename; end
end

View File

@ -4,11 +4,16 @@
module Homebrew module Homebrew
# @api private # @api private
module Fetch module Fetch
extend T::Sig
sig { params(f: Formula, args: CLI::Args).returns(T::Boolean) }
def fetch_bottle?(f, args:) def fetch_bottle?(f, args:)
return true if args.force_bottle? && f.bottle bottle = f.bottle
return false unless f.bottle && f.pour_bottle?
return true if args.force_bottle? && bottle
return false unless bottle && f.pour_bottle?
return false if args.build_from_source_formulae.include?(f.full_name) return false if args.build_from_source_formulae.include?(f.full_name)
return false unless f.bottle.compatible_cellar? return false unless bottle.compatible_cellar?
true true
end end

View File

@ -9,6 +9,11 @@ require "ostruct"
require "pp" require "pp"
require "forwardable" require "forwardable"
require "rbconfig"
RUBY_PATH = Pathname.new(RbConfig.ruby).freeze
RUBY_BIN = RUBY_PATH.dirname.freeze
require_relative "load_path" require_relative "load_path"
require "rubygems" require "rubygems"
@ -41,26 +46,11 @@ HOMEBREW_DEFAULT_CACHE = ENV["HOMEBREW_DEFAULT_CACHE"]
HOMEBREW_DEFAULT_LOGS = ENV["HOMEBREW_DEFAULT_LOGS"] HOMEBREW_DEFAULT_LOGS = ENV["HOMEBREW_DEFAULT_LOGS"]
HOMEBREW_DEFAULT_TEMP = ENV["HOMEBREW_DEFAULT_TEMP"] HOMEBREW_DEFAULT_TEMP = ENV["HOMEBREW_DEFAULT_TEMP"]
HOMEBREW_REQUIRED_RUBY_VERSION = ENV["HOMEBREW_REQUIRED_RUBY_VERSION"] HOMEBREW_REQUIRED_RUBY_VERSION = ENV["HOMEBREW_REQUIRED_RUBY_VERSION"]
require "env_config"
require "config"
require "os"
require "context"
require "extend/pathname"
require "extend/predicable"
require "extend/module"
require "cli/args"
require "messages"
HOMEBREW_PRODUCT = ENV["HOMEBREW_PRODUCT"] HOMEBREW_PRODUCT = ENV["HOMEBREW_PRODUCT"]
HOMEBREW_VERSION = ENV["HOMEBREW_VERSION"] HOMEBREW_VERSION = ENV["HOMEBREW_VERSION"]
HOMEBREW_WWW = "https://brew.sh" HOMEBREW_WWW = "https://brew.sh"
require "rbconfig"
RUBY_PATH = Pathname.new(RbConfig.ruby).freeze
RUBY_BIN = RUBY_PATH.dirname.freeze
HOMEBREW_USER_AGENT_CURL = ENV["HOMEBREW_USER_AGENT_CURL"] HOMEBREW_USER_AGENT_CURL = ENV["HOMEBREW_USER_AGENT_CURL"]
HOMEBREW_USER_AGENT_RUBY = HOMEBREW_USER_AGENT_RUBY =
"#{ENV["HOMEBREW_USER_AGENT"]} ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}" "#{ENV["HOMEBREW_USER_AGENT"]} ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
@ -72,8 +62,18 @@ HOMEBREW_DEFAULT_PREFIX = "/usr/local"
HOMEBREW_MACOS_ARM_DEFAULT_PREFIX = "/opt/homebrew" HOMEBREW_MACOS_ARM_DEFAULT_PREFIX = "/opt/homebrew"
HOMEBREW_LINUX_DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew" HOMEBREW_LINUX_DEFAULT_PREFIX = "/home/linuxbrew/.linuxbrew"
HOMEBREW_PULL_API_REGEX =
%r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
HOMEBREW_PULL_OR_COMMIT_URL_REGEX =
%r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})].freeze
HOMEBREW_RELEASES_URL_REGEX =
%r{https://github\.com/([\w-]+)/([\w-]+)?/releases/download/(.+)}.freeze
require "fileutils" require "fileutils"
require "os"
require "os/global" require "os/global"
require "messages"
module Homebrew module Homebrew
extend FileUtils extend FileUtils
@ -111,12 +111,14 @@ module Homebrew
end end
end end
HOMEBREW_PULL_API_REGEX = require "env_config"
%r{https://api\.github\.com/repos/([\w-]+)/([\w-]+)?/pulls/(\d+)}.freeze
HOMEBREW_PULL_OR_COMMIT_URL_REGEX = require "config"
%r[https://github\.com/([\w-]+)/([\w-]+)?/(?:pull/(\d+)|commit/[0-9a-fA-F]{4,40})].freeze require "context"
HOMEBREW_RELEASES_URL_REGEX = require "extend/pathname"
%r{https://github\.com/([\w-]+)/([\w-]+)?/releases/download/(.+)}.freeze require "extend/predicable"
require "extend/module"
require "cli/args"
require "PATH" require "PATH"

View File

@ -234,7 +234,7 @@ class Migrator
return unless old_cellar.exist? return unless old_cellar.exist?
if new_cellar.exist? if new_cellar.exist?
conflicted = false conflicted = T.let(false, T::Boolean)
old_cellar.each_child do |c| old_cellar.each_child do |c|
next unless (new_cellar/c.basename).exist? next unless (new_cellar/c.basename).exist?

View File

@ -94,7 +94,7 @@ module Homebrew
alias generic_disallowed_reason disallowed_reason alias generic_disallowed_reason disallowed_reason
def tap_migration_reason(name) def tap_migration_reason(name)
message = nil message = T.let(nil, T.nilable(String))
Tap.each do |old_tap| Tap.each do |old_tap|
new_tap = old_tap.tap_migrations[name] new_tap = old_tap.tap_migrations[name]

View File

@ -5,9 +5,12 @@
# #
# @api private # @api private
module OS module OS
extend T::Sig
# Check if the operating system is macOS. # Check if the operating system is macOS.
# #
# @api public # @api public
sig { returns(T::Boolean) }
def self.mac? def self.mac?
return false if ENV["HOMEBREW_TEST_GENERIC_OS"] return false if ENV["HOMEBREW_TEST_GENERIC_OS"]
@ -17,6 +20,7 @@ module OS
# Check if the operating system is Linux. # Check if the operating system is Linux.
# #
# @api public # @api public
sig { returns(T::Boolean) }
def self.linux? def self.linux?
return false if ENV["HOMEBREW_TEST_GENERIC_OS"] return false if ENV["HOMEBREW_TEST_GENERIC_OS"]
@ -26,6 +30,7 @@ module OS
# Get the kernel version. # Get the kernel version.
# #
# @api public # @api public
sig { returns(Version) }
def self.kernel_version def self.kernel_version
@kernel_version ||= Version.new(Utils.safe_popen_read("uname", "-r").chomp) @kernel_version ||= Version.new(Utils.safe_popen_read("uname", "-r").chomp)
end end

View File

@ -1,6 +1,8 @@
# typed: false # typed: false
# frozen_string_literal: true # frozen_string_literal: true
require "env_config"
# Enables experimental `patchelf.rb` write support. # Enables experimental `patchelf.rb` write support.
HOMEBREW_PATCHELF_RB_WRITE = ( HOMEBREW_PATCHELF_RB_WRITE = (
ENV["HOMEBREW_NO_PATCHELF_RB_WRITE"].blank? && ENV["HOMEBREW_NO_PATCHELF_RB_WRITE"].blank? &&
@ -8,7 +10,7 @@ HOMEBREW_PATCHELF_RB_WRITE = (
).freeze ).freeze
module Homebrew module Homebrew
DEFAULT_PREFIX ||= if Homebrew::EnvConfig.force_homebrew_on_linux? DEFAULT_PREFIX ||= if EnvConfig.force_homebrew_on_linux?
HOMEBREW_DEFAULT_PREFIX HOMEBREW_DEFAULT_PREFIX
else else
HOMEBREW_LINUX_DEFAULT_PREFIX HOMEBREW_LINUX_DEFAULT_PREFIX

View File

@ -1,4 +1,4 @@
# typed: false # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
old_trap = trap("INT") { exit! 130 } old_trap = trap("INT") { exit! 130 }
@ -12,12 +12,12 @@ require "cmd/postinstall"
begin begin
args = Homebrew.postinstall_args.parse args = Homebrew.postinstall_args.parse
error_pipe = UNIXSocket.open(ENV["HOMEBREW_ERROR_PIPE"], &:recv_io) error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
trap("INT", old_trap) trap("INT", old_trap)
formula = args.named.to_resolved_formulae.first formula = T.must(args.named.to_resolved_formulae.first)
formula.extend(Debrew::Formula) if args.debug? formula.extend(Debrew::Formula) if args.debug?
formula.run_post_install formula.run_post_install
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException

View File

@ -10,7 +10,7 @@ require "cask/cask_loader"
module Readall module Readall
class << self class << self
def valid_ruby_syntax?(ruby_files) def valid_ruby_syntax?(ruby_files)
failed = false failed = T.let(false, T::Boolean)
ruby_files.each do |ruby_file| ruby_files.each do |ruby_file|
# As a side effect, print syntax errors/warnings to `$stderr`. # As a side effect, print syntax errors/warnings to `$stderr`.
failed = true if syntax_errors_or_warnings?(ruby_file) failed = true if syntax_errors_or_warnings?(ruby_file)
@ -21,7 +21,7 @@ module Readall
def valid_aliases?(alias_dir, formula_dir) def valid_aliases?(alias_dir, formula_dir)
return true unless alias_dir.directory? return true unless alias_dir.directory?
failed = false failed = T.let(false, T::Boolean)
alias_dir.each_child do |f| alias_dir.each_child do |f|
if !f.symlink? if !f.symlink?
onoe "Non-symlink alias: #{f}" onoe "Non-symlink alias: #{f}"
@ -40,7 +40,7 @@ module Readall
end end
def valid_formulae?(formulae) def valid_formulae?(formulae)
success = true success = T.let(true, T::Boolean)
formulae.each do |file| formulae.each do |file|
Formulary.factory(file) Formulary.factory(file)
rescue Interrupt rescue Interrupt
@ -54,7 +54,7 @@ module Readall
end end
def valid_casks?(casks) def valid_casks?(casks)
success = true success = T.let(true, T::Boolean)
casks.each do |file| casks.each do |file|
Cask::CaskLoader.load(file) Cask::CaskLoader.load(file)
rescue Interrupt rescue Interrupt

View File

@ -46,7 +46,7 @@ module RuboCop
next if node.nil? next if node.nil?
reason_found = false reason_found = T.let(false, T::Boolean)
reason(node) do |reason_node| reason(node) do |reason_node|
reason_found = true reason_found = true
next if reason_node.sym_type? next if reason_node.sym_type?

View File

@ -1,4 +1,4 @@
# typed: false # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "erb" require "erb"
@ -56,12 +56,12 @@ class Sandbox
end end
def allow_cvs def allow_cvs
allow_write_path "#{Dir.home(ENV["USER"])}/.cvspass" allow_write_path "#{Dir.home(ENV.fetch("USER"))}/.cvspass"
end end
def allow_fossil def allow_fossil
allow_write_path "#{Dir.home(ENV["USER"])}/.fossil" allow_write_path "#{Dir.home(ENV.fetch("USER"))}/.fossil"
allow_write_path "#{Dir.home(ENV["USER"])}/.fossil-journal" allow_write_path "#{Dir.home(ENV.fetch("USER"))}/.fossil-journal"
end end
def allow_write_cellar(formula) def allow_write_cellar(formula)
@ -72,7 +72,7 @@ class Sandbox
# Xcode projects expect access to certain cache/archive dirs. # Xcode projects expect access to certain cache/archive dirs.
def allow_write_xcode def allow_write_xcode
allow_write_path "#{Dir.home(ENV["USER"])}/Library/Developer" allow_write_path "#{Dir.home(ENV.fetch("USER"))}/Library/Developer"
end end
def allow_write_log(formula) def allow_write_log(formula)
@ -94,40 +94,43 @@ class Sandbox
seatbelt.write(@profile.dump) seatbelt.write(@profile.dump)
seatbelt.close seatbelt.close
@start = Time.now @start = Time.now
safe_system SANDBOX_EXEC, "-f", seatbelt.path, *args
rescue
@failed = true
raise
ensure
seatbelt.unlink
sleep 0.1 # wait for a bit to let syslog catch up the latest events.
syslog_args = %W[
-F $((Time)(local))\ $(Sender)[$(PID)]:\ $(Message)
-k Time ge #{@start.to_i}
-k Message S deny
-k Sender kernel
-o
-k Time ge #{@start.to_i}
-k Message S deny
-k Sender sandboxd
]
logs = Utils.popen_read("syslog", *syslog_args)
# These messages are confusing and non-fatal, so don't report them. begin
logs = logs.lines.reject { |l| l.match(/^.*Python\(\d+\) deny file-write.*pyc$/) }.join T.unsafe(self).safe_system SANDBOX_EXEC, "-f", seatbelt.path, *args
rescue
@failed = true
raise
ensure
seatbelt.unlink
sleep 0.1 # wait for a bit to let syslog catch up the latest events.
syslog_args = %W[
-F $((Time)(local))\ $(Sender)[$(PID)]:\ $(Message)
-k Time ge #{@start.to_i}
-k Message S deny
-k Sender kernel
-o
-k Time ge #{@start.to_i}
-k Message S deny
-k Sender sandboxd
]
logs = Utils.popen_read("syslog", *syslog_args)
unless logs.empty? # These messages are confusing and non-fatal, so don't report them.
if @logfile logs = logs.lines.reject { |l| l.match(/^.*Python\(\d+\) deny file-write.*pyc$/) }.join
File.open(@logfile, "w") do |log|
log.write logs unless logs.empty?
log.write "\nWe use time to filter sandbox log. Therefore, unrelated logs may be recorded.\n" if @logfile
File.open(@logfile, "w") do |log|
log.write logs
log.write "\nWe use time to filter sandbox log. Therefore, unrelated logs may be recorded.\n"
end
end end
end
if @failed && Homebrew::EnvConfig.verbose? if @failed && Homebrew::EnvConfig.verbose?
ohai "Sandbox log" ohai "Sandbox log"
puts logs puts logs
$stdout.flush # without it, brew test-bot would fail to catch the log $stdout.flush # without it, brew test-bot would fail to catch the log
end
end end
end end
end end

View File

@ -1,13 +1,31 @@
# typed: strict # typed: strict
class Pathname # This file contains temporary definitions for fixes that have
# https://github.com/sorbet/sorbet/pull/3676 # been submitted upstream to https://github.com/sorbet/sorbet.
sig { params(p1: T.any(String, Pathname), p2: String).returns(T::Array[Pathname]) }
def self.glob(p1, p2 = T.unsafe(nil)); end
# https://github.com/sorbet/sorbet/pull/3678 class IO
sig { params(with_directory: T::Boolean).returns(T::Array[Pathname]) } # https://github.com/sorbet/sorbet/pull/3722
def children(with_directory = true); end sig do
type_parameters(:U).params(
fd: T.any(String, Integer),
mode: T.any(Integer, String),
opt: T.nilable(T::Hash[Symbol, T.untyped]),
blk: T.proc.params(io: T.attached_class).returns(T.type_parameter(:U))
).returns(T.type_parameter(:U))
end
def self.open(fd, mode='r', opt=nil, &blk); end
end
class Pathname
# https://github.com/sorbet/sorbet/pull/3729
sig do
params(
owner: T.nilable(Integer),
group: T.nilable(Integer),
)
.returns(Integer)
end
def chown(owner, group); end
end end
module FileUtils module FileUtils

View File

@ -1,6 +1,8 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "config"
# Match taps' formulae, e.g. `someuser/sometap/someformula` # Match taps' formulae, e.g. `someuser/sometap/someformula`
HOMEBREW_TAP_FORMULA_REGEX = %r{^([\w-]+)/([\w-]+)/([\w+-.@]+)$}.freeze HOMEBREW_TAP_FORMULA_REGEX = %r{^([\w-]+)/([\w-]+)/([\w+-.@]+)$}.freeze
# Match taps' casks, e.g. `someuser/sometap/somecask` # Match taps' casks, e.g. `someuser/sometap/somecask`

View File

@ -20,7 +20,7 @@ begin
args = Homebrew.test_args.parse args = Homebrew.test_args.parse
Context.current = args.context Context.current = args.context
error_pipe = UNIXSocket.open(ENV["HOMEBREW_ERROR_PIPE"], &:recv_io) error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
trap("INT", old_trap) trap("INT", old_trap)
@ -30,13 +30,13 @@ begin
raise "cannot kill child processes without `pkill`, please install!" unless which("pkill") raise "cannot kill child processes without `pkill`, please install!" unless which("pkill")
end end
formula = args.named.to_resolved_formulae.first formula = T.must(args.named.to_resolved_formulae.first)
formula.extend(Homebrew::Assertions) formula.extend(Homebrew::Assertions)
formula.extend(Homebrew::FreePort) formula.extend(Homebrew::FreePort)
formula.extend(Debrew::Formula) if args.debug? formula.extend(Debrew::Formula) if args.debug?
ENV.extend(Stdenv) ENV.extend(Stdenv)
ENV.setup_build_environment(formula: formula) T.cast(ENV, Stdenv).setup_build_environment(formula: formula)
# tests can also return false to indicate failure # tests can also return false to indicate failure
Timeout.timeout TEST_TIMEOUT_SECONDS do Timeout.timeout TEST_TIMEOUT_SECONDS do

View File

@ -2,7 +2,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "keg" require "keg"
require "formula"
module Homebrew module Homebrew
# Helper module for uninstalling kegs. # Helper module for uninstalling kegs.

View File

@ -34,7 +34,7 @@ module Homebrew
end end
exit! 1 # never gets here unless exec failed exit! 1 # never gets here unless exec failed
end end
Process.wait(pid) Process.wait(T.must(pid))
$CHILD_STATUS.success? $CHILD_STATUS.success?
end end
@ -58,10 +58,13 @@ module Homebrew
method = instance_method(name) method = instance_method(name)
define_method(name) do |*args, &block| define_method(name) do |*args, &block|
time = Time.now time = Time.now
method.bind(self).call(*args, &block)
ensure begin
$times[name] ||= 0 method.bind(self).call(*args, &block)
$times[name] += Time.now - time ensure
$times[name] ||= 0
$times[name] += Time.now - time
end
end end
end end
end end
@ -190,7 +193,7 @@ module Kernel
line.include?("/.metadata/") line.include?("/.metadata/")
end end
tap_message = nil tap_message = T.let(nil, T.nilable(String))
backtrace.each do |line| backtrace.each do |line|
next unless match = line.match(HOMEBREW_TAP_PATH_REGEX) next unless match = line.match(HOMEBREW_TAP_PATH_REGEX)
@ -263,12 +266,12 @@ module Kernel
ENV["HOMEBREW_DEBUG_INSTALL"] = f.full_name ENV["HOMEBREW_DEBUG_INSTALL"] = f.full_name
end end
if ENV["SHELL"].include?("zsh") && ENV["HOME"].start_with?(HOMEBREW_TEMP.resolved_path.to_s) if ENV["SHELL"].include?("zsh") && (home = ENV["HOME"])&.start_with?(HOMEBREW_TEMP.resolved_path.to_s)
FileUtils.mkdir_p ENV["HOME"] FileUtils.mkdir_p home
FileUtils.touch "#{ENV["HOME"]}/.zshrc" FileUtils.touch "#{home}/.zshrc"
end end
Process.wait fork { exec ENV["SHELL"] } Process.wait fork { exec ENV.fetch("SHELL") }
return if $CHILD_STATUS.success? return if $CHILD_STATUS.success?
raise "Aborted due to non-zero exit status (#{$CHILD_STATUS.exitstatus})" if $CHILD_STATUS.exited? raise "Aborted due to non-zero exit status (#{$CHILD_STATUS.exitstatus})" if $CHILD_STATUS.exited?

View File

@ -58,7 +58,7 @@ module Utils
"--silent", "--output", "/dev/null", "--silent", "--output", "/dev/null",
"https://www.google-analytics.com/collect" "https://www.google-analytics.com/collect"
end end
Process.detach pid Process.detach T.must(pid)
end end
end end

View File

@ -64,7 +64,7 @@ module Utils
begin begin
socket = server.accept_nonblock socket = server.accept_nonblock
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
retry unless Process.waitpid(pid, Process::WNOHANG) retry unless Process.waitpid(T.must(pid), Process::WNOHANG)
else else
socket.send_io(write) socket.send_io(write)
socket.close socket.close
@ -72,7 +72,7 @@ module Utils
write.close write.close
data = read.read data = read.read
read.close read.close
Process.wait(pid) unless socket.nil? Process.wait(T.must(pid)) unless socket.nil?
# 130 is the exit status for a process interrupted via Ctrl-C. # 130 is the exit status for a process interrupted via Ctrl-C.
# We handle it here because of the possibility of an interrupted process terminating # We handle it here because of the possibility of an interrupted process terminating
@ -80,7 +80,7 @@ module Utils
raise Interrupt if $CHILD_STATUS.exitstatus == 130 raise Interrupt if $CHILD_STATUS.exitstatus == 130
if data && !data.empty? if data && !data.empty?
error_hash = JSON.parse(data.lines.first) error_hash = JSON.parse(T.must(data.lines.first))
e = ChildProcessError.new(error_hash) e = ChildProcessError.new(error_hash)

View File

@ -122,9 +122,9 @@ module PyPI
package_name: T.nilable(String), package_name: T.nilable(String),
extra_packages: T.nilable(T::Array[String]), extra_packages: T.nilable(T::Array[String]),
exclude_packages: T.nilable(T::Array[String]), exclude_packages: T.nilable(T::Array[String]),
print_only: T::Boolean, print_only: T.nilable(T::Boolean),
silent: T::Boolean, silent: T.nilable(T::Boolean),
ignore_non_pypi_packages: T::Boolean, ignore_non_pypi_packages: T.nilable(T::Boolean),
).returns(T.nilable(T::Boolean)) ).returns(T.nilable(T::Boolean))
end end
def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil, def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil,

View File

@ -1,6 +1,8 @@
# typed: true # typed: true
# frozen_string_literal: true # frozen_string_literal: true
require "env_config"
# Various helper functions for interacting with TTYs. # Various helper functions for interacting with TTYs.
# #
# @api private # @api private