diff --git a/Library/Homebrew/test/utils/path_spec.rb b/Library/Homebrew/test/utils/path_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..72c2967de80214f0c3b28139bdd1a7dd895d460f --- /dev/null +++ b/Library/Homebrew/test/utils/path_spec.rb @@ -0,0 +1,33 @@ +# typed: false +# frozen_string_literal: true + +require "utils/path" + +describe Utils do + describe "::path_is_parent_of?" do + it "returns true when child path is a descendant of the parent" do + expect(described_class.path_is_parent_of?("/foo", "/foo/bar/baz")).to eq(true) + end + + it "returns false when child path is not a descendant of the parent" do + expect(described_class.path_is_parent_of?("/foo/bar/baz/qux", "/foo/bar")).to eq(false) + end + end + + describe "::shortened_brew_path" do + it "returns shortened path when the path can be expressed with the output of a brew command" do + expect(described_class.shortened_brew_path("#{HOMEBREW_PREFIX}/foo/bar")).to eq("$(brew --prefix)/foo/bar") + end + + it "returns shortened path with $(brew --prefix <formula>) when path is in a linked keg", :integration_test do + install_test_formula "testball" + f = Formula["testball"] + + expect(described_class.shortened_brew_path("#{f.opt_prefix}/main.c")).to eq("$(brew --prefix testball)/main.c") + end + + it "returns the original path when the path cannot be shortened" do + expect(described_class.shortened_brew_path("/foo/bar/baz")).to eq("/foo/bar/baz") + end + end +end diff --git a/Library/Homebrew/utils.rb b/Library/Homebrew/utils.rb index b041cfee9bfb6f173d3fc214839b18bd3bf9b6d4..de12d056b28a3301ee73d136dc512b9f7f659c0b 100644 --- a/Library/Homebrew/utils.rb +++ b/Library/Homebrew/utils.rb @@ -13,6 +13,7 @@ require "utils/git_repository" require "utils/github" require "utils/inreplace" require "utils/link" +require "utils/path" require "utils/popen" require "utils/repology" require "utils/svn" diff --git a/Library/Homebrew/utils/path.rb b/Library/Homebrew/utils/path.rb new file mode 100644 index 0000000000000000000000000000000000000000..5df02345df35ff0425de51ab145b8dc72fc07673 --- /dev/null +++ b/Library/Homebrew/utils/path.rb @@ -0,0 +1,51 @@ +# typed: strict +# frozen_string_literal: true + +# Helper functions for working with paths +module Utils + extend T::Sig + + # Checks if a a child path is a descendant of a given parent path + sig { params(parent_path: T.any(String, Pathname), child_path: T.any(String, Pathname)).returns(T::Boolean) } + def self.path_is_parent_of?(parent_path, child_path) + parent_component_array = Pathname(parent_path).each_filename.to_a + child_component_array = Pathname(child_path).each_filename.to_a + + child_component_array.first(parent_component_array.length) == parent_component_array + end + + # Gets a condensed short brew path for a given path, or the original path if it cannot be condensed + sig { params(long_path: T.any(String, Pathname)).returns(String) } + def self.shortened_brew_path(long_path) + short_path = long_path.to_s + long_path = Pathname(long_path) + + if long_path.exist? + begin + k = Keg.for(long_path) + opt_record = k.opt_record + formula_name = k.to_formula.name + rescue FormulaUnavailableError, NotAKegError + nil + else + short_path = short_path.sub(/\A#{Regexp.escape(opt_record.to_s)}/, "$(brew --prefix #{formula_name})") + end + end + + try_paths = { + HOMEBREW_CACHE => "--cache", + HOMEBREW_CELLAR => "--cellar", + HOMEBREW_REPOSITORY => "--repository", + HOMEBREW_PREFIX => "--prefix", + } + + try_paths.each do |try_path, flag| + if path_is_parent_of?(try_path, long_path) + short_path = short_path.sub(/\A#{Regexp.escape(try_path.to_s)}/, "$(brew #{flag})") + break + end + end + + short_path + end +end