diff --git a/Library/Homebrew/dev-cmd/extract.rb b/Library/Homebrew/dev-cmd/extract.rb index d6c1bae817c825fb237de06a793bc88440bd4441..fb8aa976a6631f36c072eef20c809f0507c80d2c 100644 --- a/Library/Homebrew/dev-cmd/extract.rb +++ b/Library/Homebrew/dev-cmd/extract.rb @@ -81,7 +81,8 @@ module Homebrew Look through repository history to find the most recent version of <formula> and create a copy in <tap>`/Formula/`<formula>`@`<version>`.rb`. If the tap is not - installed yet, attempt to install/clone the tap before continuing. + installed yet, attempt to install/clone the tap before continuing. To extract + a <formula> from a tap that is not homebrew/core use <user>/<repo>/<formula>. EOS flag "--version=", @@ -112,7 +113,12 @@ module Homebrew destination_tap.install unless destination_tap.installed? repo = source_tap.path - pattern = source_tap.core_tap? ? repo/"Formula/#{name}.rb" : repo/"{,**/}#{name}.rb" + pattern = if source_tap.core_tap? + [repo/"Formula/#{name}.rb"] + 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"] + end if args.version ohai "Searching repository history" @@ -138,6 +144,7 @@ module Homebrew end odie "Could not find #{name}! The formula or version may not have existed." if test_formula.nil? else + # Search in the root directory of <repo> as well as recursively in all of its subdirectories files = Dir[repo/"{,**/}"].map do |dir| Pathname.glob(["#{dir}/#{name}.rb"]).find(&:file?) end.compact diff --git a/Library/Homebrew/test/dev-cmd/extract_spec.rb b/Library/Homebrew/test/dev-cmd/extract_spec.rb index b905108e3c6628e1b97a286e72b7f88905ae6292..59e7cc19059cc7c0f2f3afa36c4c60e3bda28bad 100644 --- a/Library/Homebrew/test/dev-cmd/extract_spec.rb +++ b/Library/Homebrew/test/dev-cmd/extract_spec.rb @@ -1,5 +1,5 @@ describe "brew extract", :integration_test do - it "retrieves the specified version of formula from core tap, defaulting to most recent" do + it "retrieves the specified version of formula, defaulting to most recent" do path = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" (path/"Formula").mkpath target = Tap.from_path(path) @@ -29,69 +29,4 @@ describe "brew extract", :integration_test do expect(Formulary.factory(path/"Formula/testball@0.1.rb").version).to be == "0.1" end - - it "retrieves the specified version of formula from a tap other than core, defaulting to most recent" do - destination = Tap::TAP_DIRECTORY/"homebrew/homebrew-foo" - (destination/"Formula").mkpath - destination_tap = Tap.from_path(destination) - - source = Tap::TAP_DIRECTORY/"homebrew/homebrew-bar" - source.mkpath - source_tap = Tap.from_path(source) - - tarball = if OS.linux? - TEST_FIXTURE_DIR/"tarballs/testball-0.1-linux.tbz" - else - TEST_FIXTURE_DIR/"tarballs/testball-0.1.tbz" - end - - content = <<~RUBY - desc "Some test" - homepage "https://brew.sh/testball" - url "file://#{tarball}" - sha256 "#{tarball.sha256}" - - option "with-foo", "Build with foo" - - def install - (prefix/"foo"/"test").write("test") if build.with? "foo" - prefix.install Dir["*"] - (buildpath/"test.c").write \ - "#include <stdio.h>\\nint main(){return printf(\\"test\\");}" - bin.mkpath - system ENV.cc, "test.c", "-o", bin/"test" - end - RUBY - - formula_file = source_tap.path/"testball.rb" - formula_file.write <<~RUBY - class Testball < Formula - #{content} - end - RUBY - - source_tap.path.cd do - system "git", "init" - system "git", "add", "--all" - system "git", "commit", "-m", "testball 0.1" - contents = File.read(formula_file) - contents.gsub!("testball-0.1", "testball-0.2") - File.write(formula_file, contents) - system "git", "add", "--all" - system "git", "commit", "-m", "testball 0.2" - end - expect { brew "extract", "homebrew/bar/testball", destination_tap.name } - .to be_a_success - - expect(destination/"Formula/testball@0.2.rb").to exist - - expect(Formulary.factory(destination/"Formula/testball@0.2.rb").version).to be == "0.2" - - expect { brew "extract", "homebrew/bar/testball", destination_tap.name, "--version=0.1" } - .to be_a_success - - expect(destination/"Formula/testball@0.1.rb").to exist - - expect(Formulary.factory(destination/"Formula/testball@0.1.rb").version).to be == "0.1" - end end diff --git a/Library/Homebrew/utils/git.rb b/Library/Homebrew/utils/git.rb index 5b71b9347165f6163ac3186f020d33199a717560..875b07dc13babddfa54834f493a8d75673d1617d 100644 --- a/Library/Homebrew/utils/git.rb +++ b/Library/Homebrew/utils/git.rb @@ -4,7 +4,11 @@ module Git module_function def last_revision_commit_of_file(repo, file, before_commit: nil) - args = [before_commit.nil? ? "--skip=1" : before_commit.split("..").first] + args = if before_commit.nil? + ["--skip=1"] + else + [before_commit.split("..").first] + end out, = Open3.capture3( HOMEBREW_SHIMS_PATH/"scm/git", "-C", repo, @@ -14,17 +18,26 @@ module Git out.chomp end - def last_revision_commit_of_files(repo, file, before_commit: nil) - args = [before_commit.nil? ? "--skip=1" : before_commit.split("..").first] + def last_revision_commit_of_files(repo, files, before_commit: nil) + args = if before_commit.nil? + ["--skip=1"] + else + [before_commit.split("..").first] + end - cmd = [ - HOMEBREW_SHIMS_PATH/"scm/git", "-C", repo, - "log", "--format=%h", "--abbrev=7", "--max-count=1", "--name-only", - *args, "--", file - ] - out, = Open3.capture3("/bin/bash", "-c", cmd.join(" ")) - rev, *files = out.chomp.split(/\n/).reject(&:empty?) - [rev, files] + # git log output format: + # <commit_hash> + # <file_path1> + # <file_path2> + # ... + # return [<commit_hash>, [file_path1, file_path2, ...]] + out, = Open3.capture3( + HOMEBREW_SHIMS_PATH/"scm/git", "-C", repo, "log", + "--pretty=format:%h", "--abbrev=7", "--max-count=1", + "--diff-filter=d", "--name-only", *args, "--", *files + ) + rev, *paths = out.chomp.split(/\n/).reject(&:empty?) + [rev, paths] end def last_revision_of_file(repo, file, before_commit: nil) diff --git a/docs/Manpage.md b/docs/Manpage.md index 9bb1e9789d72fc19de2ad127c9f4d07cdde4dc89..bf67269311a442d309f4f9ca249594f83dcdc9b6 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -785,7 +785,8 @@ Homebrew repository for editing if no *`formula`* is provided. Look through repository history to find the most recent version of *`formula`* and create a copy in *`tap`*`/Formula/`*`formula`*`@`*`version`*`.rb`. If the tap is not -installed yet, attempt to install/clone the tap before continuing. +installed yet, attempt to install/clone the tap before continuing. To extract a +*`formula`* from a tap that is not homebrew/core use *`user`*/*`repo`*/*`formula`*. * `--version`: Extract the provided *`version`* of *`formula`* instead of the most recent. diff --git a/manpages/brew.1 b/manpages/brew.1 index f15edcf778ee0008835fdd0147abb35c14cfd1d8..52dcf05e0360214c636a1f93ba37d7a42b11945e 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -985,7 +985,7 @@ Generate the new formula in the provided tap, specified as \fIuser\fR\fB/\fR\fIr Open a formula in the editor set by \fBEDITOR\fR or \fBHOMEBREW_EDITOR\fR, or open the Homebrew repository for editing if no \fIformula\fR is provided\. . .SS "\fBextract\fR [\fIoptions\fR] \fIformula\fR \fItap\fR" -Look through repository history to find the most recent version of \fIformula\fR and create a copy in \fItap\fR\fB/Formula/\fR\fIformula\fR\fB@\fR\fIversion\fR\fB\.rb\fR\. If the tap is not installed yet, attempt to install/clone the tap before continuing\. +Look through repository history to find the most recent version of \fIformula\fR and create a copy in \fItap\fR\fB/Formula/\fR\fIformula\fR\fB@\fR\fIversion\fR\fB\.rb\fR\. If the tap is not installed yet, attempt to install/clone the tap before continuing\. To extract a \fIformula\fR from a tap that is not homebrew/core use \fIuser\fR/\fIrepo\fR/\fIformula\fR\. . .TP \fB\-\-version\fR