2024-08-12 10:30:59 +01:00
|
|
|
# typed: true # rubocop:todo Sorbet/StrictSigil
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2024-07-14 08:49:39 -04:00
|
|
|
require "context"
|
2009-10-15 14:42:19 +01:00
|
|
|
|
2010-01-13 09:00:51 +00:00
|
|
|
module Homebrew
|
2020-08-02 14:32:31 +02:00
|
|
|
extend Context
|
|
|
|
|
2023-03-06 09:49:53 -08:00
|
|
|
def self._system(cmd, *args, **options)
|
2014-03-29 02:24:01 -05:00
|
|
|
pid = fork do
|
2010-01-13 09:00:51 +00:00
|
|
|
yield if block_given?
|
2018-09-02 20:14:54 +01:00
|
|
|
args.map!(&:to_s)
|
2016-09-11 17:47:04 +01:00
|
|
|
begin
|
2018-05-21 01:43:42 +02:00
|
|
|
exec(cmd, *args, **options)
|
2016-09-11 17:47:04 +01:00
|
|
|
rescue
|
|
|
|
nil
|
|
|
|
end
|
2010-01-13 09:00:51 +00:00
|
|
|
exit! 1 # never gets here unless exec failed
|
|
|
|
end
|
2020-11-23 18:15:48 +01:00
|
|
|
Process.wait(T.must(pid))
|
2017-06-10 20:12:55 +03:00
|
|
|
$CHILD_STATUS.success?
|
2010-01-13 09:00:51 +00:00
|
|
|
end
|
2014-06-30 19:15:03 -05:00
|
|
|
|
2023-03-06 09:49:53 -08:00
|
|
|
def self.system(cmd, *args, **options)
|
2020-08-02 14:32:31 +02:00
|
|
|
if verbose?
|
2023-10-28 23:41:01 -07:00
|
|
|
out = (options[:out] == :err) ? $stderr : $stdout
|
|
|
|
out.puts "#{cmd} #{args * " "}".gsub(RUBY_PATH, "ruby")
|
|
|
|
.gsub($LOAD_PATH.join(File::PATH_SEPARATOR).to_s, "$LOAD_PATH")
|
2019-11-06 14:59:27 +00:00
|
|
|
end
|
2018-05-21 01:43:42 +02:00
|
|
|
_system(cmd, *args, **options)
|
2015-09-08 16:06:39 +08:00
|
|
|
end
|
|
|
|
|
2025-01-29 09:17:01 +00:00
|
|
|
# `Module` and `Regexp` are global variables used as types here so they don't need to be imported
|
2017-10-07 00:31:28 +02:00
|
|
|
# rubocop:disable Style/GlobalVars
|
2023-02-27 11:43:16 -08:00
|
|
|
sig { params(the_module: Module, pattern: Regexp).void }
|
2023-03-06 09:49:53 -08:00
|
|
|
def self.inject_dump_stats!(the_module, pattern)
|
2017-10-07 00:31:28 +02:00
|
|
|
@injected_dump_stat_modules ||= {}
|
2016-09-26 01:44:51 +02:00
|
|
|
@injected_dump_stat_modules[the_module] ||= []
|
|
|
|
injected_methods = @injected_dump_stat_modules[the_module]
|
2016-04-18 17:39:21 -04:00
|
|
|
the_module.module_eval do
|
|
|
|
instance_methods.grep(pattern).each do |name|
|
|
|
|
next if injected_methods.include? name
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-04-18 17:39:21 -04:00
|
|
|
method = instance_method(name)
|
|
|
|
define_method(name) do |*args, &block|
|
2024-07-14 08:49:39 -04:00
|
|
|
require "time"
|
|
|
|
|
2019-10-13 10:03:26 +01:00
|
|
|
time = Time.now
|
2020-11-23 18:15:48 +01:00
|
|
|
|
|
|
|
begin
|
2024-02-22 23:52:46 +00:00
|
|
|
method.bind_call(self, *args, &block)
|
2020-11-23 18:15:48 +01:00
|
|
|
ensure
|
|
|
|
$times[name] ||= 0
|
|
|
|
$times[name] += Time.now - time
|
|
|
|
end
|
2016-04-18 17:39:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-09-23 22:02:23 +02:00
|
|
|
return unless $times.nil?
|
2018-09-17 02:45:00 +02:00
|
|
|
|
2016-09-23 22:02:23 +02:00
|
|
|
$times = {}
|
|
|
|
at_exit do
|
2019-01-22 14:20:24 +00:00
|
|
|
col_width = [$times.keys.map(&:size).max.to_i + 2, 15].max
|
2016-09-23 22:02:23 +02:00
|
|
|
$times.sort_by { |_k, v| v }.each do |method, time|
|
2024-03-07 16:20:20 +00:00
|
|
|
puts format("%<method>-#{col_width}s %<time>0.4f sec", method: "#{method}:", time:)
|
2016-04-18 17:39:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-10-07 00:31:28 +02:00
|
|
|
# rubocop:enable Style/GlobalVars
|
2010-01-13 09:00:51 +00:00
|
|
|
end
|
2023-02-27 20:20:56 -08:00
|
|
|
|
|
|
|
module Utils
|
|
|
|
# Removes the rightmost segment from the constant expression in the string.
|
|
|
|
#
|
|
|
|
# deconstantize('Net::HTTP') # => "Net"
|
|
|
|
# deconstantize('::Net::HTTP') # => "::Net"
|
|
|
|
# deconstantize('String') # => ""
|
|
|
|
# deconstantize('::String') # => ""
|
|
|
|
# deconstantize('') # => ""
|
|
|
|
#
|
|
|
|
# See also #demodulize.
|
|
|
|
# @see https://github.com/rails/rails/blob/b0dd7c7/activesupport/lib/active_support/inflector/methods.rb#L247-L258
|
|
|
|
# `ActiveSupport::Inflector.deconstantize`
|
|
|
|
sig { params(path: String).returns(String) }
|
|
|
|
def self.deconstantize(path)
|
|
|
|
T.must(path[0, path.rindex("::") || 0]) # implementation based on the one in facets' Module#spacename
|
|
|
|
end
|
|
|
|
|
|
|
|
# Removes the module part from the expression in the string.
|
|
|
|
#
|
|
|
|
# demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
|
|
|
|
# demodulize('Inflections') # => "Inflections"
|
|
|
|
# demodulize('::Inflections') # => "Inflections"
|
|
|
|
# demodulize('') # => ""
|
|
|
|
#
|
|
|
|
# See also #deconstantize.
|
|
|
|
# @see https://github.com/rails/rails/blob/b0dd7c7/activesupport/lib/active_support/inflector/methods.rb#L230-L245
|
|
|
|
# `ActiveSupport::Inflector.demodulize`
|
2025-02-23 11:08:00 -08:00
|
|
|
# @raise [ArgumentError] if the provided path is nil
|
|
|
|
sig { params(path: T.nilable(String)).returns(String) }
|
2023-02-27 20:20:56 -08:00
|
|
|
def self.demodulize(path)
|
2025-02-23 11:08:00 -08:00
|
|
|
raise ArgumentError, "No constant path provided" if path.nil?
|
|
|
|
|
2023-02-27 20:20:56 -08:00
|
|
|
if (i = path.rindex("::"))
|
|
|
|
T.must(path[(i + 2)..])
|
|
|
|
else
|
|
|
|
path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# A lightweight alternative to `ActiveSupport::Inflector.pluralize`:
|
|
|
|
# Combines `stem` with the `singular` or `plural` suffix based on `count`.
|
2023-03-20 07:23:17 -04:00
|
|
|
# Adds a prefix of the count value if `include_count` is set to true.
|
2023-03-19 23:10:47 -04:00
|
|
|
sig {
|
2023-03-20 07:23:17 -04:00
|
|
|
params(stem: String, count: Integer, plural: String, singular: String, include_count: T::Boolean).returns(String)
|
2023-03-19 23:10:47 -04:00
|
|
|
}
|
2023-03-20 07:23:17 -04:00
|
|
|
def self.pluralize(stem, count, plural: "s", singular: "", include_count: false)
|
|
|
|
prefix = include_count ? "#{count} " : ""
|
2023-02-27 20:20:56 -08:00
|
|
|
suffix = (count == 1) ? singular : plural
|
2023-03-19 23:10:47 -04:00
|
|
|
"#{prefix}#{stem}#{suffix}"
|
2023-02-27 20:20:56 -08:00
|
|
|
end
|
2023-03-07 10:11:59 -08:00
|
|
|
|
2023-03-14 10:23:29 -07:00
|
|
|
sig { params(author: String).returns({ email: String, name: String }) }
|
|
|
|
def self.parse_author!(author)
|
|
|
|
match_data = /^(?<name>[^<]+?)[ \t]*<(?<email>[^>]+?)>$/.match(author)
|
|
|
|
if match_data
|
|
|
|
name = match_data[:name]
|
|
|
|
email = match_data[:email]
|
|
|
|
end
|
|
|
|
raise UsageError, "Unable to parse name and email." if name.blank? && email.blank?
|
|
|
|
|
|
|
|
{ name: T.must(name), email: T.must(email) }
|
|
|
|
end
|
|
|
|
|
2023-03-07 10:11:59 -08:00
|
|
|
# Makes an underscored, lowercase form from the expression in the string.
|
|
|
|
#
|
|
|
|
# Changes '::' to '/' to convert namespaces to paths.
|
|
|
|
#
|
|
|
|
# underscore('ActiveModel') # => "active_model"
|
|
|
|
# underscore('ActiveModel::Errors') # => "active_model/errors"
|
|
|
|
#
|
|
|
|
# @see https://github.com/rails/rails/blob/v6.1.7.2/activesupport/lib/active_support/inflector/methods.rb#L81-L100
|
|
|
|
# `ActiveSupport::Inflector.underscore`
|
|
|
|
sig { params(camel_cased_word: T.any(String, Symbol)).returns(String) }
|
|
|
|
def self.underscore(camel_cased_word)
|
2023-03-07 10:45:53 -08:00
|
|
|
return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
|
2023-03-07 10:14:57 -08:00
|
|
|
|
2023-03-07 10:11:59 -08:00
|
|
|
word = camel_cased_word.to_s.gsub("::", "/")
|
2023-03-07 10:14:57 -08:00
|
|
|
word.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) do
|
2023-03-07 10:45:53 -08:00
|
|
|
T.must(::Regexp.last_match(1) || ::Regexp.last_match(2)) << "_"
|
2023-03-07 10:14:57 -08:00
|
|
|
end
|
2023-03-07 10:11:59 -08:00
|
|
|
word.tr!("-", "_")
|
|
|
|
word.downcase!
|
|
|
|
word
|
|
|
|
end
|
2024-01-01 17:46:48 +00:00
|
|
|
|
|
|
|
SAFE_FILENAME_REGEX = /[[:cntrl:]#{Regexp.escape("#{File::SEPARATOR}#{File::ALT_SEPARATOR}")}]/o
|
|
|
|
private_constant :SAFE_FILENAME_REGEX
|
|
|
|
|
|
|
|
sig { params(basename: String).returns(T::Boolean) }
|
|
|
|
def self.safe_filename?(basename)
|
|
|
|
!SAFE_FILENAME_REGEX.match?(basename)
|
|
|
|
end
|
|
|
|
|
|
|
|
sig { params(basename: String).returns(String) }
|
|
|
|
def self.safe_filename(basename)
|
|
|
|
basename.gsub(SAFE_FILENAME_REGEX, "")
|
|
|
|
end
|
2023-02-27 20:20:56 -08:00
|
|
|
end
|