diff --git a/Library/Homebrew/cask/audit.rb b/Library/Homebrew/cask/audit.rb index 56f7f1e3de..70412cce30 100644 --- a/Library/Homebrew/cask/audit.rb +++ b/Library/Homebrew/cask/audit.rb @@ -381,12 +381,15 @@ module Cask sig { void } def audit_token_conflicts return unless token_conflicts? - return unless core_formula_names.include?(cask.token) - add_error( - "possible duplicate, cask token conflicts with Homebrew core formula: #{Formatter.url(core_formula_url)}", - strict_only: true, - ) + Homebrew.with_no_api_env do + return unless core_formula_names.include?(cask.token) + + add_error( + "possible duplicate, cask token conflicts with Homebrew core formula: #{Formatter.url(core_formula_url)}", + strict_only: true, + ) + end end sig { void } @@ -846,7 +849,10 @@ module Cask sig { returns(String) } def core_formula_url - "#{core_tap.default_remote}/blob/HEAD/Formula/#{cask.token}.rb" + formula_path = Formulary.core_path(cask.token) + .to_s + .delete_prefix(core_tap.path.to_s) + "#{core_tap.default_remote}/blob/HEAD/Formula/#{formula_path}" end end end diff --git a/Library/Homebrew/cask/cask_loader.rb b/Library/Homebrew/cask/cask_loader.rb index bcf12b04d2..c343f491db 100644 --- a/Library/Homebrew/cask/cask_loader.rb +++ b/Library/Homebrew/cask/cask_loader.rb @@ -439,7 +439,7 @@ module Cask end def self.default_path(token) - CoreCaskTap.instance.cask_dir/"#{token.to_s.downcase}.rb" + find_cask_in_tap(token.to_s.downcase, CoreCaskTap.instance) end def self.tap_paths(token, warn: true) @@ -455,7 +455,8 @@ module Cask def self.find_cask_in_tap(token, tap) filename = "#{token}.rb" - Tap.cask_files_by_name(tap).fetch(filename, tap.cask_dir/filename) + Tap.cask_files_by_name(tap) + .fetch(token, tap.cask_dir/filename) end end end diff --git a/Library/Homebrew/cli/named_args.rb b/Library/Homebrew/cli/named_args.rb index 37ffa4bbcb..98ab981c18 100644 --- a/Library/Homebrew/cli/named_args.rb +++ b/Library/Homebrew/cli/named_args.rb @@ -227,40 +227,42 @@ module Homebrew sig { params(only: T.nilable(Symbol), recurse_tap: T::Boolean).returns(T::Array[Pathname]) } def to_paths(only: parent&.only_formula_or_cask, recurse_tap: false) @to_paths ||= {} - @to_paths[only] ||= downcased_unique_named.flat_map do |name| - path = Pathname(name) - if File.exist?(name) - path - elsif name.count("/") == 1 && !name.start_with?("./", "/") - tap = Tap.fetch(name) + @to_paths[only] ||= Homebrew.with_no_api_env_if_needed(@without_api) do + downcased_unique_named.flat_map do |name| + path = Pathname(name) + if File.exist?(name) + path + elsif name.count("/") == 1 && !name.start_with?("./", "/") + tap = Tap.fetch(name) - if recurse_tap - next tap.formula_files if only == :formula - next tap.cask_files if only == :cask + if recurse_tap + next tap.formula_files if only == :formula + next tap.cask_files if only == :cask + end + + tap.path + else + next Formulary.path(name) if only == :formula + next Cask::CaskLoader.path(name) if only == :cask + + formula_path = Formulary.path(name) + cask_path = Cask::CaskLoader.path(name) + + paths = [] + + if formula_path.exist? || + (!CoreTap.instance.installed? && Homebrew::API::Formula.all_formulae.key?(path.basename)) + paths << formula_path + end + if cask_path.exist? || + (!CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(path.basename)) + paths << cask_path + end + + paths.empty? ? path : paths end - - tap.path - else - next Formulary.path(name) if only == :formula - next Cask::CaskLoader.path(name) if only == :cask - - formula_path = Formulary.path(name) - cask_path = Cask::CaskLoader.path(name) - - paths = [] - - if formula_path.exist? || - (!CoreTap.instance.installed? && Homebrew::API::Formula.all_formulae.key?(path.basename)) - paths << formula_path - end - if cask_path.exist? || - (!CoreCaskTap.instance.installed? && Homebrew::API::Cask.all_casks.key?(path.basename)) - paths << cask_path - end - - paths.empty? ? path : paths - end - end.uniq.freeze + end.uniq.freeze + end end sig { returns(T::Array[Keg]) } diff --git a/Library/Homebrew/cmd/log.rb b/Library/Homebrew/cmd/log.rb index a0f56165b4..35a6033de6 100644 --- a/Library/Homebrew/cmd/log.rb +++ b/Library/Homebrew/cmd/log.rb @@ -29,7 +29,7 @@ module Homebrew conflicts "-1", "--max-count" conflicts "--formula", "--cask" - named_args [:formula, :cask], max: 1 + named_args [:formula, :cask], max: 1, without_api: true end end diff --git a/Library/Homebrew/dev-cmd/create.rb b/Library/Homebrew/dev-cmd/create.rb index e0e3c5d5e1..f02b61769a 100644 --- a/Library/Homebrew/dev-cmd/create.rb +++ b/Library/Homebrew/dev-cmd/create.rb @@ -96,7 +96,7 @@ module Homebrew cask_tap = Tap.fetch(args.tap || "homebrew/cask") raise TapUnavailableError, cask_tap.name unless cask_tap.installed? - cask_path = Cask::CaskLoader.path("#{cask_tap}/#{token}") + cask_path = cask_tap.new_cask_path(token) cask_path.dirname.mkpath unless cask_path.dirname.exist? raise Cask::CaskAlreadyCreatedError, token if cask_path.exist? diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb index 58ab33a0b2..9b17567d75 100644 --- a/Library/Homebrew/dev-cmd/extract.rb +++ b/Library/Homebrew/dev-cmd/extract.rb @@ -114,7 +114,7 @@ module Homebrew repo = source_tap.path pattern = if source_tap.core_tap? - [repo/"Formula/#{name}.rb"] + [source_tap.new_formula_path(name), repo/"Formula/#{name}.rb"].uniq else # A formula can technically live in the root directory of a tap or in any of its subdirectories [repo/"#{name}.rb", repo/"**/#{name}.rb"] diff --git a/Library/Homebrew/dev-cmd/pr-pull.rb b/Library/Homebrew/dev-cmd/pr-pull.rb index 479167bdc4..82a60194c7 100644 --- a/Library/Homebrew/dev-cmd/pr-pull.rb +++ b/Library/Homebrew/dev-cmd/pr-pull.rb @@ -110,7 +110,7 @@ module Homebrew end def self.get_package(tap, subject_name, subject_path, content) - if subject_path.dirname == tap.cask_dir + if subject_path.to_s.start_with?("#{tap.cask_dir}/") cask = begin Cask::CaskLoader.load(content.dup) rescue Cask::CaskUnavailableError @@ -130,7 +130,7 @@ module Homebrew subject_path = Pathname(subject_path) tap = Tap.from_path(subject_path) subject_name = subject_path.basename.to_s.chomp(".rb") - is_cask = subject_path.dirname == tap.cask_dir + is_cask = subject_path.to_s.start_with?("#{tap.cask_dir}/") name = is_cask ? "cask" : "formula" new_package = get_package(tap, subject_name, subject_path, new_contents) @@ -241,8 +241,8 @@ module Homebrew files.each do |file| files_to_commits[file] ||= [] files_to_commits[file] << commit - tap_file = tap.path/file - if (tap_file.dirname == tap.formula_dir || tap_file.dirname == tap.cask_dir) && + tap_file = (tap.path/file).to_s + if (tap_file.start_with?("#{tap.formula_dir}/") || tap_file.start_with?("#{tap.cask_dir}/")) && File.extname(file) == ".rb" next end diff --git a/Library/Homebrew/formula_creator.rb b/Library/Homebrew/formula_creator.rb index dd4a3701ef..d5e8dc92c6 100644 --- a/Library/Homebrew/formula_creator.rb +++ b/Library/Homebrew/formula_creator.rb @@ -45,7 +45,7 @@ module Homebrew def update_path return if @name.nil? || @tap.nil? - @path = Formulary.path "#{@tap}/#{@name}" + @path = @tap.new_formula_path(@name) end def fetch? diff --git a/Library/Homebrew/formula_path.sh b/Library/Homebrew/formula_path.sh index bab691b2c7..c23174971c 100644 --- a/Library/Homebrew/formula_path.sh +++ b/Library/Homebrew/formula_path.sh @@ -49,7 +49,7 @@ homebrew-formula-path() { local formula_path formula_path="$( shopt -s nullglob - echo "${HOMEBREW_REPOSITORY}/Library/Taps"/*/*/{Formula/,HomebrewFormula/,}"${formula}.rb" + echo "${HOMEBREW_REPOSITORY}/Library/Taps"/*/*/{Formula/,HomebrewFormula/,Formula/*/,}"${formula}.rb" )" [[ -n "${formula_path}" ]] && formula_exists="1" fi diff --git a/Library/Homebrew/formulary.rb b/Library/Homebrew/formulary.rb index cd014e72f3..0123a79b3e 100644 --- a/Library/Homebrew/formulary.rb +++ b/Library/Homebrew/formulary.rb @@ -1003,10 +1003,15 @@ module Formulary end.select(&:file?) end + sig { params(name: String, tap: Tap).returns(Pathname) } def self.find_formula_in_tap(name, tap) - filename = name.dup - filename << ".rb" unless filename.end_with?(".rb") + filename = if name.end_with?(".rb") + name + else + "#{name}.rb" + end - Tap.formula_files_by_name(tap).fetch(filename, tap.formula_dir/filename) + Tap.formula_files_by_name(tap) + .fetch(name, tap.formula_dir/filename) end end diff --git a/Library/Homebrew/readall.rb b/Library/Homebrew/readall.rb index 09f5f75861..a165a4351f 100644 --- a/Library/Homebrew/readall.rb +++ b/Library/Homebrew/readall.rb @@ -31,7 +31,7 @@ module Readall failed = true end - if (formula_dir/"#{f.basename}.rb").exist? + if formula_dir.glob("**/#{f.basename}.rb").any?(&:exist?) onoe "Formula duplicating alias: #{f}" failed = true end diff --git a/Library/Homebrew/tap.rb b/Library/Homebrew/tap.rb index 73a71a29e8..0af9421b5c 100644 --- a/Library/Homebrew/tap.rb +++ b/Library/Homebrew/tap.rb @@ -500,12 +500,22 @@ class Tap @potential_formula_dirs ||= [path/"Formula", path/"HomebrewFormula", path].freeze end + sig { params(name: String).returns(Pathname) } + def new_formula_path(name) + formula_dir/"#{name.downcase}.rb" + end + # Path to the directory of all {Cask} files for this {Tap}. sig { returns(Pathname) } def cask_dir @cask_dir ||= path/"Casks" end + sig { params(token: String).returns(Pathname) } + def new_cask_path(token) + cask_dir/"#{token.downcase}.rb" + end + def contents contents = [] @@ -555,7 +565,7 @@ class Tap formula_files.each_with_object({}) do |file, hash| # If there's more than one file with the same basename: intentionally # ignore the later ones here. - hash[file.basename.to_s] ||= file + hash[file.basename(".rb").to_s] ||= file end end @@ -584,7 +594,7 @@ class Tap cask_files.each_with_object({}) do |file, hash| # If there's more than one file with the same basename: intentionally # ignore the later ones here. - hash[file.basename.to_s] ||= file + hash[file.basename(".rb").to_s] ||= file end end @@ -984,6 +994,19 @@ class CoreTap < AbstractCoreTap end end + sig { params(name: String).returns(Pathname) } + def new_formula_path(name) + formula_subdir = if name.start_with?("lib") + "lib" + else + name[0].to_s + end + + return super unless (formula_dir/formula_subdir).directory? + + formula_dir/formula_subdir/"#{name.downcase}.rb" + end + # @private sig { returns(Pathname) } def alias_dir @@ -1108,6 +1131,15 @@ class CoreCaskTap < AbstractCoreTap true end + sig { params(token: String).returns(Pathname) } + def new_cask_path(token) + cask_subdir = token[0].to_s + + return super unless (cask_dir/cask_subdir).directory? + + cask_dir/cask_subdir/"#{token.downcase}.rb" + end + sig { override.returns(T::Array[Pathname]) } def cask_files return super if Homebrew::EnvConfig.no_install_from_api? || installed? diff --git a/Library/Homebrew/test/cleanup_spec.rb b/Library/Homebrew/test/cleanup_spec.rb index 345a6c5c99..00054edaf0 100644 --- a/Library/Homebrew/test/cleanup_spec.rb +++ b/Library/Homebrew/test/cleanup_spec.rb @@ -333,7 +333,7 @@ describe Homebrew::Cleanup do FileUtils.touch testball FileUtils.touch testball_resource (HOMEBREW_CELLAR/"testball"/"0.0.1").mkpath - FileUtils.touch(CoreTap.instance.formula_dir/"testball.rb") + FileUtils.touch(CoreTap.instance.new_formula_path("testball")) end it "cleans up file if outdated" do diff --git a/Library/Homebrew/test/dev-cmd/create_spec.rb b/Library/Homebrew/test/dev-cmd/create_spec.rb index 68589217f9..e0026dd19f 100644 --- a/Library/Homebrew/test/dev-cmd/create_spec.rb +++ b/Library/Homebrew/test/dev-cmd/create_spec.rb @@ -4,7 +4,7 @@ require "cmd/shared_examples/args_parse" describe "brew create" do let(:url) { "file://#{TEST_FIXTURE_DIR}/tarballs/testball-0.1.tbz" } - let(:formula_file) { CoreTap.new.formula_dir/"testball.rb" } + let(:formula_file) { CoreTap.new.new_formula_path("testball") } it_behaves_like "parseable arguments" diff --git a/Library/Homebrew/test/formula_installer_spec.rb b/Library/Homebrew/test/formula_installer_spec.rb index 49404f8208..b9c8ae33a1 100644 --- a/Library/Homebrew/test/formula_installer_spec.rb +++ b/Library/Homebrew/test/formula_installer_spec.rb @@ -82,7 +82,7 @@ describe FormulaInstaller do ENV["HOMEBREW_DEVELOPER"] = "1" dep_name = "homebrew-test-cyclic" - dep_path = CoreTap.new.formula_dir/"#{dep_name}.rb" + dep_path = CoreTap.new.new_formula_path(dep_name) dep_path.write <<~RUBY class #{Formulary.class_s(dep_name)} < Formula url "foo" @@ -105,7 +105,7 @@ describe FormulaInstaller do formula1_name = "homebrew-test-formula1" formula2_name = "homebrew-test-formula2" - formula1_path = CoreTap.new.formula_dir/"#{formula1_name}.rb" + formula1_path = CoreTap.new.new_formula_path(formula1_name) formula1_path.write <<~RUBY class #{Formulary.class_s(formula1_name)} < Formula url "foo" @@ -116,7 +116,7 @@ describe FormulaInstaller do Formulary.cache.delete(formula1_path) formula1 = Formulary.factory(formula1_name) - formula2_path = CoreTap.new.formula_dir/"#{formula2_name}.rb" + formula2_path = CoreTap.new.new_formula_path(formula2_name) formula2_path.write <<~RUBY class #{Formulary.class_s(formula2_name)} < Formula url "foo" @@ -135,7 +135,7 @@ describe FormulaInstaller do it "raises on pinned dependency" do dep_name = "homebrew-test-dependency" - dep_path = CoreTap.new.formula_dir/"#{dep_name}.rb" + dep_path = CoreTap.new.new_formula_path(dep_name) dep_path.write <<~RUBY class #{Formulary.class_s(dep_name)} < Formula url "foo" diff --git a/Library/Homebrew/test/formula_spec.rb b/Library/Homebrew/test/formula_spec.rb index c8e3fb4c78..5f4a6765d4 100644 --- a/Library/Homebrew/test/formula_spec.rb +++ b/Library/Homebrew/test/formula_spec.rb @@ -429,7 +429,7 @@ describe Formula do example "alias paths with tab with non alias source path" do alias_path = (CoreTap.instance.alias_dir/"another_name") - source_path = (CoreTap.instance.formula_dir/"another_other_name") + source_path = CoreTap.instance.new_formula_path("another_other_name") f = formula alias_path: alias_path do url "foo-1.0" @@ -940,7 +940,7 @@ describe Formula do end describe "#to_hash_with_variations", :needs_macos do - let(:formula_path) { CoreTap.new.formula_dir/"foo-variations.rb" } + let(:formula_path) { CoreTap.new.new_formula_path("foo-variations") } let(:formula_content) do <<~RUBY class FooVariations < Formula diff --git a/Library/Homebrew/test/formulary_spec.rb b/Library/Homebrew/test/formulary_spec.rb index ad81b0aa83..7c237cc4b4 100644 --- a/Library/Homebrew/test/formulary_spec.rb +++ b/Library/Homebrew/test/formulary_spec.rb @@ -6,7 +6,7 @@ require "utils/bottles" describe Formulary do let(:formula_name) { "testball_bottle" } - let(:formula_path) { CoreTap.new.formula_dir/"#{formula_name}.rb" } + let(:formula_path) { CoreTap.new.new_formula_path(formula_name) } let(:formula_content) do <<~RUBY class #{described_class.class_s(formula_name)} < Formula @@ -84,7 +84,11 @@ describe Formulary do before { CoreTap.instance.clear_cache } let(:formula_name) { "testball_sharded" } - let(:formula_path) { CoreTap.new.formula_dir/formula_name[0]/"#{formula_name}.rb" } + let(:formula_path) do + core_tap = CoreTap.new + (core_tap.formula_dir/formula_name[0]).mkpath + core_tap.new_formula_path(formula_name) + end it "returns a Formula" do expect(described_class.factory(formula_name)).to be_a(Formula) diff --git a/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb b/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb index b005657977..9dcbf60b31 100644 --- a/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb +++ b/Library/Homebrew/test/support/helper/spec/shared_examples/formulae_exist.rb @@ -4,9 +4,9 @@ shared_examples "formulae exist" do |array| array.each do |f| it "#{f} formula exists" do core_tap = Pathname("#{HOMEBREW_LIBRARY_PATH}/../Taps/homebrew/homebrew-core") - formula_path = core_tap/"Formula/#{f}.rb" + formula_paths = core_tap.glob("Formula/**/#{f}.rb") alias_path = core_tap/"Aliases/#{f}" - expect(formula_path.exist? || alias_path.exist?).to be true + expect(formula_paths.any?(&:exist?) || alias_path.exist?).to be true end end end