Merge remote-tracking branch 'origin/master' into test-runners
This commit is contained in:
commit
ffcc4cd75f
12
.github/workflows/tests.yml
vendored
12
.github/workflows/tests.yml
vendored
@ -38,7 +38,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-rubygems-
|
||||
|
||||
- name: Install Bundler RubyGems
|
||||
run: brew install-bundler-gems --groups=all
|
||||
run: brew install-bundler-gems --groups=sorbet
|
||||
|
||||
- name: Install shellcheck and shfmt
|
||||
run: brew install shellcheck shfmt
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-rubygems-
|
||||
|
||||
- name: Install Bundler RubyGems
|
||||
run: brew install-bundler-gems --groups=all
|
||||
run: brew install-bundler-gems --groups=sorbet
|
||||
|
||||
- name: Run brew style on homebrew-core
|
||||
run: brew style --display-cop-names homebrew/core
|
||||
@ -142,7 +142,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-rubygems-
|
||||
|
||||
- name: Install Bundler RubyGems
|
||||
run: brew install-bundler-gems --groups=all
|
||||
run: brew install-bundler-gems --groups=sorbet
|
||||
|
||||
- name: Set up the homebrew/core tap
|
||||
run: brew tap homebrew/core
|
||||
@ -173,7 +173,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-rubygems-
|
||||
|
||||
- name: Install Bundler RubyGems
|
||||
run: brew install-bundler-gems --groups=all
|
||||
run: brew install-bundler-gems --groups=sorbet
|
||||
|
||||
- name: Set up Homebrew all cask taps
|
||||
run: |
|
||||
@ -209,7 +209,7 @@ jobs:
|
||||
# Can't cache this because we need to check that it doesn't fail the
|
||||
# "uncommitted RubyGems" step with a cold cache.
|
||||
- name: Install Bundler RubyGems
|
||||
run: brew install-bundler-gems --groups=all
|
||||
run: brew install-bundler-gems --groups=sorbet
|
||||
|
||||
- name: Check for uncommitted RubyGems
|
||||
working-directory: ${{ steps.set-up-homebrew.outputs.repository-path }}
|
||||
@ -318,7 +318,7 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-rubygems-
|
||||
|
||||
- name: Install Bundler RubyGems
|
||||
run: brew install-bundler-gems --groups=all
|
||||
run: brew install-bundler-gems --groups=sorbet
|
||||
|
||||
- name: Create parallel test log directory
|
||||
run: mkdir tests
|
||||
|
@ -27,8 +27,12 @@ gem "rspec-retry", require: false
|
||||
gem "rspec-sorbet", require: false
|
||||
gem "rubocop", require: false
|
||||
gem "rubocop-ast", require: false
|
||||
# NOTE: ruby-prof v1.4.3 is the last version that supports Ruby 2.6.x
|
||||
# TODO: remove explicit version when HOMEBREW_REQUIRED_RUBY_VERSION >= 2.7
|
||||
gem "ruby-prof", "1.4.3", require: false
|
||||
gem "simplecov", require: false
|
||||
gem "simplecov-cobertura", require: false
|
||||
gem "stackprof", require: false
|
||||
gem "warning", require: false
|
||||
|
||||
group :sorbet, optional: true do
|
||||
@ -38,13 +42,6 @@ group :sorbet, optional: true do
|
||||
gem "tapioca", require: false
|
||||
end
|
||||
|
||||
group :prof, optional: true do
|
||||
# NOTE: ruby-prof v1.4.3 is the last version that supports Ruby 2.6.x
|
||||
# TODO: remove explicit version when HOMEBREW_REQUIRED_RUBY_VERSION >= 2.7
|
||||
gem "ruby-prof", "1.4.3", require: false
|
||||
gem "stackprof", require: false
|
||||
end
|
||||
|
||||
# vendored gems
|
||||
gem "activesupport"
|
||||
gem "addressable"
|
||||
|
@ -7,7 +7,7 @@ GEM
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.1)
|
||||
addressable (2.8.2)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
ast (2.4.2)
|
||||
bindata (2.4.15)
|
||||
@ -82,7 +82,7 @@ GEM
|
||||
parser
|
||||
rainbow (~> 3.0)
|
||||
sorbet-runtime (>= 0.5)
|
||||
parser (3.2.1.1)
|
||||
parser (3.2.2.0)
|
||||
ast (~> 2.4.1)
|
||||
patchelf (1.4.0)
|
||||
elftools (>= 1.2)
|
||||
|
@ -104,7 +104,7 @@ module Cask
|
||||
message << "during #{section} " if section
|
||||
message << "on Cask #{token}."
|
||||
|
||||
opoo "#{message}\n#{error_message_with_suggestions}"
|
||||
ofail "#{message}\n#{error_message_with_suggestions}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
@ -60,10 +60,10 @@ module Homebrew
|
||||
|
||||
odie "No #{name} #{pg_version_data}.* version installed!" unless old_bin
|
||||
|
||||
server_stopped = false
|
||||
moved_data = false
|
||||
initdb_run = false
|
||||
upgraded = false
|
||||
server_stopped = T.let(false, T::Boolean)
|
||||
moved_data = T.let(false, T::Boolean)
|
||||
initdb_run = T.let(false, T::Boolean)
|
||||
upgraded = T.let(false, T::Boolean)
|
||||
|
||||
begin
|
||||
# Following instructions from:
|
||||
@ -88,7 +88,7 @@ module Homebrew
|
||||
system "#{old_bin}/pg_ctl", "-w", "-D", datadir, "start"
|
||||
end
|
||||
|
||||
initdb_args = []
|
||||
initdb_args = T.let([], T::Array[String])
|
||||
locale_settings = %w[
|
||||
lc_collate
|
||||
lc_ctype
|
||||
|
@ -32,6 +32,11 @@ module Commands
|
||||
"lc" => "livecheck",
|
||||
"tc" => "typecheck",
|
||||
}.freeze
|
||||
# This pattern is used to split descriptions at full stops. We only consider a
|
||||
# dot as a full stop if it is either followed by a whitespace or at the end of
|
||||
# the description. In this way we can prevent cutting off a sentence in the
|
||||
# middle due to dots in URLs or paths.
|
||||
DESCRIPTION_SPLITTING_PATTERN = /\.(?>\s|$)/.freeze
|
||||
|
||||
def valid_internal_cmd?(cmd)
|
||||
require?(HOMEBREW_CMD_PATH/cmd)
|
||||
@ -203,7 +208,7 @@ module Commands
|
||||
|
||||
if (cmd_parser = Homebrew::CLI::Parser.from_cmd_path(path))
|
||||
if short
|
||||
cmd_parser.description.split(".").first
|
||||
cmd_parser.description.split(DESCRIPTION_SPLITTING_PATTERN).first
|
||||
else
|
||||
cmd_parser.description
|
||||
end
|
||||
@ -215,7 +220,7 @@ module Commands
|
||||
match_data = /^#: (?<desc>\w.*+)$/.match(line)
|
||||
if match_data
|
||||
desc = match_data[:desc]
|
||||
return T.must(desc).split(".").first if short
|
||||
return T.must(desc).split(DESCRIPTION_SPLITTING_PATTERN).first if short
|
||||
|
||||
return desc
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "mutex_m"
|
||||
@ -47,7 +47,7 @@ module Debrew
|
||||
menu = new
|
||||
yield menu
|
||||
|
||||
choice = nil
|
||||
choice = T.let(nil, T.nilable(Entry))
|
||||
while choice.nil?
|
||||
menu.entries.each_with_index { |e, i| puts "#{i + 1}. #{e.name}" }
|
||||
print menu.prompt unless menu.prompt.nil?
|
||||
@ -90,7 +90,7 @@ module Debrew
|
||||
yield
|
||||
rescue SystemExit
|
||||
raise
|
||||
rescue Exception => e # rubocop:disable Lint/RescueException
|
||||
rescue Ignorable::ExceptionMixin => e
|
||||
e.ignore if debug(e) == :ignore # execution jumps back to where the exception was thrown
|
||||
ensure
|
||||
Ignorable.unhook_raise
|
||||
@ -99,7 +99,7 @@ module Debrew
|
||||
end
|
||||
|
||||
def self.debug(exception)
|
||||
raise(exception) if !active? || !debugged_exceptions.add?(exception) || !try_lock
|
||||
raise(exception) if !active? || !debugged_exceptions.add?(exception) || !mu_try_lock
|
||||
|
||||
begin
|
||||
puts exception.backtrace.first.to_s
|
||||
@ -119,7 +119,7 @@ module Debrew
|
||||
set_trace_func proc { |event, _, _, id, binding, klass|
|
||||
if klass == Object && id == :raise && event == "return"
|
||||
set_trace_func(nil)
|
||||
synchronize { IRB.start_within(binding) }
|
||||
mu_synchronize { IRB.start_within(binding) }
|
||||
end
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ module Debrew
|
||||
end
|
||||
end
|
||||
ensure
|
||||
unlock
|
||||
mu_unlock
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "delegate"
|
||||
@ -16,19 +16,19 @@ class Dependencies < SimpleDelegator
|
||||
alias eql? ==
|
||||
|
||||
def optional
|
||||
select(&:optional?)
|
||||
__getobj__.select(&:optional?)
|
||||
end
|
||||
|
||||
def recommended
|
||||
select(&:recommended?)
|
||||
__getobj__.select(&:recommended?)
|
||||
end
|
||||
|
||||
def build
|
||||
select(&:build?)
|
||||
__getobj__.select(&:build?)
|
||||
end
|
||||
|
||||
def required
|
||||
select(&:required?)
|
||||
__getobj__.select(&:required?)
|
||||
end
|
||||
|
||||
def default
|
||||
@ -37,7 +37,7 @@ class Dependencies < SimpleDelegator
|
||||
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: #{to_a}>"
|
||||
"#<#{self.class.name}: #{__getobj__}>"
|
||||
end
|
||||
end
|
||||
|
||||
@ -52,11 +52,11 @@ class Requirements < SimpleDelegator
|
||||
end
|
||||
|
||||
def <<(other)
|
||||
if other.is_a?(Comparable)
|
||||
grep(other.class) do |req|
|
||||
if other.is_a?(Object) && other.is_a?(Comparable)
|
||||
__getobj__.grep(other.class) do |req|
|
||||
return self if req > other
|
||||
|
||||
delete(req)
|
||||
__getobj__.delete(req)
|
||||
end
|
||||
end
|
||||
super
|
||||
@ -65,6 +65,6 @@ class Requirements < SimpleDelegator
|
||||
|
||||
sig { returns(String) }
|
||||
def inspect
|
||||
"#<#{self.class.name}: {#{to_a.join(", ")}}>"
|
||||
"#<#{self.class.name}: {#{__getobj__.to_a.join(", ")}}>"
|
||||
end
|
||||
end
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
class Dependencies < SimpleDelegator
|
||||
include Kernel
|
||||
# This is a workaround to enable `alias eql? ==`
|
||||
# @see https://github.com/sorbet/sorbet/issues/2378#issuecomment-569474238
|
||||
sig { params(arg0: BasicObject).returns(T::Boolean) }
|
||||
def ==(arg0); end
|
||||
end
|
||||
|
||||
class Requirements < SimpleDelegator
|
||||
|
@ -24,14 +24,9 @@ module Homebrew
|
||||
def install_bundler_gems
|
||||
args = install_bundler_gems_args.parse
|
||||
|
||||
groups = args.groups
|
||||
|
||||
# Clear previous settings. We want to fully replace - not append.
|
||||
Homebrew::Settings.delete(:gemgroups) if groups
|
||||
Homebrew::Settings.delete(:gemgroups) if args.groups
|
||||
|
||||
groups ||= []
|
||||
groups |= VALID_GEM_GROUPS if groups.delete("all")
|
||||
|
||||
Homebrew.install_bundler_gems!(groups: groups)
|
||||
Homebrew.install_bundler_gems!(groups: args.groups || [])
|
||||
end
|
||||
end
|
||||
|
@ -95,7 +95,7 @@ module Homebrew
|
||||
.reject { |line| line.start_with?("#") || line.blank? }
|
||||
.map(&:strip)
|
||||
|
||||
named_args = T.unsafe(CLI::NamedArgs).new(*names, parent: args)
|
||||
named_args = CLI::NamedArgs.new(*names, parent: args)
|
||||
named_args.to_formulae_and_casks(ignore_unavailable: true)
|
||||
rescue Errno::ENOENT => e
|
||||
onoe e
|
||||
|
@ -24,8 +24,6 @@ module Homebrew
|
||||
def prof
|
||||
args = prof_args.parse
|
||||
|
||||
Homebrew.install_bundler_gems!(groups: ["prof"])
|
||||
|
||||
brew_rb = (HOMEBREW_LIBRARY_PATH/"brew.rb").resolved_path
|
||||
FileUtils.mkdir_p "prof"
|
||||
cmd = args.named.first
|
||||
@ -43,12 +41,16 @@ module Homebrew
|
||||
end
|
||||
|
||||
if args.stackprof?
|
||||
# Already installed from Gemfile but use this to setup PATH and LOADPATH
|
||||
Homebrew.install_gem_setup_path! "stackprof"
|
||||
with_env HOMEBREW_STACKPROF: "1" do
|
||||
system(*HOMEBREW_RUBY_EXEC_ARGS, brew_rb, *args.named)
|
||||
end
|
||||
output_filename = "prof/d3-flamegraph.html"
|
||||
safe_system "stackprof --d3-flamegraph prof/stackprof.dump > #{output_filename}"
|
||||
else
|
||||
# Already installed from Gemfile but use this to setup PATH and LOADPATH
|
||||
Homebrew.install_gem_setup_path! "ruby-prof"
|
||||
output_filename = "prof/call_stack.html"
|
||||
safe_system "ruby-prof", "--printer=call_stack", "--file=#{output_filename}", brew_rb, "--", *args.named
|
||||
end
|
||||
|
@ -81,7 +81,7 @@ module Homebrew
|
||||
|
||||
- name: Cache Homebrew Bundler RubyGems
|
||||
id: cache
|
||||
uses: actions/cache@v1
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.set-up-homebrew.outputs.gems-path }}
|
||||
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
|
||||
|
@ -88,7 +88,7 @@ module Homebrew
|
||||
def tests
|
||||
args = tests_args.parse
|
||||
|
||||
Homebrew.install_bundler_gems!(groups: ["prof"])
|
||||
Homebrew.install_bundler_gems!
|
||||
|
||||
require "byebug" if args.byebug?
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
@ -6,10 +6,8 @@ require "cli/parser"
|
||||
module Homebrew
|
||||
extend T::Sig
|
||||
|
||||
module_function
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def typecheck_args
|
||||
def self.typecheck_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Check for typechecking errors using Sorbet.
|
||||
@ -44,7 +42,7 @@ module Homebrew
|
||||
end
|
||||
|
||||
sig { void }
|
||||
def typecheck
|
||||
def self.typecheck
|
||||
args = typecheck_args.parse
|
||||
|
||||
Homebrew.install_bundler_gems!(groups: ["sorbet"])
|
||||
@ -95,9 +93,10 @@ module Homebrew
|
||||
|
||||
srb_exec += ["--ignore", args.ignore] if args.ignore.present?
|
||||
if args.file.present? || args.dir.present?
|
||||
cd("sorbet")
|
||||
srb_exec += ["--file", "../#{args.file}"] if args.file
|
||||
srb_exec += ["--dir", "../#{args.dir}"] if args.dir
|
||||
cd("sorbet") do
|
||||
srb_exec += ["--file", "../#{args.file}"] if args.file
|
||||
srb_exec += ["--dir", "../#{args.dir}"] if args.dir
|
||||
end
|
||||
end
|
||||
success = system(*srb_exec)
|
||||
return if success
|
||||
|
@ -202,7 +202,7 @@ module Homebrew
|
||||
when MacOSRequirement
|
||||
next true unless r.version_specified?
|
||||
|
||||
macos_version.public_send(r.comparator, r.version)
|
||||
macos_version.compare(r.comparator, r.version)
|
||||
when XcodeRequirement
|
||||
next true unless r.version
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "stringio"
|
||||
@ -8,10 +8,8 @@ require "cli/parser"
|
||||
module Homebrew
|
||||
extend T::Sig
|
||||
|
||||
module_function
|
||||
|
||||
sig { returns(CLI::Parser) }
|
||||
def unpack_args
|
||||
def self.unpack_args
|
||||
Homebrew::CLI::Parser.new do
|
||||
description <<~EOS
|
||||
Unpack the source files for <formula> into subdirectories of the current
|
||||
@ -33,7 +31,7 @@ module Homebrew
|
||||
end
|
||||
end
|
||||
|
||||
def unpack
|
||||
def self.unpack
|
||||
args = unpack_args.parse
|
||||
|
||||
formulae = args.named.to_formulae
|
||||
@ -69,10 +67,11 @@ module Homebrew
|
||||
next unless args.git?
|
||||
|
||||
ohai "Setting up Git repository"
|
||||
cd stage_dir
|
||||
system "git", "init", "-q"
|
||||
system "git", "add", "-A"
|
||||
system "git", "commit", "-q", "-m", "brew-unpack"
|
||||
cd(stage_dir) do
|
||||
system "git", "init", "-q"
|
||||
system "git", "add", "-A"
|
||||
system "git", "commit", "-q", "-m", "brew-unpack"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
@ -40,7 +40,8 @@ module Homebrew
|
||||
|
||||
named_sponsors = []
|
||||
logo_sponsors = []
|
||||
largest_monthly_amount = 0
|
||||
# FIXME: This T.let should be unnecessary https://github.com/sorbet/sorbet/issues/6894
|
||||
largest_monthly_amount = T.let(0, T.untyped)
|
||||
|
||||
GitHub.sponsorships("Homebrew").each do |s|
|
||||
largest_monthly_amount = [s[:monthly_amount], s[:closest_tier_monthly_amount]].max
|
||||
|
@ -54,7 +54,7 @@ module Homebrew
|
||||
start_commit = T.let("", T.untyped)
|
||||
end_commit = "HEAD"
|
||||
cd HOMEBREW_REPOSITORY do
|
||||
start_commit = if (commit = T.let(args.commit, T.nilable(String)))
|
||||
start_commit = if (commit = args.commit)
|
||||
commit
|
||||
elsif (date = args.before)
|
||||
Utils.popen_read("git", "rev-list", "-n1", "--before=#{date}", "origin/master").chomp
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "cli/parser"
|
||||
@ -30,7 +30,7 @@ module Homebrew
|
||||
|
||||
Homebrew.install_bundler!
|
||||
|
||||
ENV["BUNDLE_WITH"] = VALID_GEM_GROUPS.join(":")
|
||||
ENV["BUNDLE_WITH"] = "sorbet"
|
||||
|
||||
# System Ruby does not pick up the correct SDK by default.
|
||||
ENV["SDKROOT"] = MacOS.sdk_path if ENV["HOMEBREW_MACOS_SYSTEM_RUBY_NEW_ENOUGH"]
|
||||
|
6
Library/Homebrew/extend/object.rbi
Normal file
6
Library/Homebrew/extend/object.rbi
Normal file
@ -0,0 +1,6 @@
|
||||
# typed: strict
|
||||
|
||||
class Object
|
||||
sig { returns(T::Boolean) }
|
||||
def present?; end
|
||||
end
|
@ -1,18 +1,16 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Homebrew
|
||||
extend T::Sig
|
||||
|
||||
module_function
|
||||
|
||||
class << self
|
||||
alias generic_git_tags git_tags
|
||||
end
|
||||
|
||||
def git_tags
|
||||
tags = generic_git_tags
|
||||
tags = Utils.popen_read("git tag --list | sort -rV") if tags.blank?
|
||||
tags
|
||||
def git_tags
|
||||
tags = generic_git_tags
|
||||
tags = Utils.popen_read("git tag --list | sort -rV") if tags.blank?
|
||||
tags
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "tempfile"
|
||||
@ -46,7 +46,7 @@ module Homebrew
|
||||
f.write "#!/bin/sh\n"
|
||||
f.chmod 0700
|
||||
f.close
|
||||
return if system f.path
|
||||
return if system T.must(f.path)
|
||||
|
||||
<<~EOS
|
||||
The directory #{HOMEBREW_TEMP} does not permit executing
|
||||
@ -56,12 +56,12 @@ module Homebrew
|
||||
echo 'export HOMEBREW_TEMP=~/tmp' >> #{shell_profile}
|
||||
EOS
|
||||
ensure
|
||||
f.unlink
|
||||
f&.unlink
|
||||
end
|
||||
|
||||
def check_xdg_data_dirs
|
||||
return if ENV["XDG_DATA_DIRS"].blank?
|
||||
return if ENV["XDG_DATA_DIRS"].split("/").include?(HOMEBREW_PREFIX/"share")
|
||||
xdg_data_dirs = ENV.fetch("XDG_DATA_DIRS", nil)
|
||||
return if xdg_data_dirs.blank? || xdg_data_dirs.split("/").include?(HOMEBREW_PREFIX/"share")
|
||||
|
||||
<<~EOS
|
||||
Homebrew's share was not found in your XDG_DATA_DIRS but you have
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Hardware
|
||||
@ -111,7 +111,10 @@ module Hardware
|
||||
end
|
||||
|
||||
%w[aes altivec avx avx2 lm ssse3 sse4_2].each do |flag|
|
||||
define_method("#{flag}?") { flags.include? flag }
|
||||
define_method("#{flag}?") do
|
||||
T.bind(self, T.class_of(Hardware::CPU))
|
||||
flags.include? flag
|
||||
end
|
||||
end
|
||||
|
||||
def sse3?
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Homebrew
|
||||
@ -379,7 +379,7 @@ module Homebrew
|
||||
real_tmp = tmp.realpath.parent
|
||||
where_tmp = volumes.which real_tmp
|
||||
ensure
|
||||
Dir.delete tmp
|
||||
Dir.delete tmp.to_s
|
||||
end
|
||||
rescue
|
||||
return
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "macho"
|
||||
@ -114,7 +114,7 @@ module Hardware
|
||||
end
|
||||
end
|
||||
|
||||
def intel_family
|
||||
def intel_family(_family = nil, _cpu_model = nil)
|
||||
case sysctl_int("hw.cpufamily")
|
||||
when 0x73d67300 # Yonah: Core Solo/Duo
|
||||
:core
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Keg
|
||||
@ -108,7 +108,7 @@ class Keg
|
||||
# Needed to make symlink permissions consistent on macOS and Linux for
|
||||
# reproducible bottles.
|
||||
def consistent_reproducible_symlink_permissions!
|
||||
find do |file|
|
||||
path.find do |file|
|
||||
File.lchmod 0777, file if file.symlink?
|
||||
end
|
||||
end
|
||||
|
@ -19,7 +19,7 @@ module Readall
|
||||
# Fine to have missing URLs for unsupported macOS
|
||||
macos_req = cask.depends_on.macos
|
||||
next if macos_req&.version && Array(macos_req.version).none? do |macos_version|
|
||||
current_macos_version.public_send(macos_req.comparator, macos_version)
|
||||
current_macos_version.compare(macos_req.comparator, macos_version)
|
||||
end
|
||||
|
||||
raise "Missing URL" if cask.url.nil?
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Predicable
|
||||
|
5
Library/Homebrew/extend/predicable.rbi
Normal file
5
Library/Homebrew/extend/predicable.rbi
Normal file
@ -0,0 +1,5 @@
|
||||
# typed: strict
|
||||
|
||||
module Predicable
|
||||
requires_ancestor { Class }
|
||||
end
|
@ -1,16 +1,17 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module TimeRemaining
|
||||
refine Time do
|
||||
def remaining
|
||||
T.bind(self, Time)
|
||||
[0, self - Time.now].max
|
||||
end
|
||||
|
||||
def remaining!
|
||||
r = remaining
|
||||
|
||||
raise Timeout::Error if r <= 0
|
||||
Kernel.raise Timeout::Error if r <= 0
|
||||
|
||||
r
|
||||
end
|
||||
|
@ -1152,7 +1152,7 @@ class Formula
|
||||
ENV.activate_extensions!
|
||||
|
||||
etc_var_dirs = [bottle_prefix/"etc", bottle_prefix/"var"]
|
||||
T.unsafe(Find).find(*etc_var_dirs.select(&:directory?)) do |path|
|
||||
Find.find(*etc_var_dirs.select(&:directory?)) do |path|
|
||||
path = Pathname.new(path)
|
||||
path.extend(InstallRenamed)
|
||||
path.cp_path_sub(bottle_prefix, HOMEBREW_PREFIX)
|
||||
@ -2672,7 +2672,7 @@ class Formula
|
||||
out.close
|
||||
args.map!(&:to_s)
|
||||
begin
|
||||
T.unsafe(Kernel).exec(cmd, *args)
|
||||
Kernel.exec(cmd, *args)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "warnings"
|
||||
@ -30,7 +30,7 @@ module Ignorable
|
||||
rescue Exception => e # rubocop:disable Lint/RescueException
|
||||
unless e.is_a?(ScriptError)
|
||||
e.extend(ExceptionMixin)
|
||||
e.continuation = continuation
|
||||
T.cast(e, ExceptionMixin).continuation = continuation
|
||||
end
|
||||
super(e)
|
||||
end
|
||||
@ -47,7 +47,6 @@ module Ignorable
|
||||
|
||||
def self.unhook_raise
|
||||
Object.class_eval do
|
||||
# False positive - https://github.com/rubocop/rubocop/issues/5022
|
||||
alias_method :raise, :original_raise
|
||||
alias_method :fail, :original_raise
|
||||
undef :original_raise
|
||||
|
8
Library/Homebrew/ignorable.rbi
Normal file
8
Library/Homebrew/ignorable.rbi
Normal file
@ -0,0 +1,8 @@
|
||||
# typed: strict
|
||||
|
||||
module Ignorable
|
||||
include Kernel
|
||||
# This is a workaround to enable `raise` to be aliased
|
||||
# @see https://github.com/sorbet/sorbet/issues/2378#issuecomment-569474238
|
||||
def self.raise(*); end
|
||||
end
|
@ -174,15 +174,15 @@ module Homebrew
|
||||
The currently linked version is: #{formula.linked_version}
|
||||
EOS
|
||||
end
|
||||
elsif only_dependencies
|
||||
msg = nil
|
||||
return true
|
||||
elsif !formula.linked? || formula.keg_only?
|
||||
msg = <<~EOS
|
||||
#{msg}, it's just not linked.
|
||||
To link this version, run:
|
||||
brew link #{formula}
|
||||
EOS
|
||||
elsif only_dependencies
|
||||
msg = nil
|
||||
return true
|
||||
else
|
||||
msg = if quiet
|
||||
nil
|
||||
|
@ -264,14 +264,14 @@ module Language
|
||||
# Multiline strings are allowed and treated as though they represent
|
||||
# the contents of a `requirements.txt`.
|
||||
# @return [void]
|
||||
def pip_install(targets)
|
||||
def pip_install(targets, build_isolation: true)
|
||||
targets = Array(targets)
|
||||
targets.each do |t|
|
||||
if t.respond_to? :stage
|
||||
t.stage { do_install Pathname.pwd }
|
||||
t.stage { do_install(Pathname.pwd, build_isolation: build_isolation) }
|
||||
else
|
||||
t = t.lines.map(&:strip) if t.respond_to?(:lines) && t.include?("\n")
|
||||
do_install t
|
||||
do_install(t, build_isolation: build_isolation)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -281,11 +281,11 @@ module Language
|
||||
#
|
||||
# @param (see #pip_install)
|
||||
# @return (see #pip_install)
|
||||
def pip_install_and_link(targets, link_manpages: false)
|
||||
def pip_install_and_link(targets, link_manpages: false, build_isolation: true)
|
||||
bin_before = Dir[@venv_root/"bin/*"].to_set
|
||||
man_before = Dir[@venv_root/"share/man/man*/*"].to_set if link_manpages
|
||||
|
||||
pip_install(targets)
|
||||
pip_install(targets, build_isolation: build_isolation)
|
||||
|
||||
bin_after = Dir[@venv_root/"bin/*"].to_set
|
||||
bin_to_link = (bin_after - bin_before).to_a
|
||||
@ -301,12 +301,15 @@ module Language
|
||||
|
||||
private
|
||||
|
||||
def do_install(targets)
|
||||
def do_install(targets, build_isolation: true)
|
||||
targets = Array(targets)
|
||||
@formula.system @venv_root/"bin/pip", "install",
|
||||
"-v", "--no-deps", "--no-binary", ":all:",
|
||||
"--use-feature=no-binary-enable-wheel-cache",
|
||||
"--ignore-installed", *targets
|
||||
args = [
|
||||
"-v", "--no-deps", "--no-binary", ":all:",
|
||||
"--use-feature=no-binary-enable-wheel-cache",
|
||||
"--ignore-installed"
|
||||
]
|
||||
args << "--no-build-isolation" unless build_isolation
|
||||
@formula.system @venv_root/"bin/pip", "install", *args, *targets
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Homebrew
|
||||
@ -161,7 +161,7 @@ module Homebrew
|
||||
# specifies the strategy and contains a `strategy` block
|
||||
next if (livecheck_strategy != strategy_symbol) || !block_provided
|
||||
elsif strategy.const_defined?(:PRIORITY) &&
|
||||
!strategy::PRIORITY.positive? &&
|
||||
!strategy.const_get(:PRIORITY).positive? &&
|
||||
livecheck_strategy != strategy_symbol
|
||||
# Ignore strategies with a priority of 0 or lower, unless the
|
||||
# strategy is specified in the `livecheck` block
|
||||
@ -174,7 +174,7 @@ module Homebrew
|
||||
# Sort usable strategies in descending order by priority, using the
|
||||
# DEFAULT_PRIORITY when a strategy doesn't contain a PRIORITY constant
|
||||
usable_strategies.sort_by do |strategy|
|
||||
(strategy.const_defined?(:PRIORITY) ? -strategy::PRIORITY : -DEFAULT_PRIORITY)
|
||||
(strategy.const_defined?(:PRIORITY) ? -strategy.const_get(:PRIORITY) : -DEFAULT_PRIORITY)
|
||||
end
|
||||
end
|
||||
|
||||
@ -216,7 +216,7 @@ module Homebrew
|
||||
# @return [Hash]
|
||||
sig { params(url: String, homebrew_curl: T::Boolean).returns(T::Hash[Symbol, T.untyped]) }
|
||||
def self.page_content(url, homebrew_curl: false)
|
||||
stderr = nil
|
||||
stderr = T.let(nil, T.nilable(String))
|
||||
[:default, :browser].each do |user_agent|
|
||||
stdout, stderr, status = curl_with_workarounds(
|
||||
*PAGE_CONTENT_CURL_ARGS, url,
|
||||
|
@ -93,13 +93,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -96,13 +96,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -80,13 +80,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -45,7 +45,7 @@ module Homebrew
|
||||
regex: T.nilable(Regexp),
|
||||
provided_content: T.nilable(String),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, provided_content: nil, **unused, &block)
|
||||
@ -54,7 +54,7 @@ module Homebrew
|
||||
"#{Utils.demodulize(T.must(name))} only supports a regex when using a `strategy` block"
|
||||
end
|
||||
|
||||
T.unsafe(Yaml).find_versions(
|
||||
Yaml.find_versions(
|
||||
url: url,
|
||||
regex: regex,
|
||||
provided_content: provided_content,
|
||||
|
@ -64,7 +64,7 @@ module Homebrew
|
||||
params(
|
||||
items: T::Hash[String, Item],
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_items(items, regex = nil, &block)
|
||||
@ -92,7 +92,7 @@ module Homebrew
|
||||
url: T.nilable(String),
|
||||
regex: T.nilable(Regexp),
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(cask:, url: nil, regex: nil, **_unused, &block)
|
||||
|
@ -85,7 +85,7 @@ module Homebrew
|
||||
params(
|
||||
tags: T::Array[String],
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_tags(tags, regex = nil, &block)
|
||||
@ -125,7 +125,7 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **_unused, &block)
|
||||
|
@ -92,13 +92,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -82,13 +82,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
version_data = T.unsafe(PageMatch).find_versions(
|
||||
version_data = PageMatch.find_versions(
|
||||
url: generated[:url],
|
||||
regex: regex || generated[:regex],
|
||||
**unused,
|
||||
|
@ -92,13 +92,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -78,13 +78,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -44,7 +44,7 @@ module Homebrew
|
||||
params(
|
||||
headers: T::Hash[String, String],
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_headers(headers, regex = nil, &block)
|
||||
@ -79,7 +79,7 @@ module Homebrew
|
||||
regex: T.nilable(Regexp),
|
||||
homebrew_curl: T::Boolean,
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, homebrew_curl: false, **_unused, &block)
|
||||
|
@ -70,7 +70,7 @@ module Homebrew
|
||||
params(
|
||||
content: String,
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_content(content, regex = nil, &block)
|
||||
@ -105,7 +105,7 @@ module Homebrew
|
||||
provided_content: T.nilable(String),
|
||||
homebrew_curl: T::Boolean,
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)
|
||||
|
@ -75,13 +75,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || DEFAULT_REGEX, **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -73,13 +73,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -51,7 +51,7 @@ module Homebrew
|
||||
params(
|
||||
content: String,
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_content(content, regex, &block)
|
||||
@ -88,7 +88,7 @@ module Homebrew
|
||||
provided_content: T.nilable(String),
|
||||
homebrew_curl: T::Boolean,
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)
|
||||
|
@ -87,13 +87,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
PageMatch.find_versions(url: generated[:url], regex: regex || generated[:regex], **unused, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -92,13 +92,13 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
generated = generate_input_values(url)
|
||||
|
||||
T.unsafe(PageMatch).find_versions(
|
||||
PageMatch.find_versions(
|
||||
url: generated[:url] || url,
|
||||
regex: regex || generated[:regex],
|
||||
**unused,
|
||||
|
@ -146,7 +146,7 @@ module Homebrew
|
||||
params(
|
||||
content: String,
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_content(content, regex = nil, &block)
|
||||
@ -181,7 +181,7 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **_unused, &block)
|
||||
|
@ -87,7 +87,7 @@ module Homebrew
|
||||
params(
|
||||
content: String,
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_content(content, regex = nil, &block)
|
||||
@ -123,7 +123,7 @@ module Homebrew
|
||||
provided_content: T.nilable(String),
|
||||
homebrew_curl: T::Boolean,
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)
|
||||
|
@ -114,7 +114,7 @@ module Homebrew
|
||||
url: String,
|
||||
regex: T.nilable(Regexp),
|
||||
unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, **unused, &block)
|
||||
@ -123,7 +123,7 @@ module Homebrew
|
||||
|
||||
# Use the cached page content to avoid duplicate fetches
|
||||
cached_content = @page_data[generated_url]
|
||||
match_data = T.unsafe(PageMatch).find_versions(
|
||||
match_data = PageMatch.find_versions(
|
||||
url: generated_url,
|
||||
regex: regex || generated[:regex],
|
||||
provided_content: cached_content,
|
||||
|
@ -70,7 +70,7 @@ module Homebrew
|
||||
params(
|
||||
content: String,
|
||||
regex: T.nilable(Regexp),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Array[String])
|
||||
}
|
||||
def self.versions_from_content(content, regex = nil, &block)
|
||||
@ -105,7 +105,7 @@ module Homebrew
|
||||
provided_content: T.nilable(String),
|
||||
homebrew_curl: T::Boolean,
|
||||
_unused: T.nilable(T::Hash[Symbol, T.untyped]),
|
||||
block: T.untyped,
|
||||
block: T.nilable(Proc),
|
||||
).returns(T::Hash[Symbol, T.untyped])
|
||||
}
|
||||
def self.find_versions(url:, regex: nil, provided_content: nil, homebrew_curl: false, **_unused, &block)
|
||||
|
@ -56,7 +56,7 @@ class MacOSRequirement < Requirement
|
||||
|
||||
satisfy(build_env: false) do
|
||||
T.bind(self, MacOSRequirement)
|
||||
next Array(@version).any? { |v| OS::Mac.version.public_send(@comparator, v) } if OS.mac? && version_specified?
|
||||
next Array(@version).any? { |v| OS::Mac.version.compare(@comparator, v) } if OS.mac? && version_specified?
|
||||
next true if OS.mac?
|
||||
next true if @version
|
||||
|
||||
|
@ -24,6 +24,7 @@ require_relative "lines"
|
||||
require_relative "livecheck"
|
||||
require_relative "options"
|
||||
require_relative "patches"
|
||||
require_relative "service"
|
||||
require_relative "text"
|
||||
require_relative "urls"
|
||||
require_relative "uses_from_macos"
|
||||
|
@ -8,13 +8,13 @@ module RuboCop
|
||||
#
|
||||
# @example
|
||||
# # bad
|
||||
# url "https://example.com/foo.dmg",
|
||||
# verified: "https://example.com"
|
||||
# url "https://example.com/download/foo.dmg",
|
||||
# verified: "https://example.com/download"
|
||||
#
|
||||
#
|
||||
# # good
|
||||
# url "https://example.com/foo.dmg",
|
||||
# verified: "example.com"
|
||||
# url "https://example.com/download/foo.dmg",
|
||||
# verified: "example.com/download/"
|
||||
#
|
||||
class Url < Base
|
||||
extend AutoCorrector
|
||||
@ -24,19 +24,35 @@ module RuboCop
|
||||
def on_url_stanza(stanza)
|
||||
return if stanza.stanza_node.block_type?
|
||||
|
||||
url_stanza = stanza.stanza_node.first_argument
|
||||
hash_node = stanza.stanza_node.last_argument
|
||||
return unless hash_node.hash_type?
|
||||
|
||||
hash_node.each_pair do |key_node, value_node|
|
||||
next unless key_node.source == "verified"
|
||||
next unless value_node.str_type?
|
||||
next unless value_node.source.start_with?(%r{^"https?://})
|
||||
|
||||
if value_node.source.start_with?(%r{^"https?://})
|
||||
add_offense(
|
||||
value_node.source_range,
|
||||
message: "Verified URL parameter value should not contain a URL scheme.",
|
||||
) do |corrector|
|
||||
corrector.replace(value_node.source_range, value_node.source.gsub(%r{^"https?://}, "\""))
|
||||
end
|
||||
end
|
||||
|
||||
# Skip if the URL and the verified value are the same.
|
||||
next if value_node.source == url_stanza.source.gsub(%r{^"https?://}, "\"")
|
||||
# Skip if the URL has two path components, eg: `https://github.com/google/fonts.git`.
|
||||
next if url_stanza.source.gsub(%r{^"https?://}, "\"").count("/") == 2
|
||||
# Skip if the verified value ends with a slash.
|
||||
next if value_node.str_content.end_with?("/")
|
||||
|
||||
add_offense(
|
||||
value_node.source_range,
|
||||
message: "Verified URL parameter value should not start with https:// or http://.",
|
||||
message: "Verified URL parameter value should end with a /.",
|
||||
) do |corrector|
|
||||
corrector.replace(value_node.source_range, value_node.source.gsub(%r{^"https?://}, "\""))
|
||||
corrector.replace(value_node.source_range, value_node.source.gsub(/"$/, "/\""))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
31
Library/Homebrew/rubocops/service.rb
Normal file
31
Library/Homebrew/rubocops/service.rb
Normal file
@ -0,0 +1,31 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rubocops/extend/formula_cop"
|
||||
|
||||
module RuboCop
|
||||
module Cop
|
||||
module FormulaAudit
|
||||
# This cop audits the service block.
|
||||
#
|
||||
# @api private
|
||||
class Service < FormulaCop
|
||||
extend AutoCorrector
|
||||
|
||||
def audit_formula(_node, _class_node, _parent_class_node, body_node)
|
||||
service_node = find_block(body_node, :service)
|
||||
return if service_node.blank?
|
||||
|
||||
# This check ensures that `bin` is not referenced because
|
||||
# `opt_bin` is more portable and works with the API.
|
||||
find_every_method_call_by_name(service_node, :bin).each do |bin_node|
|
||||
offending_node(bin_node)
|
||||
problem "Use `opt_bin` instead of `bin` in service blocks." do |corrector|
|
||||
corrector.replace(bin_node.source_range, "opt_bin")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -101,7 +101,7 @@ class Sandbox
|
||||
begin
|
||||
command = [SANDBOX_EXEC, "-f", seatbelt.path, *args]
|
||||
# Start sandbox in a pseudoterminal to prevent access of the parent terminal.
|
||||
T.unsafe(PTY).spawn(*command) do |r, w, pid|
|
||||
PTY.spawn(*command) do |r, w, pid|
|
||||
# Set the PTY's window size to match the parent terminal.
|
||||
# Some formula tests are sensitive to the terminal size and fail if this is not set.
|
||||
winch = proc do |_sig|
|
||||
|
@ -46,8 +46,11 @@ module Homebrew
|
||||
}
|
||||
def run(command = nil, macos: nil, linux: nil)
|
||||
# Save parameters for serialization
|
||||
@run_params ||= command
|
||||
@run_params ||= { macos: macos, linux: linux }.compact
|
||||
if command
|
||||
@run_params = command
|
||||
elsif macos || linux
|
||||
@run_params = { macos: macos, linux: linux }.compact
|
||||
end
|
||||
|
||||
command ||= on_system_conditional(macos: macos, linux: linux)
|
||||
case T.unsafe(command)
|
||||
@ -551,15 +554,22 @@ module Homebrew
|
||||
hash = {}
|
||||
hash[:run] =
|
||||
case api_hash["run"]
|
||||
when Hash
|
||||
api_hash["run"].to_h do |key, array|
|
||||
[
|
||||
key.to_sym,
|
||||
array.map(&method(:replace_placeholders)),
|
||||
]
|
||||
end
|
||||
when String
|
||||
replace_placeholders(api_hash["run"])
|
||||
when Array
|
||||
api_hash["run"].map(&method(:replace_placeholders))
|
||||
when Hash
|
||||
api_hash["run"].to_h do |key, elem|
|
||||
run_cmd = if elem.is_a?(Array)
|
||||
elem.map(&method(:replace_placeholders))
|
||||
else
|
||||
replace_placeholders(elem)
|
||||
end
|
||||
|
||||
[key.to_sym, run_cmd]
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Unexpected run command: #{api_hash["run"]}"
|
||||
end
|
||||
|
||||
hash[:keep_alive] = api_hash["keep_alive"].transform_keys(&:to_sym) if api_hash.key?("keep_alive")
|
||||
|
@ -10,13 +10,9 @@ module Addressable::IDNA
|
||||
class << self
|
||||
def to_ascii(input); end
|
||||
def to_unicode(input); end
|
||||
def unicode_normalize_kc(input); end
|
||||
|
||||
private
|
||||
|
||||
def lookup_unicode_combining_class(codepoint); end
|
||||
def lookup_unicode_compatibility(codepoint); end
|
||||
def lookup_unicode_composition(unpacked); end
|
||||
def lookup_unicode_lowercase(codepoint); end
|
||||
def punycode_adapt(delta, numpoints, firsttime); end
|
||||
def punycode_basic?(codepoint); end
|
||||
@ -25,28 +21,13 @@ module Addressable::IDNA
|
||||
def punycode_delimiter?(codepoint); end
|
||||
def punycode_encode(unicode); end
|
||||
def punycode_encode_digit(d); end
|
||||
def ucs4_to_utf8(char, buffer); end
|
||||
def unicode_compose(unpacked); end
|
||||
def unicode_compose_pair(ch_one, ch_two); end
|
||||
def unicode_decompose(unpacked); end
|
||||
def unicode_decompose_hangul(codepoint); end
|
||||
def unicode_downcase(input); end
|
||||
def unicode_sort_canonical(unpacked); end
|
||||
end
|
||||
end
|
||||
|
||||
Addressable::IDNA::ACE_MAX_LENGTH = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::ACE_PREFIX = T.let(T.unsafe(nil), String)
|
||||
Addressable::IDNA::COMPOSITION_TABLE = T.let(T.unsafe(nil), Hash)
|
||||
Addressable::IDNA::HANGUL_LBASE = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_LCOUNT = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_NCOUNT = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_SBASE = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_SCOUNT = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_TBASE = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_TCOUNT = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_VBASE = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::HANGUL_VCOUNT = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::PUNYCODE_BASE = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::PUNYCODE_DAMP = T.let(T.unsafe(nil), Integer)
|
||||
Addressable::IDNA::PUNYCODE_DELIMITER = T.let(T.unsafe(nil), Integer)
|
||||
@ -226,6 +207,10 @@ class Addressable::URI
|
||||
def split_path(path); end
|
||||
def validate; end
|
||||
|
||||
private
|
||||
|
||||
def reset_ivs; end
|
||||
|
||||
class << self
|
||||
def convert_path(path); end
|
||||
def encode(uri, return_type = T.unsafe(nil)); end
|
||||
@ -265,6 +250,7 @@ Addressable::URI::CharacterClasses::SUB_DELIMS = T.let(T.unsafe(nil), String)
|
||||
Addressable::URI::CharacterClasses::UNRESERVED = T.let(T.unsafe(nil), String)
|
||||
Addressable::URI::EMPTY_STR = T.let(T.unsafe(nil), String)
|
||||
class Addressable::URI::InvalidURIError < ::StandardError; end
|
||||
Addressable::URI::NONE = T.let(T.unsafe(nil), Object)
|
||||
Addressable::URI::NORMPATH = T.let(T.unsafe(nil), Regexp)
|
||||
module Addressable::URI::NormalizeCharacterClasses; end
|
||||
Addressable::URI::NormalizeCharacterClasses::FRAGMENT = T.let(T.unsafe(nil), Regexp)
|
@ -5018,8 +5018,6 @@ end
|
||||
class Net::HTTPAlreadyReported
|
||||
end
|
||||
|
||||
Net::HTTPClientError::EXCEPTION_TYPE = Net::HTTPServerException
|
||||
|
||||
Net::HTTPClientErrorCode = Net::HTTPClientError
|
||||
|
||||
class Net::HTTPEarlyHints
|
||||
@ -5031,9 +5029,13 @@ end
|
||||
|
||||
Net::HTTPFatalErrorCode = Net::HTTPClientError
|
||||
|
||||
Net::HTTPInformation::EXCEPTION_TYPE = Net::HTTPError
|
||||
class Net::HTTPInformation
|
||||
end
|
||||
|
||||
Net::HTTPInformationCode = Net::HTTPInformation
|
||||
Net::HTTPInformationCode::EXCEPTION_TYPE = Net::HTTPError
|
||||
|
||||
class Net::HTTPInformation
|
||||
end
|
||||
|
||||
class Net::HTTPLoopDetected
|
||||
HAS_BODY = ::T.let(nil, ::T.untyped)
|
||||
@ -5081,8 +5083,6 @@ end
|
||||
class Net::HTTPRangeNotSatisfiable
|
||||
end
|
||||
|
||||
Net::HTTPRedirection::EXCEPTION_TYPE = Net::HTTPRetriableError
|
||||
|
||||
Net::HTTPRedirectionCode = Net::HTTPRedirection
|
||||
|
||||
Net::HTTPRequestURITooLarge = Net::HTTPURITooLong
|
||||
@ -5091,15 +5091,17 @@ Net::HTTPResponceReceiver = Net::HTTPResponse
|
||||
|
||||
Net::HTTPRetriableCode = Net::HTTPRedirection
|
||||
|
||||
Net::HTTPServerError::EXCEPTION_TYPE = Net::HTTPFatalError
|
||||
|
||||
Net::HTTPServerErrorCode = Net::HTTPServerError
|
||||
|
||||
Net::HTTPSession = Net::HTTP
|
||||
|
||||
Net::HTTPSuccess::EXCEPTION_TYPE = Net::HTTPError
|
||||
class Net::HTTPSuccess
|
||||
end
|
||||
|
||||
Net::HTTPSuccessCode = Net::HTTPSuccess
|
||||
Net::HTTPSuccessCode::EXCEPTION_TYPE = Net::HTTPError
|
||||
|
||||
class Net::HTTPSuccess
|
||||
end
|
||||
|
||||
class Net::HTTPURITooLong
|
||||
HAS_BODY = ::T.let(nil, ::T.untyped)
|
||||
|
48
Library/Homebrew/sorbet/rbi/upstream.rbi
Normal file
48
Library/Homebrew/sorbet/rbi/upstream.rbi
Normal file
@ -0,0 +1,48 @@
|
||||
# typed: strict
|
||||
|
||||
# This file contains temporary definitions for fixes that have
|
||||
# been submitted upstream to https://github.com/sorbet/sorbet.
|
||||
|
||||
module FileUtils
|
||||
# @see https://github.com/sorbet/sorbet/pull/6847
|
||||
sig do
|
||||
params(
|
||||
src: T.any(String, Pathname),
|
||||
dest: T.any(String, Pathname),
|
||||
preserve: T.nilable(T::Boolean),
|
||||
noop: T.nilable(T::Boolean),
|
||||
verbose: T.nilable(T::Boolean),
|
||||
dereference_root: T::Boolean,
|
||||
remove_destination: T.nilable(T::Boolean)
|
||||
).returns(T::Array[String])
|
||||
end
|
||||
module_function def cp_r(src, dest, preserve: nil, noop: nil, verbose: nil, dereference_root: true, remove_destination: nil); end
|
||||
end
|
||||
|
||||
module Kernel
|
||||
# @see https://github.com/sorbet/sorbet/blob/a1e8389/rbi/core/kernel.rbi#L41-L46
|
||||
sig do
|
||||
type_parameters(:U).params(
|
||||
block: T.proc.params(cont: Continuation).returns(T.type_parameter(:U))
|
||||
).returns(T.type_parameter(:U))
|
||||
end
|
||||
def callcc(&block); end
|
||||
|
||||
# @see https://github.com/sorbet/sorbet/blob/a1e8389/rbi/core/kernel.rbi#L2348-L2363
|
||||
sig do
|
||||
params(
|
||||
arg0: T.nilable(
|
||||
T.proc.params(
|
||||
event: String,
|
||||
file: String,
|
||||
line: Integer,
|
||||
id: T.nilable(Symbol),
|
||||
binding: T.nilable(Binding),
|
||||
classname: Object,
|
||||
).returns(T.untyped)
|
||||
)
|
||||
).void
|
||||
end
|
||||
sig { params(arg0: NilClass).returns(NilClass) }
|
||||
def set_trace_func(arg0); end
|
||||
end
|
@ -199,8 +199,8 @@ class SystemCommand
|
||||
|
||||
pid = T.let(nil, T.nilable(Integer))
|
||||
raw_stdin, raw_stdout, raw_stderr, raw_wait_thr = ignore_interrupts do
|
||||
T.unsafe(Open3).popen3(env, [executable, executable], *args, **options)
|
||||
.tap { |*, wait_thr| pid = wait_thr.pid }
|
||||
Open3.popen3(env, [executable, executable], *args, **options)
|
||||
.tap { |*, wait_thr| pid = wait_thr.pid }
|
||||
end
|
||||
|
||||
write_input_to(raw_stdin)
|
||||
|
@ -870,7 +870,7 @@ class CoreTap < Tap
|
||||
|
||||
sig { returns(String) }
|
||||
def remote
|
||||
super if installed? || Homebrew::EnvConfig.no_install_from_api?
|
||||
super if Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
Homebrew::EnvConfig.core_git_remote
|
||||
end
|
||||
@ -988,7 +988,7 @@ class CoreTap < Tap
|
||||
# @private
|
||||
sig { returns(T::Array[String]) }
|
||||
def aliases
|
||||
return super if installed? || Homebrew::EnvConfig.no_install_from_api?
|
||||
return super if Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
Homebrew::API::Formula.all_aliases.keys
|
||||
end
|
||||
@ -996,7 +996,7 @@ class CoreTap < Tap
|
||||
# @private
|
||||
sig { returns(T::Array[String]) }
|
||||
def formula_names
|
||||
return super if installed? || Homebrew::EnvConfig.no_install_from_api?
|
||||
return super if Homebrew::EnvConfig.no_install_from_api?
|
||||
|
||||
Homebrew::API::Formula.all_formulae.keys
|
||||
end
|
||||
|
@ -20,10 +20,10 @@ describe Cask::DSL, :cask do
|
||||
end
|
||||
end
|
||||
|
||||
it "prints a warning that it has encountered an unexpected method" do
|
||||
it "prints an error that it has encountered an unexpected method" do
|
||||
expected = Regexp.compile(<<~EOS.lines.map(&:chomp).join)
|
||||
(?m)
|
||||
Warning:
|
||||
Error:
|
||||
.*
|
||||
Unexpected method 'future_feature' called on Cask unexpected-method-cask\\.
|
||||
.*
|
||||
|
@ -67,6 +67,14 @@ describe Language::Python::Virtualenv::Virtualenv, :needs_python do
|
||||
|
||||
virtualenv.pip_install res
|
||||
end
|
||||
|
||||
it "works without build isolation" do
|
||||
expect(formula).to receive(:system)
|
||||
.with(dir/"bin/pip", "install", "-v", "--no-deps", "--no-binary", ":all:",
|
||||
"--use-feature=no-binary-enable-wheel-cache", "--ignore-installed", "--no-build-isolation", "foo")
|
||||
.and_return(true)
|
||||
virtualenv.pip_install("foo", build_isolation: false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#pip_install_and_link" do
|
||||
@ -86,7 +94,7 @@ describe Language::Python::Virtualenv::Virtualenv, :needs_python do
|
||||
FileUtils.touch src_bin/"kilroy"
|
||||
bin_after = Dir.glob(src_bin/"*")
|
||||
|
||||
expect(virtualenv).to receive(:pip_install).with("foo")
|
||||
expect(virtualenv).to receive(:pip_install).with("foo", { build_isolation: true })
|
||||
expect(Dir).to receive(:[]).with(src_bin/"*").twice.and_return(bin_before, bin_after)
|
||||
|
||||
virtualenv.pip_install_and_link "foo"
|
||||
@ -115,7 +123,7 @@ describe Language::Python::Virtualenv::Virtualenv, :needs_python do
|
||||
FileUtils.touch src_man/"man5/kilroy.5"
|
||||
man_after = Dir.glob(src_man/"**/*")
|
||||
|
||||
expect(virtualenv).to receive(:pip_install).with("foo")
|
||||
expect(virtualenv).to receive(:pip_install).with("foo", { build_isolation: true })
|
||||
expect(Dir).to receive(:[]).with(src_bin/"*").and_return([])
|
||||
expect(Dir).to receive(:[]).with(src_man/"man*/*").and_return(man_before)
|
||||
expect(Dir).to receive(:[]).with(src_bin/"*").and_return([])
|
||||
|
@ -14,7 +14,7 @@ describe RuboCop::Cop::Cask::Url do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://example.com/download/foo-v1.2.0.dmg",
|
||||
verified: "example.com"
|
||||
verified: "example.com/download/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
@ -27,18 +27,18 @@ describe RuboCop::Cop::Cask::Url do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://example.com/download/foo-v1.2.0.dmg",
|
||||
verified: "https://example.com"
|
||||
verified: "https://example.com/download/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "Verified URL parameter value should not start with https:// or http://.",
|
||||
message: "Verified URL parameter value should not contain a URL scheme.",
|
||||
severity: :convention,
|
||||
line: 3,
|
||||
column: 14,
|
||||
source: "\"https://example.com\"",
|
||||
column: 16,
|
||||
source: "\"https://example.com/download/\"",
|
||||
}]
|
||||
end
|
||||
|
||||
@ -46,7 +46,189 @@ describe RuboCop::Cop::Cask::Url do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://example.com/download/foo-v1.2.0.dmg",
|
||||
verified: "example.com"
|
||||
verified: "example.com/download/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
include_examples "autocorrects source"
|
||||
end
|
||||
|
||||
context "when url 'verified' value does not have a path component" do
|
||||
context "when the URL ends with a slash" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://example.org/",
|
||||
verified: "example.org/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the URL does not end with a slash" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://example.org/",
|
||||
verified: "example.org"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "Verified URL parameter value should end with a /.",
|
||||
severity: :convention,
|
||||
line: 3,
|
||||
column: 16,
|
||||
source: "\"example.org\"",
|
||||
}]
|
||||
end
|
||||
|
||||
let(:correct_source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://example.org/",
|
||||
verified: "example.org/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
include_examples "autocorrects source"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the URL does not end with a slash" do
|
||||
describe "and it has one path component" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/Foo",
|
||||
verified: "github.com/Foo"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
describe "and it has two path components" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/foo/foo.git",
|
||||
verified: "github.com/foo/foo"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
end
|
||||
|
||||
context "when the url ends with a / and the verified value does too" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/",
|
||||
verified: "github.com/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url ends with a / and the verified value does not" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/",
|
||||
verified: "github.com"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "Verified URL parameter value should end with a /.",
|
||||
severity: :convention,
|
||||
line: 3,
|
||||
column: 16,
|
||||
source: "\"github.com\"",
|
||||
}]
|
||||
end
|
||||
|
||||
let(:correct_source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/",
|
||||
verified: "github.com/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "reports offenses"
|
||||
include_examples "autocorrects source"
|
||||
end
|
||||
|
||||
context "when url 'verified' value has a path component that ends with a /" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg",
|
||||
verified: "github.com/Foo/foo/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url has interpolation in it and the verified url ends with a /" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
version "1.2.3"
|
||||
url "https://example.com/download/foo-v\#{version}.dmg",
|
||||
verified: "example.com/download/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
include_examples "does not report any offenses"
|
||||
end
|
||||
|
||||
context "when the url 'verified' value has a path component that doesn't end with a /" do
|
||||
let(:source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg",
|
||||
verified: "github.com/Foo/foo"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
||||
let(:expected_offenses) do
|
||||
[{
|
||||
message: "Verified URL parameter value should end with a /.",
|
||||
severity: :convention,
|
||||
line: 3,
|
||||
column: 16,
|
||||
source: "\"github.com/Foo/foo\"",
|
||||
}]
|
||||
end
|
||||
|
||||
let(:correct_source) do
|
||||
<<~CASK
|
||||
cask "foo" do
|
||||
url "https://github.com/Foo/foo/releases/download/v1.2.0/foo-v1.2.0.dmg",
|
||||
verified: "github.com/Foo/foo/"
|
||||
end
|
||||
CASK
|
||||
end
|
||||
|
43
Library/Homebrew/test/rubocops/service_spec.rb
Normal file
43
Library/Homebrew/test/rubocops/service_spec.rb
Normal file
@ -0,0 +1,43 @@
|
||||
# typed: false
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "rubocops/service"
|
||||
|
||||
describe RuboCop::Cop::FormulaAudit::Service do
|
||||
subject(:cop) { described_class.new }
|
||||
|
||||
it "reports an offense when a formula's service block uses `bin`" do
|
||||
expect_offense(<<~RUBY)
|
||||
class Foo < Formula
|
||||
url "https://brew.sh/foo-1.0.tgz"
|
||||
|
||||
service do
|
||||
run [bin/"foo", "run", "-config", etc/"foo/config.json"]
|
||||
^^^ Use `opt_bin` instead of `bin` in service blocks.
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
expect_correction(<<~RUBY)
|
||||
class Foo < Formula
|
||||
url "https://brew.sh/foo-1.0.tgz"
|
||||
|
||||
service do
|
||||
run [opt_bin/"foo", "run", "-config", etc/"foo/config.json"]
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
|
||||
it "reports no offenses when a formula's service block uses `opt_bin`" do
|
||||
expect_no_offenses(<<~RUBY)
|
||||
class Bin < Formula
|
||||
url "https://brew.sh/foo-1.0.tgz"
|
||||
|
||||
service do
|
||||
run [opt_bin/"bin", "run", "-config", etc/"bin/config.json"]
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
end
|
||||
end
|
@ -975,5 +975,37 @@ describe Homebrew::Service do
|
||||
it "replaces placeholders with local paths" do
|
||||
expect(described_class.deserialize(serialized_hash)).to eq(deserialized_hash)
|
||||
end
|
||||
|
||||
describe "run command" do
|
||||
it "handles String argument correctly" do
|
||||
expect(described_class.deserialize({
|
||||
"run" => "$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd",
|
||||
})).to eq({
|
||||
run: "#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd",
|
||||
})
|
||||
end
|
||||
|
||||
it "handles Array argument correctly" do
|
||||
expect(described_class.deserialize({
|
||||
"run" => ["$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd", "--option"],
|
||||
})).to eq({
|
||||
run: ["#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd", "--option"],
|
||||
})
|
||||
end
|
||||
|
||||
it "handles Hash argument correctly" do
|
||||
expect(described_class.deserialize({
|
||||
"run" => {
|
||||
"linux" => "$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd",
|
||||
"macos" => ["$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd", "--option"],
|
||||
},
|
||||
})).to eq({
|
||||
run: {
|
||||
linux: "#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd",
|
||||
macos: ["#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd", "--option"],
|
||||
},
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -93,6 +93,26 @@ describe Version do
|
||||
expect(described_class.create("1.2.3")).to be < described_class.create("1.2.3-p34")
|
||||
end
|
||||
|
||||
specify "compare" do
|
||||
expect(described_class.create("0.1").compare("==", described_class.create("0.1.0"))).to be true
|
||||
expect(described_class.create("0.1").compare("<", described_class.create("0.2"))).to be true
|
||||
expect(described_class.create("1.2.3").compare(">", described_class.create("1.2.2"))).to be true
|
||||
expect(described_class.create("1.2.4").compare("<", described_class.create("1.2.4.1"))).to be true
|
||||
expect(described_class.create("0.1").compare("!=", described_class.create("0.1.0"))).to be false
|
||||
expect(described_class.create("0.1").compare(">=", described_class.create("0.2"))).to be false
|
||||
expect(described_class.create("1.2.3").compare("<=", described_class.create("1.2.2"))).to be false
|
||||
expect(described_class.create("1.2.4").compare(">=", described_class.create("1.2.4.1"))).to be false
|
||||
|
||||
expect(described_class.create("1.2.3").compare(">", described_class.create("1.2.3alpha4"))).to be true
|
||||
expect(described_class.create("1.2.3").compare(">", described_class.create("1.2.3beta2"))).to be true
|
||||
expect(described_class.create("1.2.3").compare(">", described_class.create("1.2.3rc3"))).to be true
|
||||
expect(described_class.create("1.2.3").compare("<", described_class.create("1.2.3-p34"))).to be true
|
||||
expect(described_class.create("1.2.3").compare("<=", described_class.create("1.2.3alpha4"))).to be false
|
||||
expect(described_class.create("1.2.3").compare("<=", described_class.create("1.2.3beta2"))).to be false
|
||||
expect(described_class.create("1.2.3").compare("<=", described_class.create("1.2.3rc3"))).to be false
|
||||
expect(described_class.create("1.2.3").compare(">=", described_class.create("1.2.3-p34"))).to be false
|
||||
end
|
||||
|
||||
specify "HEAD" do
|
||||
expect(described_class.create("HEAD")).to be > described_class.create("1.2.3")
|
||||
expect(described_class.create("HEAD-abcdef")).to be > described_class.create("1.2.3")
|
||||
|
@ -41,6 +41,16 @@ module Homebrew
|
||||
@qlplugins ||= @cask.artifacts.select { |a| a.is_a?(Cask::Artifact::Qlplugin) }
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Cask::Artifact::Dictionary]) }
|
||||
def dictionaries
|
||||
@dictionaries ||= @cask.artifacts.select { |a| a.is_a?(Cask::Artifact::Dictionary) }
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Cask::Artifact::ScreenSaver]) }
|
||||
def screen_savers
|
||||
@screen_savers ||= @cask.artifacts.select { |a| a.is_a?(Cask::Artifact::ScreenSaver) }
|
||||
end
|
||||
|
||||
sig { returns(T::Array[Cask::Artifact::Colorpicker]) }
|
||||
def colorpickers
|
||||
@colorpickers ||= @cask.artifacts.select { |a| a.is_a?(Cask::Artifact::Colorpicker) }
|
||||
@ -113,11 +123,24 @@ module Homebrew
|
||||
*keyboard_layouts,
|
||||
*mdimporters,
|
||||
*colorpickers,
|
||||
*dictionaries,
|
||||
*qlplugins,
|
||||
*installers,
|
||||
*screen_savers,
|
||||
].flat_map do |artifact|
|
||||
source = artifact.is_a?(Cask::Artifact::Installer) ? artifact.path : artifact.source.basename
|
||||
top_level_info_plists(Pathname.glob(dir/"**"/source/"Contents"/"Info.plist")).sort
|
||||
sources = if artifact.is_a?(Cask::Artifact::Installer)
|
||||
# Installers are sometimes contained within an `.app`, so try both.
|
||||
installer_path = artifact.path
|
||||
installer_path.ascend
|
||||
.select { |path| path == installer_path || path.extname == ".app" }
|
||||
.sort
|
||||
else
|
||||
[artifact.source.basename]
|
||||
end
|
||||
|
||||
sources.flat_map do |source|
|
||||
top_level_info_plists(Pathname.glob(dir/"**"/source/"Contents"/"Info.plist")).sort
|
||||
end
|
||||
end
|
||||
|
||||
info_plist_paths.each(&parse_info_plist)
|
||||
|
@ -12,8 +12,6 @@ module Homebrew
|
||||
# After updating this, run `brew vendor-gems --update=--bundler`.
|
||||
HOMEBREW_BUNDLER_VERSION = "2.3.26"
|
||||
|
||||
VALID_GEM_GROUPS = ["sorbet", "prof"].freeze
|
||||
|
||||
module_function
|
||||
|
||||
def ruby_bindir
|
||||
@ -136,9 +134,6 @@ module Homebrew
|
||||
old_bundle_frozen = ENV.fetch("BUNDLE_FROZEN", nil)
|
||||
old_sdkroot = ENV.fetch("SDKROOT", nil)
|
||||
|
||||
invalid_groups = groups - VALID_GEM_GROUPS
|
||||
raise ArgumentError, "Invalid gem groups: #{invalid_groups.join(", ")}" unless invalid_groups.empty?
|
||||
|
||||
install_bundler!
|
||||
|
||||
require "settings"
|
||||
|
@ -418,6 +418,17 @@ module GitHub
|
||||
result["organization"]["team"]["members"]["nodes"].to_h { |member| [member["login"], member["name"]] }
|
||||
end
|
||||
|
||||
sig {
|
||||
params(user: String)
|
||||
.returns(
|
||||
T::Array[{
|
||||
closest_tier_monthly_amount: Integer,
|
||||
login: String,
|
||||
monthly_amount: Integer,
|
||||
name: String,
|
||||
}],
|
||||
)
|
||||
}
|
||||
def self.sponsorships(user)
|
||||
has_next_page = T.let(true, T::Boolean)
|
||||
after = ""
|
||||
|
@ -1,4 +1,4 @@
|
||||
# typed: false
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Helper functions for updating PyPI resources.
|
||||
@ -7,8 +7,6 @@
|
||||
module PyPI
|
||||
extend T::Sig
|
||||
|
||||
module_function
|
||||
|
||||
PYTHONHOSTED_URL_PREFIX = "https://files.pythonhosted.org/packages/"
|
||||
private_constant :PYTHONHOSTED_URL_PREFIX
|
||||
|
||||
@ -35,13 +33,16 @@ module PyPI
|
||||
return
|
||||
end
|
||||
|
||||
@name = package_string
|
||||
@name, @version = @name.split("==") if @name.include? "=="
|
||||
if package_string.include? "=="
|
||||
@name, @version = package_string.split("==")
|
||||
else
|
||||
@name = package_string
|
||||
end
|
||||
|
||||
return unless (match = @name.match(/^(.*?)\[(.+)\]$/))
|
||||
return unless (match = T.must(@name).match(/^(.*?)\[(.+)\]$/))
|
||||
|
||||
@name = match[1]
|
||||
@extras = match[2].split ","
|
||||
@extras = T.must(match[2]).split ","
|
||||
end
|
||||
|
||||
# Get name, URL, SHA-256 checksum, and latest version for a given PyPI package.
|
||||
@ -87,7 +88,7 @@ module PyPI
|
||||
|
||||
sig { params(other: Package).returns(T::Boolean) }
|
||||
def same_package?(other)
|
||||
@name.tr("_", "-").casecmp(other.name.tr("_", "-")).zero?
|
||||
T.must(@name.tr("_", "-").casecmp(other.name.tr("_", "-"))).zero?
|
||||
end
|
||||
|
||||
# Compare only names so we can use .include? and .uniq on a Package array
|
||||
@ -109,7 +110,7 @@ module PyPI
|
||||
end
|
||||
|
||||
sig { params(url: String, version: T.any(String, Version)).returns(T.nilable(String)) }
|
||||
def update_pypi_url(url, version)
|
||||
def self.update_pypi_url(url, version)
|
||||
package = Package.new url, is_url: true
|
||||
|
||||
return unless package.valid_pypi_package?
|
||||
@ -133,8 +134,9 @@ module PyPI
|
||||
ignore_non_pypi_packages: T.nilable(T::Boolean),
|
||||
).returns(T.nilable(T::Boolean))
|
||||
}
|
||||
def update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil, exclude_packages: nil,
|
||||
print_only: false, silent: false, ignore_non_pypi_packages: false)
|
||||
def self.update_python_resources!(formula, version: nil, package_name: nil, extra_packages: nil,
|
||||
exclude_packages: nil, print_only: false, silent: false,
|
||||
ignore_non_pypi_packages: false)
|
||||
|
||||
auto_update_list = formula.tap&.pypi_formula_mappings
|
||||
if auto_update_list.present? && auto_update_list.key?(formula.full_name) &&
|
||||
@ -282,7 +284,7 @@ module PyPI
|
||||
true
|
||||
end
|
||||
|
||||
def json_to_packages(json_tree, main_package, exclude_packages)
|
||||
def self.json_to_packages(json_tree, main_package, exclude_packages)
|
||||
return [] if json_tree.blank?
|
||||
|
||||
json_tree.flat_map do |package_json|
|
||||
|
@ -30,7 +30,7 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/zeitwerk-2.6.7/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/activesupport-6.1.7.3/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/public_suffix-5.0.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/addressable-2.8.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/addressable-2.8.2/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ast-2.4.2/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/bindata-2.4.15/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/universal-darwin-21/#{Gem.extension_api_version}/msgpack-1.7.0")
|
||||
@ -76,7 +76,7 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/mustache-1.1.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parallel-1.22.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parallel_tests-3.13.0/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parser-3.2.1.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parser-3.2.2.0/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rainbow-3.1.1/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-runtime-0.5.10461/lib")
|
||||
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parlour-8.1.0/lib")
|
||||
|
@ -29,10 +29,6 @@ module Addressable
|
||||
IDN::Punycode.decode(value.to_s)
|
||||
end
|
||||
|
||||
def self.unicode_normalize_kc(value)
|
||||
IDN::Stringprep.nfkc_normalize(value.to_s)
|
||||
end
|
||||
|
||||
def self.to_ascii(value)
|
||||
value.to_s.split('.', -1).map do |segment|
|
||||
if segment.size > 0 && segment.size < 64
|
@ -66,7 +66,7 @@ module Addressable
|
||||
# domain name as described in RFC 3490.
|
||||
def self.to_ascii(input)
|
||||
input = input.to_s unless input.is_a?(String)
|
||||
input = input.dup
|
||||
input = input.dup.force_encoding(Encoding::UTF_8).unicode_normalize(:nfkc)
|
||||
if input.respond_to?(:force_encoding)
|
||||
input.force_encoding(Encoding::ASCII_8BIT)
|
||||
end
|
||||
@ -77,7 +77,7 @@ module Addressable
|
||||
part.force_encoding(Encoding::ASCII_8BIT)
|
||||
end
|
||||
if part =~ UTF8_REGEX && part =~ UTF8_REGEX_MULTIBYTE
|
||||
ACE_PREFIX + punycode_encode(unicode_normalize_kc(part))
|
||||
ACE_PREFIX + punycode_encode(part)
|
||||
else
|
||||
part
|
||||
end
|
||||
@ -112,15 +112,6 @@ module Addressable
|
||||
output
|
||||
end
|
||||
|
||||
# Unicode normalization form KC.
|
||||
def self.unicode_normalize_kc(input)
|
||||
input = input.to_s unless input.is_a?(String)
|
||||
unpacked = input.unpack("U*")
|
||||
unpacked =
|
||||
unicode_compose(unicode_sort_canonical(unicode_decompose(unpacked)))
|
||||
return unpacked.pack("U*")
|
||||
end
|
||||
|
||||
##
|
||||
# Unicode aware downcase method.
|
||||
#
|
||||
@ -136,164 +127,6 @@ module Addressable
|
||||
end
|
||||
private_class_method :unicode_downcase
|
||||
|
||||
def self.unicode_compose(unpacked)
|
||||
unpacked_result = []
|
||||
length = unpacked.length
|
||||
|
||||
return unpacked if length == 0
|
||||
|
||||
starter = unpacked[0]
|
||||
starter_cc = lookup_unicode_combining_class(starter)
|
||||
starter_cc = 256 if starter_cc != 0
|
||||
for i in 1...length
|
||||
ch = unpacked[i]
|
||||
|
||||
if (starter_cc == 0 &&
|
||||
(composite = unicode_compose_pair(starter, ch)) != nil)
|
||||
starter = composite
|
||||
else
|
||||
unpacked_result << starter
|
||||
starter = ch
|
||||
end
|
||||
end
|
||||
unpacked_result << starter
|
||||
return unpacked_result
|
||||
end
|
||||
private_class_method :unicode_compose
|
||||
|
||||
def self.unicode_compose_pair(ch_one, ch_two)
|
||||
if ch_one >= HANGUL_LBASE && ch_one < HANGUL_LBASE + HANGUL_LCOUNT &&
|
||||
ch_two >= HANGUL_VBASE && ch_two < HANGUL_VBASE + HANGUL_VCOUNT
|
||||
# Hangul L + V
|
||||
return HANGUL_SBASE + (
|
||||
(ch_one - HANGUL_LBASE) * HANGUL_VCOUNT + (ch_two - HANGUL_VBASE)
|
||||
) * HANGUL_TCOUNT
|
||||
elsif ch_one >= HANGUL_SBASE &&
|
||||
ch_one < HANGUL_SBASE + HANGUL_SCOUNT &&
|
||||
(ch_one - HANGUL_SBASE) % HANGUL_TCOUNT == 0 &&
|
||||
ch_two >= HANGUL_TBASE && ch_two < HANGUL_TBASE + HANGUL_TCOUNT
|
||||
# Hangul LV + T
|
||||
return ch_one + (ch_two - HANGUL_TBASE)
|
||||
end
|
||||
|
||||
p = []
|
||||
|
||||
ucs4_to_utf8(ch_one, p)
|
||||
ucs4_to_utf8(ch_two, p)
|
||||
|
||||
return lookup_unicode_composition(p)
|
||||
end
|
||||
private_class_method :unicode_compose_pair
|
||||
|
||||
def self.ucs4_to_utf8(char, buffer)
|
||||
if char < 128
|
||||
buffer << char
|
||||
elsif char < 2048
|
||||
buffer << (char >> 6 | 192)
|
||||
buffer << (char & 63 | 128)
|
||||
elsif char < 0x10000
|
||||
buffer << (char >> 12 | 224)
|
||||
buffer << (char >> 6 & 63 | 128)
|
||||
buffer << (char & 63 | 128)
|
||||
elsif char < 0x200000
|
||||
buffer << (char >> 18 | 240)
|
||||
buffer << (char >> 12 & 63 | 128)
|
||||
buffer << (char >> 6 & 63 | 128)
|
||||
buffer << (char & 63 | 128)
|
||||
elsif char < 0x4000000
|
||||
buffer << (char >> 24 | 248)
|
||||
buffer << (char >> 18 & 63 | 128)
|
||||
buffer << (char >> 12 & 63 | 128)
|
||||
buffer << (char >> 6 & 63 | 128)
|
||||
buffer << (char & 63 | 128)
|
||||
elsif char < 0x80000000
|
||||
buffer << (char >> 30 | 252)
|
||||
buffer << (char >> 24 & 63 | 128)
|
||||
buffer << (char >> 18 & 63 | 128)
|
||||
buffer << (char >> 12 & 63 | 128)
|
||||
buffer << (char >> 6 & 63 | 128)
|
||||
buffer << (char & 63 | 128)
|
||||
end
|
||||
end
|
||||
private_class_method :ucs4_to_utf8
|
||||
|
||||
def self.unicode_sort_canonical(unpacked)
|
||||
unpacked = unpacked.dup
|
||||
i = 1
|
||||
length = unpacked.length
|
||||
|
||||
return unpacked if length < 2
|
||||
|
||||
while i < length
|
||||
last = unpacked[i-1]
|
||||
ch = unpacked[i]
|
||||
last_cc = lookup_unicode_combining_class(last)
|
||||
cc = lookup_unicode_combining_class(ch)
|
||||
if cc != 0 && last_cc != 0 && last_cc > cc
|
||||
unpacked[i] = last
|
||||
unpacked[i-1] = ch
|
||||
i -= 1 if i > 1
|
||||
else
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
return unpacked
|
||||
end
|
||||
private_class_method :unicode_sort_canonical
|
||||
|
||||
def self.unicode_decompose(unpacked)
|
||||
unpacked_result = []
|
||||
for cp in unpacked
|
||||
if cp >= HANGUL_SBASE && cp < HANGUL_SBASE + HANGUL_SCOUNT
|
||||
l, v, t = unicode_decompose_hangul(cp)
|
||||
unpacked_result << l
|
||||
unpacked_result << v if v
|
||||
unpacked_result << t if t
|
||||
else
|
||||
dc = lookup_unicode_compatibility(cp)
|
||||
unless dc
|
||||
unpacked_result << cp
|
||||
else
|
||||
unpacked_result.concat(unicode_decompose(dc.unpack("U*")))
|
||||
end
|
||||
end
|
||||
end
|
||||
return unpacked_result
|
||||
end
|
||||
private_class_method :unicode_decompose
|
||||
|
||||
def self.unicode_decompose_hangul(codepoint)
|
||||
sindex = codepoint - HANGUL_SBASE;
|
||||
if sindex < 0 || sindex >= HANGUL_SCOUNT
|
||||
l = codepoint
|
||||
v = t = nil
|
||||
return l, v, t
|
||||
end
|
||||
l = HANGUL_LBASE + sindex / HANGUL_NCOUNT
|
||||
v = HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
|
||||
t = HANGUL_TBASE + sindex % HANGUL_TCOUNT
|
||||
if t == HANGUL_TBASE
|
||||
t = nil
|
||||
end
|
||||
return l, v, t
|
||||
end
|
||||
private_class_method :unicode_decompose_hangul
|
||||
|
||||
def self.lookup_unicode_combining_class(codepoint)
|
||||
codepoint_data = UNICODE_DATA[codepoint]
|
||||
(codepoint_data ?
|
||||
(codepoint_data[UNICODE_DATA_COMBINING_CLASS] || 0) :
|
||||
0)
|
||||
end
|
||||
private_class_method :lookup_unicode_combining_class
|
||||
|
||||
def self.lookup_unicode_compatibility(codepoint)
|
||||
codepoint_data = UNICODE_DATA[codepoint]
|
||||
(codepoint_data ?
|
||||
codepoint_data[UNICODE_DATA_COMPATIBILITY] : nil)
|
||||
end
|
||||
private_class_method :lookup_unicode_compatibility
|
||||
|
||||
def self.lookup_unicode_lowercase(codepoint)
|
||||
codepoint_data = UNICODE_DATA[codepoint]
|
||||
(codepoint_data ?
|
||||
@ -302,21 +135,6 @@ module Addressable
|
||||
end
|
||||
private_class_method :lookup_unicode_lowercase
|
||||
|
||||
def self.lookup_unicode_composition(unpacked)
|
||||
return COMPOSITION_TABLE[unpacked]
|
||||
end
|
||||
private_class_method :lookup_unicode_composition
|
||||
|
||||
HANGUL_SBASE = 0xac00
|
||||
HANGUL_LBASE = 0x1100
|
||||
HANGUL_LCOUNT = 19
|
||||
HANGUL_VBASE = 0x1161
|
||||
HANGUL_VCOUNT = 21
|
||||
HANGUL_TBASE = 0x11a7
|
||||
HANGUL_TCOUNT = 28
|
||||
HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT # 588
|
||||
HANGUL_SCOUNT = HANGUL_LCOUNT * HANGUL_NCOUNT # 11172
|
||||
|
||||
UNICODE_DATA_COMBINING_CLASS = 0
|
||||
UNICODE_DATA_EXCLUSION = 1
|
||||
UNICODE_DATA_CANONICAL = 2
|
@ -892,7 +892,7 @@ module Addressable
|
||||
# operator.
|
||||
#
|
||||
# @param [Hash, Array, String] value
|
||||
# Normalizes keys and values with IDNA#unicode_normalize_kc
|
||||
# Normalizes unicode keys and values with String#unicode_normalize (NFC)
|
||||
#
|
||||
# @return [Hash, Array, String] The normalized values
|
||||
def normalize_value(value)
|
||||
@ -902,15 +902,17 @@ module Addressable
|
||||
|
||||
# Handle unicode normalization
|
||||
if value.kind_of?(Array)
|
||||
value.map! { |val| Addressable::IDNA.unicode_normalize_kc(val) }
|
||||
value.map! { |val| normalize_value(val) }
|
||||
elsif value.kind_of?(Hash)
|
||||
value = value.inject({}) { |acc, (k, v)|
|
||||
acc[Addressable::IDNA.unicode_normalize_kc(k)] =
|
||||
Addressable::IDNA.unicode_normalize_kc(v)
|
||||
acc[normalize_value(k)] = normalize_value(v)
|
||||
acc
|
||||
}
|
||||
else
|
||||
value = Addressable::IDNA.unicode_normalize_kc(value)
|
||||
if value.encoding != Encoding::UTF_8
|
||||
value = value.dup.force_encoding(Encoding::UTF_8)
|
||||
end
|
||||
value = value.unicode_normalize(:nfc)
|
||||
end
|
||||
value
|
||||
end
|
@ -53,7 +53,7 @@ module Addressable
|
||||
PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
|
||||
SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
|
||||
HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
|
||||
AUTHORITY = (PCHAR + "\\[\\:\\]").freeze
|
||||
AUTHORITY = (PCHAR + "\\[\\]").freeze
|
||||
PATH = (PCHAR + "\\/").freeze
|
||||
QUERY = (PCHAR + "\\/\\?").freeze
|
||||
FRAGMENT = (PCHAR + "\\/\\?").freeze
|
||||
@ -117,7 +117,7 @@ module Addressable
|
||||
uri = uri.to_str
|
||||
rescue TypeError, NoMethodError
|
||||
raise TypeError, "Can't convert #{uri.class} into String."
|
||||
end if not uri.is_a? String
|
||||
end unless uri.is_a?(String)
|
||||
|
||||
# This Regexp supplied as an example in RFC 3986, and it works great.
|
||||
scan = uri.scan(URIREGEX)
|
||||
@ -138,15 +138,15 @@ module Addressable
|
||||
user = userinfo.strip[/^([^:]*):?/, 1]
|
||||
password = userinfo.strip[/:(.*)$/, 1]
|
||||
end
|
||||
|
||||
host = authority.sub(
|
||||
/^([^\[\]]*)@/, EMPTY_STR
|
||||
).sub(
|
||||
/:([^:@\[\]]*?)$/, EMPTY_STR
|
||||
)
|
||||
|
||||
port = authority[/:([^:@\[\]]*?)$/, 1]
|
||||
end
|
||||
if port == EMPTY_STR
|
||||
port = nil
|
||||
port = nil if port == EMPTY_STR
|
||||
end
|
||||
|
||||
return new(
|
||||
@ -189,7 +189,7 @@ module Addressable
|
||||
uri = uri.to_s
|
||||
end
|
||||
|
||||
if !uri.respond_to?(:to_str)
|
||||
unless uri.respond_to?(:to_str)
|
||||
raise TypeError, "Can't convert #{uri.class} into String."
|
||||
end
|
||||
# Otherwise, convert to a String
|
||||
@ -281,7 +281,7 @@ module Addressable
|
||||
return nil unless path
|
||||
# If a URI object is passed, just return itself.
|
||||
return path if path.kind_of?(self)
|
||||
if !path.respond_to?(:to_str)
|
||||
unless path.respond_to?(:to_str)
|
||||
raise TypeError, "Can't convert #{path.class} into String."
|
||||
end
|
||||
# Otherwise, convert to a String
|
||||
@ -329,13 +329,13 @@ module Addressable
|
||||
# #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
|
||||
def self.join(*uris)
|
||||
uri_objects = uris.collect do |uri|
|
||||
if !uri.respond_to?(:to_str)
|
||||
unless uri.respond_to?(:to_str)
|
||||
raise TypeError, "Can't convert #{uri.class} into String."
|
||||
end
|
||||
uri.kind_of?(self) ? uri : self.parse(uri.to_str)
|
||||
end
|
||||
result = uri_objects.shift.dup
|
||||
for uri in uri_objects
|
||||
uri_objects.each do |uri|
|
||||
result.join!(uri)
|
||||
end
|
||||
return result
|
||||
@ -481,7 +481,7 @@ module Addressable
|
||||
leave_encoded.include?(c) ? sequence : c
|
||||
end
|
||||
|
||||
result.force_encoding("utf-8")
|
||||
result.force_encoding(Encoding::UTF_8)
|
||||
if return_type == String
|
||||
return result
|
||||
elsif return_type == ::Addressable::URI
|
||||
@ -579,7 +579,7 @@ module Addressable
|
||||
unencoded = self.unencode_component(component, String, leave_encoded)
|
||||
begin
|
||||
encoded = self.encode_component(
|
||||
Addressable::IDNA.unicode_normalize_kc(unencoded),
|
||||
unencoded.unicode_normalize(:nfc),
|
||||
character_class,
|
||||
leave_encoded
|
||||
)
|
||||
@ -687,8 +687,7 @@ module Addressable
|
||||
components.each do |key, value|
|
||||
if value != nil
|
||||
begin
|
||||
components[key] =
|
||||
Addressable::IDNA.unicode_normalize_kc(value.to_str)
|
||||
components[key] = value.to_str.unicode_normalize(:nfc)
|
||||
rescue ArgumentError
|
||||
# Likely a malformed UTF-8 character, skip unicode normalization
|
||||
components[key] = value.to_str
|
||||
@ -836,7 +835,9 @@ module Addressable
|
||||
end
|
||||
end
|
||||
|
||||
self.defer_validation do
|
||||
reset_ivs
|
||||
|
||||
defer_validation do
|
||||
# Bunch of crazy logic required because of the composite components
|
||||
# like userinfo and authority.
|
||||
self.scheme = options[:scheme] if options[:scheme]
|
||||
@ -851,7 +852,8 @@ module Addressable
|
||||
self.query_values = options[:query_values] if options[:query_values]
|
||||
self.fragment = options[:fragment] if options[:fragment]
|
||||
end
|
||||
self.to_s
|
||||
|
||||
to_s # force path validation
|
||||
end
|
||||
|
||||
##
|
||||
@ -878,9 +880,7 @@ module Addressable
|
||||
# The scheme component for this URI.
|
||||
#
|
||||
# @return [String] The scheme component.
|
||||
def scheme
|
||||
return defined?(@scheme) ? @scheme : nil
|
||||
end
|
||||
attr_reader :scheme
|
||||
|
||||
##
|
||||
# The scheme component for this URI, normalized.
|
||||
@ -888,8 +888,8 @@ module Addressable
|
||||
# @return [String] The scheme component, normalized.
|
||||
def normalized_scheme
|
||||
return nil unless self.scheme
|
||||
@normalized_scheme ||= begin
|
||||
if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
||||
if @normalized_scheme == NONE
|
||||
@normalized_scheme = if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
||||
"svn+ssh".dup
|
||||
else
|
||||
Addressable::URI.normalize_component(
|
||||
@ -920,7 +920,7 @@ module Addressable
|
||||
@scheme = nil if @scheme.to_s.strip.empty?
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@normalized_scheme) if defined?(@normalized_scheme)
|
||||
@normalized_scheme = NONE
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -931,9 +931,7 @@ module Addressable
|
||||
# The user component for this URI.
|
||||
#
|
||||
# @return [String] The user component.
|
||||
def user
|
||||
return defined?(@user) ? @user : nil
|
||||
end
|
||||
attr_reader :user
|
||||
|
||||
##
|
||||
# The user component for this URI, normalized.
|
||||
@ -941,8 +939,8 @@ module Addressable
|
||||
# @return [String] The user component, normalized.
|
||||
def normalized_user
|
||||
return nil unless self.user
|
||||
return @normalized_user if defined?(@normalized_user)
|
||||
@normalized_user ||= begin
|
||||
return @normalized_user unless @normalized_user == NONE
|
||||
@normalized_user = begin
|
||||
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
||||
(!self.password || self.password.strip.empty?)
|
||||
nil
|
||||
@ -970,14 +968,14 @@ module Addressable
|
||||
|
||||
# You can't have a nil user with a non-nil password
|
||||
if password != nil
|
||||
@user = EMPTY_STR if @user.nil?
|
||||
@user = EMPTY_STR unless user
|
||||
end
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
||||
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
||||
remove_instance_variable(:@authority) if defined?(@authority)
|
||||
remove_instance_variable(:@normalized_user) if defined?(@normalized_user)
|
||||
@userinfo = nil
|
||||
@normalized_userinfo = NONE
|
||||
@authority = nil
|
||||
@normalized_user = NONE
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -988,9 +986,7 @@ module Addressable
|
||||
# The password component for this URI.
|
||||
#
|
||||
# @return [String] The password component.
|
||||
def password
|
||||
return defined?(@password) ? @password : nil
|
||||
end
|
||||
attr_reader :password
|
||||
|
||||
##
|
||||
# The password component for this URI, normalized.
|
||||
@ -998,8 +994,8 @@ module Addressable
|
||||
# @return [String] The password component, normalized.
|
||||
def normalized_password
|
||||
return nil unless self.password
|
||||
return @normalized_password if defined?(@normalized_password)
|
||||
@normalized_password ||= begin
|
||||
return @normalized_password unless @normalized_password == NONE
|
||||
@normalized_password = begin
|
||||
if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
||||
(!self.user || self.user.strip.empty?)
|
||||
nil
|
||||
@ -1026,17 +1022,15 @@ module Addressable
|
||||
@password = new_password ? new_password.to_str : nil
|
||||
|
||||
# You can't have a nil user with a non-nil password
|
||||
@password ||= nil
|
||||
@user ||= nil
|
||||
if @password != nil
|
||||
@user = EMPTY_STR if @user.nil?
|
||||
self.user = EMPTY_STR if user.nil?
|
||||
end
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
||||
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
||||
remove_instance_variable(:@authority) if defined?(@authority)
|
||||
remove_instance_variable(:@normalized_password) if defined?(@normalized_password)
|
||||
@userinfo = nil
|
||||
@normalized_userinfo = NONE
|
||||
@authority = nil
|
||||
@normalized_password = NONE
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1066,8 +1060,8 @@ module Addressable
|
||||
# @return [String] The userinfo component, normalized.
|
||||
def normalized_userinfo
|
||||
return nil unless self.userinfo
|
||||
return @normalized_userinfo if defined?(@normalized_userinfo)
|
||||
@normalized_userinfo ||= begin
|
||||
return @normalized_userinfo unless @normalized_userinfo == NONE
|
||||
@normalized_userinfo = begin
|
||||
current_user = self.normalized_user
|
||||
current_password = self.normalized_password
|
||||
if !current_user && !current_password
|
||||
@ -1105,7 +1099,7 @@ module Addressable
|
||||
self.user = new_user
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@authority) if defined?(@authority)
|
||||
@authority = nil
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1116,9 +1110,7 @@ module Addressable
|
||||
# The host component for this URI.
|
||||
#
|
||||
# @return [String] The host component.
|
||||
def host
|
||||
return defined?(@host) ? @host : nil
|
||||
end
|
||||
attr_reader :host
|
||||
|
||||
##
|
||||
# The host component for this URI, normalized.
|
||||
@ -1161,8 +1153,8 @@ module Addressable
|
||||
@host = new_host ? new_host.to_str : nil
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@authority) if defined?(@authority)
|
||||
remove_instance_variable(:@normalized_host) if defined?(@normalized_host)
|
||||
@authority = nil
|
||||
@normalized_host = nil
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1293,14 +1285,14 @@ module Addressable
|
||||
end
|
||||
|
||||
# Password assigned first to ensure validity in case of nil
|
||||
self.password = defined?(new_password) ? new_password : nil
|
||||
self.user = defined?(new_user) ? new_user : nil
|
||||
self.host = defined?(new_host) ? new_host : nil
|
||||
self.port = defined?(new_port) ? new_port : nil
|
||||
self.password = new_password
|
||||
self.user = new_user
|
||||
self.host = new_host
|
||||
self.port = new_port
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
||||
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
||||
@userinfo = nil
|
||||
@normalized_userinfo = NONE
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1348,16 +1340,16 @@ module Addressable
|
||||
new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
|
||||
end
|
||||
|
||||
self.scheme = defined?(new_scheme) ? new_scheme : nil
|
||||
self.host = defined?(new_host) ? new_host : nil
|
||||
self.port = defined?(new_port) ? new_port : nil
|
||||
self.scheme = new_scheme
|
||||
self.host = new_host
|
||||
self.port = new_port
|
||||
self.userinfo = nil
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
||||
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
||||
remove_instance_variable(:@authority) if defined?(@authority)
|
||||
remove_instance_variable(:@normalized_authority) if defined?(@normalized_authority)
|
||||
@userinfo = nil
|
||||
@normalized_userinfo = NONE
|
||||
@authority = nil
|
||||
@normalized_authority = nil
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1384,9 +1376,7 @@ module Addressable
|
||||
# infer port numbers from default values.
|
||||
#
|
||||
# @return [Integer] The port component.
|
||||
def port
|
||||
return defined?(@port) ? @port : nil
|
||||
end
|
||||
attr_reader :port
|
||||
|
||||
##
|
||||
# The port component for this URI, normalized.
|
||||
@ -1394,8 +1384,8 @@ module Addressable
|
||||
# @return [Integer] The port component, normalized.
|
||||
def normalized_port
|
||||
return nil unless self.port
|
||||
return @normalized_port if defined?(@normalized_port)
|
||||
@normalized_port ||= begin
|
||||
return @normalized_port unless @normalized_port == NONE
|
||||
@normalized_port = begin
|
||||
if URI.port_mapping[self.normalized_scheme] == self.port
|
||||
nil
|
||||
else
|
||||
@ -1426,8 +1416,8 @@ module Addressable
|
||||
@port = nil if @port == 0
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@authority) if defined?(@authority)
|
||||
remove_instance_variable(:@normalized_port) if defined?(@normalized_port)
|
||||
@authority = nil
|
||||
@normalized_port = NONE
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1528,9 +1518,7 @@ module Addressable
|
||||
# The path component for this URI.
|
||||
#
|
||||
# @return [String] The path component.
|
||||
def path
|
||||
return defined?(@path) ? @path : EMPTY_STR
|
||||
end
|
||||
attr_reader :path
|
||||
|
||||
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
||||
##
|
||||
@ -1579,7 +1567,7 @@ module Addressable
|
||||
end
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@normalized_path) if defined?(@normalized_path)
|
||||
@normalized_path = nil
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -1609,9 +1597,7 @@ module Addressable
|
||||
# The query component for this URI.
|
||||
#
|
||||
# @return [String] The query component.
|
||||
def query
|
||||
return defined?(@query) ? @query : nil
|
||||
end
|
||||
attr_reader :query
|
||||
|
||||
##
|
||||
# The query component for this URI, normalized.
|
||||
@ -1619,8 +1605,8 @@ module Addressable
|
||||
# @return [String] The query component, normalized.
|
||||
def normalized_query(*flags)
|
||||
return nil unless self.query
|
||||
return @normalized_query if defined?(@normalized_query)
|
||||
@normalized_query ||= begin
|
||||
return @normalized_query unless @normalized_query == NONE
|
||||
@normalized_query = begin
|
||||
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
||||
# Make sure possible key-value pair delimiters are escaped.
|
||||
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
||||
@ -1652,7 +1638,7 @@ module Addressable
|
||||
@query = new_query ? new_query.to_str : nil
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@normalized_query) if defined?(@normalized_query)
|
||||
@normalized_query = NONE
|
||||
remove_composite_values
|
||||
end
|
||||
|
||||
@ -1814,9 +1800,7 @@ module Addressable
|
||||
# The fragment component for this URI.
|
||||
#
|
||||
# @return [String] The fragment component.
|
||||
def fragment
|
||||
return defined?(@fragment) ? @fragment : nil
|
||||
end
|
||||
attr_reader :fragment
|
||||
|
||||
##
|
||||
# The fragment component for this URI, normalized.
|
||||
@ -1824,8 +1808,8 @@ module Addressable
|
||||
# @return [String] The fragment component, normalized.
|
||||
def normalized_fragment
|
||||
return nil unless self.fragment
|
||||
return @normalized_fragment if defined?(@normalized_fragment)
|
||||
@normalized_fragment ||= begin
|
||||
return @normalized_fragment unless @normalized_fragment == NONE
|
||||
@normalized_fragment = begin
|
||||
component = Addressable::URI.normalize_component(
|
||||
self.fragment,
|
||||
Addressable::URI::NormalizeCharacterClasses::FRAGMENT
|
||||
@ -1848,7 +1832,7 @@ module Addressable
|
||||
@fragment = new_fragment ? new_fragment.to_str : nil
|
||||
|
||||
# Reset dependent values
|
||||
remove_instance_variable(:@normalized_fragment) if defined?(@normalized_fragment)
|
||||
@normalized_fragment = NONE
|
||||
remove_composite_values
|
||||
|
||||
# Ensure we haven't created an invalid URI
|
||||
@ -2014,7 +1998,7 @@ module Addressable
|
||||
#
|
||||
# @see Hash#merge
|
||||
def merge(hash)
|
||||
if !hash.respond_to?(:to_hash)
|
||||
unless hash.respond_to?(:to_hash)
|
||||
raise TypeError, "Can't convert #{hash.class} into Hash."
|
||||
end
|
||||
hash = hash.to_hash
|
||||
@ -2408,7 +2392,8 @@ module Addressable
|
||||
yield
|
||||
@validation_deferred = false
|
||||
validate
|
||||
return nil
|
||||
ensure
|
||||
@validation_deferred = false
|
||||
end
|
||||
|
||||
protected
|
||||
@ -2507,11 +2492,7 @@ module Addressable
|
||||
# @return [Addressable::URI] <code>self</code>.
|
||||
def replace_self(uri)
|
||||
# Reset dependent values
|
||||
instance_variables.each do |var|
|
||||
if instance_variable_defined?(var) && var != :@validation_deferred
|
||||
remove_instance_variable(var)
|
||||
end
|
||||
end
|
||||
reset_ivs
|
||||
|
||||
@scheme = uri.scheme
|
||||
@user = uri.user
|
||||
@ -2543,8 +2524,8 @@ module Addressable
|
||||
#
|
||||
# @api private
|
||||
def remove_composite_values
|
||||
remove_instance_variable(:@uri_string) if defined?(@uri_string)
|
||||
remove_instance_variable(:@hash) if defined?(@hash)
|
||||
@uri_string = nil
|
||||
@hash = nil
|
||||
end
|
||||
|
||||
##
|
||||
@ -2556,5 +2537,40 @@ module Addressable
|
||||
str.force_encoding(Encoding::UTF_8)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
# Resets instance variables
|
||||
#
|
||||
# @api private
|
||||
def reset_ivs
|
||||
@scheme = nil
|
||||
@user = nil
|
||||
@normalized_scheme = NONE
|
||||
@normalized_user = NONE
|
||||
@uri_string = nil
|
||||
@hash = nil
|
||||
@userinfo = nil
|
||||
@normalized_userinfo = NONE
|
||||
@authority = nil
|
||||
@password = nil
|
||||
@normalized_authority = nil
|
||||
@port = nil
|
||||
@normalized_password = NONE
|
||||
@host = nil
|
||||
@normalized_host = nil
|
||||
@normalized_port = NONE
|
||||
@path = EMPTY_STR
|
||||
@normalized_path = nil
|
||||
@normalized_query = NONE
|
||||
@fragment = nil
|
||||
@normalized_fragment = NONE
|
||||
@query = nil
|
||||
end
|
||||
|
||||
NONE = Object.new.freeze
|
||||
|
||||
private_constant :NONE
|
||||
end
|
||||
end
|
@ -23,7 +23,7 @@ if !defined?(Addressable::VERSION)
|
||||
module VERSION
|
||||
MAJOR = 2
|
||||
MINOR = 8
|
||||
TINY = 1
|
||||
TINY = 2
|
||||
|
||||
STRING = [MAJOR, MINOR, TINY].join('.')
|
||||
end
|
@ -2,6 +2,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "pkg_version"
|
||||
require "version/head"
|
||||
require "version/null"
|
||||
require "version/parser"
|
||||
|
||||
@ -532,6 +533,19 @@ class Version
|
||||
false
|
||||
end
|
||||
|
||||
sig { params(comparator: String, other: Version).returns(T::Boolean) }
|
||||
def compare(comparator, other)
|
||||
case comparator
|
||||
when ">=" then self >= other
|
||||
when ">" then self > other
|
||||
when "<" then self < other
|
||||
when "<=" then self <= other
|
||||
when "==" then self == other
|
||||
when "!=" then self != other
|
||||
else raise ArgumentError, "Unknown comparator: #{comparator}"
|
||||
end
|
||||
end
|
||||
|
||||
sig { params(other: T.untyped).returns(T.nilable(Integer)) }
|
||||
def <=>(other)
|
||||
# Needed to retain API compatibility with older string comparisons
|
||||
@ -663,34 +677,3 @@ class Version
|
||||
version.scan(SCAN_PATTERN).map { |token| Token.create(T.cast(token, String)) }
|
||||
end
|
||||
end
|
||||
|
||||
# A formula's HEAD version.
|
||||
# @see https://docs.brew.sh/Formula-Cookbook#unstable-versions-head Unstable versions (head)
|
||||
#
|
||||
# @api private
|
||||
class HeadVersion < Version
|
||||
extend T::Sig
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
attr_reader :commit
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@commit = @version[/^HEAD-(.+)$/, 1]
|
||||
end
|
||||
|
||||
sig { params(commit: T.nilable(String)).void }
|
||||
def update_commit(commit)
|
||||
@commit = commit
|
||||
@version = if commit
|
||||
"HEAD-#{commit}"
|
||||
else
|
||||
"HEAD"
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def head?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
35
Library/Homebrew/version/head.rb
Normal file
35
Library/Homebrew/version/head.rb
Normal file
@ -0,0 +1,35 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Version
|
||||
# A formula's HEAD version.
|
||||
# @see https://docs.brew.sh/Formula-Cookbook#unstable-versions-head Unstable versions (head)
|
||||
#
|
||||
# @api private
|
||||
class HeadVersion < Version
|
||||
extend T::Sig
|
||||
|
||||
sig { returns(T.nilable(String)) }
|
||||
attr_reader :commit
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@commit = @version[/^HEAD-(.+)$/, 1]
|
||||
end
|
||||
|
||||
sig { params(commit: T.nilable(String)).void }
|
||||
def update_commit(commit)
|
||||
@commit = commit
|
||||
@version = if commit
|
||||
"HEAD-#{commit}"
|
||||
else
|
||||
"HEAD"
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def head?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
@ -882,7 +882,7 @@ There are two ways to add `launchd` plists and `systemd` services to a formula,
|
||||
|
||||
```ruby
|
||||
service do
|
||||
run bin/"script"
|
||||
run opt_bin/"script"
|
||||
end
|
||||
```
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user