Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump more files to Sorbet typed: strict #19042

Merged
merged 1 commit into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Library/.rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ Sorbet/StrictSigil:
- "Taps/**/*"
- "/**/{Formula,Casks}/**/*.rb"
- "**/{Formula,Casks}/**/*.rb"
- "Homebrew/utils/ruby_check_version_script.rb" # A standalone script.
- "Homebrew/{standalone,startup}/*.rb" # These are loaded before sorbet-runtime
- "Homebrew/test/**/*.rb"

Expand Down
9 changes: 5 additions & 4 deletions Library/Homebrew/api/formula.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true

require "extend/cachable"
Expand All @@ -15,7 +15,7 @@ module Formula

private_class_method :cache

sig { params(name: String).returns(Hash) }
sig { params(name: String).returns(T::Hash[String, T.untyped]) }
def self.fetch(name)
Homebrew::API.fetch "formula/#{name}.json"
end
Expand All @@ -41,6 +41,7 @@ def self.source_download(formula)
end
end

sig { returns(Pathname) }
def self.cached_json_file_path
if Homebrew::API.internal_json_v3?
HOMEBREW_CACHE_API/INTERNAL_V3_API_FILENAME
Expand Down Expand Up @@ -75,7 +76,7 @@ def self.download_and_cache_data!
end
private_class_method :download_and_cache_data!

sig { returns(T::Hash[String, Hash]) }
sig { returns(T::Hash[String, T.untyped]) }
def self.all_formulae
unless cache.key?("formulae")
json_updated = download_and_cache_data!
Expand Down Expand Up @@ -105,7 +106,7 @@ def self.all_renames
cache["renames"]
end

sig { returns(Hash) }
sig { returns(T::Hash[String, T.untyped]) }
def self.tap_migrations
# Not sure that we need to reload here.
unless cache.key?("tap_migrations")
Expand Down
8 changes: 5 additions & 3 deletions Library/Homebrew/bundle_version.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true

require "system_command"
Expand Down Expand Up @@ -51,14 +51,15 @@ def initialize(short_version, version)
# Remove version from short version, if present.
short_version = short_version&.sub(/\s*\(#{Regexp.escape(version)}\)\Z/, "") if version

@short_version = short_version.presence
@version = version.presence
@short_version = T.let(short_version.presence, T.nilable(String))
@version = T.let(version.presence, T.nilable(String))

return if @short_version || @version

raise ArgumentError, "`short_version` and `version` cannot both be `nil` or empty"
end

sig { params(other: BundleVersion).returns(T.any(Integer, NilClass)) }
def <=>(other)
return super unless instance_of?(other.class)

Expand All @@ -82,6 +83,7 @@ def <=>(other)
difference
end

sig { params(other: BundleVersion).returns(T::Boolean) }
def ==(other)
instance_of?(other.class) && short_version == other.short_version && version == other.version
end
Expand Down
66 changes: 41 additions & 25 deletions Library/Homebrew/cask_dependent.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true

require "requirement"
Expand All @@ -12,66 +12,82 @@
end
end

sig { returns(Cask::Cask) }
attr_reader :cask

sig { params(cask: Cask::Cask).void }
def initialize(cask)
@cask = cask
@cask = T.let(cask, Cask::Cask)
end

sig { returns(String) }
def name
@cask.token
end

sig { returns(String) }
def full_name
@cask.full_name
end

sig { returns(T::Array[Dependency]) }
def runtime_dependencies
deps.flat_map { |dep| [dep, *dep.to_formula.runtime_dependencies] }.uniq
end

sig { returns(T::Array[Dependency]) }
def deps
@deps ||= @cask.depends_on.formula.map do |f|
Dependency.new f
end
@deps ||= T.let(
@cask.depends_on.formula.map do |f|
Dependency.new f
end,
T.nilable(T::Array[Dependency]),
)
end

sig { returns(T::Array[CaskDependent::Requirement]) }
def requirements
@requirements ||= begin
requirements = []
dsl_reqs = @cask.depends_on
@requirements ||= T.let(
begin
requirements = []
dsl_reqs = @cask.depends_on

dsl_reqs.arch&.each do |arch|
arch = if arch[:bits] == 64
if arch[:type] == :intel
:x86_64
dsl_reqs.arch&.each do |arch|
arch = if arch[:bits] == 64

Check warning on line 56 in Library/Homebrew/cask_dependent.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/cask_dependent.rb#L56

Added line #L56 was not covered by tests
if arch[:type] == :intel
:x86_64
else
:"#{arch[:type]}64"
end
elsif arch[:type] == :intel && arch[:bits] == 32
:i386
else
:"#{arch[:type]}64"
arch[:type]
end
elsif arch[:type] == :intel && arch[:bits] == 32
:i386
else
arch[:type]
requirements << ArchRequirement.new([arch])

Check warning on line 67 in Library/Homebrew/cask_dependent.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/cask_dependent.rb#L67

Added line #L67 was not covered by tests
end
dsl_reqs.cask.each do |cask_ref|
requirements << CaskDependent::Requirement.new([{ cask: cask_ref }])
end
requirements << ArchRequirement.new([arch])
end
dsl_reqs.cask.each do |cask_ref|
requirements << CaskDependent::Requirement.new([{ cask: cask_ref }])
end
requirements << dsl_reqs.macos if dsl_reqs.macos
requirements << dsl_reqs.macos if dsl_reqs.macos

requirements
end
requirements
end,
T.nilable(T::Array[CaskDependent::Requirement]),
)
end

sig { params(block: T.nilable(T.proc.returns(T::Array[Dependency]))).returns(T::Array[Dependency]) }
def recursive_dependencies(&block)
Dependency.expand(self, &block)
end

sig { params(block: T.nilable(T.proc.returns(CaskDependent::Requirement))).returns(Requirements) }
def recursive_requirements(&block)
Requirement.expand(self, &block)
end

sig { returns(T::Boolean) }
def any_version_installed?
@cask.installed?
end
Expand Down
4 changes: 2 additions & 2 deletions Library/Homebrew/dev-cmd/bump-cask-pr.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ def shortened_version(version, cask:)
cask: Cask::Cask,
new_hash: T.any(NilClass, String, Symbol),
new_version: BumpVersionParser,
replacement_pairs: T::Array[[T.any(Regexp, String), T.any(Regexp, String)]],
).returns(T::Array[[T.any(Regexp, String), T.any(Regexp, String)]])
replacement_pairs: T::Array[[T.any(Regexp, String), T.any(Pathname, String)]],
).returns(T::Array[[T.any(Regexp, String), T.any(Pathname, String)]])
}
def replace_version_and_checksum(cask, new_hash, new_version, replacement_pairs)
# When blocks are absent, arch is not relevant. For consistency, we simulate the arm architecture.
Expand Down
19 changes: 16 additions & 3 deletions Library/Homebrew/formula_info.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true

# Formula information drawn from an external `brew info --json` call.
class FormulaInfo
# The whole info structure parsed from the JSON.
sig { returns(T::Hash[String, T.untyped]) }
attr_accessor :info

sig { params(info: T::Hash[String, T.untyped]).void }
def initialize(info)
@info = info
@info = T.let(info, T::Hash[String, T.untyped])
end

# Looks up formula on disk and reads its info.
# Returns nil if formula is absent or if there was an error reading it.
sig { params(name: Pathname).returns(T.nilable(FormulaInfo)) }
def self.lookup(name)
json = Utils.popen_read(
*HOMEBREW_RUBY_EXEC_ARGS,
Expand All @@ -27,12 +30,16 @@ def self.lookup(name)
FormulaInfo.new(JSON.parse(json)[0])
end

sig { returns(T::Array[String]) }
def bottle_tags
return [] unless info["bottle"]["stable"]

info["bottle"]["stable"]["files"].keys
end

sig {
params(my_bottle_tag: T.any(Utils::Bottles::Tag, T.nilable(String))).returns(T.nilable(T::Hash[String, String]))
}
def bottle_info(my_bottle_tag = Utils::Bottles.tag)
tag_s = my_bottle_tag.to_s
return unless info["bottle"]["stable"]
Expand All @@ -43,29 +50,35 @@ def bottle_info(my_bottle_tag = Utils::Bottles.tag)
{ "url" => btl_info["url"], "sha256" => btl_info["sha256"] }
end

sig { returns(T.nilable(T::Hash[String, String])) }
def bottle_info_any
bottle_info(any_bottle_tag)
end

sig { returns(T.nilable(String)) }
def any_bottle_tag
tag = Utils::Bottles.tag.to_s
# Prefer native bottles as a convenience for download caching
bottle_tags.include?(tag) ? tag : bottle_tags.first
end

sig { params(spec_type: Symbol).returns(Version) }
def version(spec_type)
version_str = info["versions"][spec_type.to_s]
version_str && Version.new(version_str)
Version.new(version_str)
end

sig { params(spec_type: Symbol).returns(PkgVersion) }
def pkg_version(spec_type = :stable)
PkgVersion.new(version(spec_type), revision)
end

sig { returns(Integer) }
def revision
info["revision"]
end

sig { params(str: String).void }
def self.force_utf8!(str)
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
end
Expand Down
14 changes: 11 additions & 3 deletions Library/Homebrew/utils/inreplace.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true

require "utils/string_inreplace_extension"
Expand All @@ -8,6 +8,7 @@ module Utils
module Inreplace
# Error during text replacement.
class Error < RuntimeError
sig { params(errors: T::Hash[String, T::Array[String]]).void }
def initialize(errors)
formatted_errors = errors.reduce(+"inreplace failed\n") do |s, (path, errs)|
s << "#{path}:\n" << errs.map { |e| " #{e}\n" }.join
Expand Down Expand Up @@ -82,12 +83,19 @@ def self.inreplace(paths, before = nil, after = nil, audit_result: true, global:
raise Utils::Inreplace::Error, errors if errors.present?
end

sig {
params(
path: T.any(String, Pathname),
replacement_pairs: T::Array[[T.any(Regexp, Pathname, String), T.any(Pathname, String)]],
read_only_run: T::Boolean,
silent: T::Boolean,
).returns(String)
}
def self.inreplace_pairs(path, replacement_pairs, read_only_run: false, silent: false)
str = File.binread(path)
contents = StringInreplaceExtension.new(str)
replacement_pairs.each do |old, new|
ohai "replace #{old.inspect} with #{new.inspect}" unless silent
unless old
if old.blank?
contents.errors << "No old value for new value #{new}! Did you pass the wrong arguments?"
next
end
Expand Down
14 changes: 12 additions & 2 deletions Library/Homebrew/utils/repology.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true

require "utils/curl"
Expand All @@ -10,6 +10,7 @@
MAX_PAGINATION = 15
private_constant :MAX_PAGINATION

sig { params(last_package_in_response: T.nilable(String), repository: String).returns(T::Hash[String, T.untyped]) }
def self.query_api(last_package_in_response = "", repository:)
last_package_in_response += "/" if last_package_in_response.present?
url = "https://repology.org/api/v1/projects/#{last_package_in_response}?inrepo=#{repository}&outdated=1"
Expand All @@ -27,6 +28,7 @@
raise
end

sig { params(name: String, repository: String).returns(T.nilable(T::Hash[String, T.untyped])) }
def self.single_package_query(name, repository:)
url = "https://repology.org/api/v1/project/#{name}"

Expand All @@ -47,6 +49,13 @@
nil
end

sig {
params(

Check warning on line 53 in Library/Homebrew/utils/repology.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/utils/repology.rb#L53

Added line #L53 was not covered by tests
limit: T.nilable(Integer),
last_package: T.nilable(String),
repository: String,
).returns(T::Hash[String, T.untyped])
}
def self.parse_api_response(limit = nil, last_package = "", repository:)
package_term = case repository
when HOMEBREW_CORE
Expand Down Expand Up @@ -80,6 +89,7 @@
outdated_packages.sort.to_h
end

sig { params(repositories: T::Array[String]).returns(T.any(String, Version)) }
def self.latest_version(repositories)
# The status is "unique" when the package is present only in Homebrew, so
# Repology has no way of knowing if the package is up-to-date.
Expand All @@ -97,6 +107,6 @@
# scheme
return "no latest version" if latest_version.blank?

Version.new(latest_version["version"])
Version.new(T.must(latest_version["version"]))

Check warning on line 110 in Library/Homebrew/utils/repology.rb

View check run for this annotation

Codecov / codecov/patch

Library/Homebrew/utils/repology.rb#L110

Added line #L110 was not covered by tests
end
end
2 changes: 1 addition & 1 deletion Library/Homebrew/utils/ruby_check_version_script.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env ruby
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: true
# frozen_string_literal: true

HOMEBREW_REQUIRED_RUBY_VERSION = ARGV.first.freeze
Expand Down
Loading