Bump more files to Sorbet typed: strict

This commit is contained in:
Issy Long 2025-01-06 00:12:03 +00:00
parent 0c268f9234
commit 268f801038
No known key found for this signature in database
9 changed files with 94 additions and 43 deletions

View File

@ -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"

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "extend/cachable"
@ -15,7 +15,7 @@ module Homebrew
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
@ -41,6 +41,7 @@ module Homebrew
end
end
sig { returns(Pathname) }
def self.cached_json_file_path
if Homebrew::API.internal_json_v3?
HOMEBREW_CACHE_API/INTERNAL_V3_API_FILENAME
@ -75,7 +76,7 @@ module Homebrew
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!
@ -105,7 +106,7 @@ module Homebrew
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")

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "system_command"
@ -51,14 +51,15 @@ module Homebrew
# 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)
@ -82,6 +83,7 @@ module Homebrew
difference
end
sig { params(other: BundleVersion).returns(T::Boolean) }
def ==(other)
instance_of?(other.class) && short_version == other.short_version && version == other.version
end

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "requirement"
@ -12,32 +12,43 @@ class CaskDependent
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|
@deps ||= T.let(
@cask.depends_on.formula.map do |f|
Dependency.new f
end
end,
T.nilable(T::Array[Dependency]),
)
end
sig { returns(T::Array[CaskDependent::Requirement]) }
def requirements
@requirements ||= begin
@requirements ||= T.let(
begin
requirements = []
dsl_reqs = @cask.depends_on
@ -61,17 +72,22 @@ class CaskDependent
requirements << dsl_reqs.macos if dsl_reqs.macos
requirements
end
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

View File

@ -186,8 +186,8 @@ module Homebrew
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.

View File

@ -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,
@ -27,12 +30,16 @@ class FormulaInfo
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"]
@ -43,29 +50,35 @@ class FormulaInfo
{ "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

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "utils/string_inreplace_extension"
@ -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
@ -82,12 +83,19 @@ module Utils
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

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil
# typed: strict
# frozen_string_literal: true
require "utils/curl"
@ -10,6 +10,7 @@ module Repology
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"
@ -27,6 +28,7 @@ module Repology
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}"
@ -47,6 +49,13 @@ module Repology
nil
end
sig {
params(
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
@ -80,6 +89,7 @@ module Repology
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.
@ -97,6 +107,6 @@ module Repology
# scheme
return "no latest version" if latest_version.blank?
Version.new(latest_version["version"])
Version.new(T.must(latest_version["version"]))
end
end

View File

@ -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