Merge pull request #5887 from kiendang/extract-all-taps

brew extract from all taps
This commit is contained in:
Mike McQuaid 2019-03-21 09:39:56 +00:00 committed by GitHub
commit 373c0242fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 24 deletions

View File

@ -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=",
@ -97,47 +98,70 @@ module Homebrew
# Expect exactly two named arguments: formula and tap
raise UsageError if ARGV.named.length != 2
if ARGV.named.first !~ HOMEBREW_TAP_FORMULA_REGEX
name = ARGV.named.first.downcase
source_tap = CoreTap.instance
else
name = Regexp.last_match(3).downcase
source_tap = Tap.fetch(Regexp.last_match(1), Regexp.last_match(2))
raise TapFormulaUnavailableError.new(source_tap, name) unless source_tap.installed?
end
destination_tap = Tap.fetch(ARGV.named.second)
odie "Cannot extract formula to homebrew/core!" if destination_tap.core_tap?
odie "Cannot extract formula to the same tap!" if destination_tap == source_tap
destination_tap.install unless destination_tap.installed?
name = ARGV.named.first.downcase
repo = CoreTap.instance.path
# Formulae can technically live in "<repo>/<formula>.rb" or
# "<repo>/Formula/<formula>.rb", but explicitly use the latter for now
# since that is how the core tap is structured.
file = repo/"Formula/#{name}.rb"
repo = source_tap.path
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"
version = args.version
rev = "HEAD"
test_formula = nil
result = ""
loop do
loop do
rev = Git.last_revision_commit_of_file(repo, file, before_commit: "#{rev}~1")
break if rev.empty?
break unless Git.last_revision_of_file(repo, file, before_commit: rev).empty?
rev, (path,) = Git.last_revision_commit_of_files(repo, pattern, before_commit: "#{rev}~1")
odie "Could not find #{name}! The formula or version may not have existed." if rev.nil?
file = repo/path
result = Git.last_revision_of_file(repo, file, before_commit: rev)
if result.empty?
ohai "Skipping revision #{rev} - file is empty at this revision" if ARGV.debug?
next
end
test_formula = formula_at_revision(repo, name, file, rev)
break if test_formula.nil? || test_formula.version == version
ohai "Trying #{test_formula.version} from revision #{rev} against desired #{version}" if ARGV.debug?
end
odie "Could not find #{name}! The formula or version may not have existed." if test_formula.nil?
result = Git.last_revision_of_file(repo, file, before_commit: rev)
elsif File.exist?(file)
rev = "HEAD"
version = Formulary.factory(file).version
result = File.read(file)
else
ohai "Searching repository history"
rev = Git.last_revision_commit_of_file(repo, file)
version = formula_at_revision(repo, name, file, rev).version
odie "Could not find #{name}! The formula or version may not have existed." if rev.empty?
result = Git.last_revision_of_file(repo, file)
# 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
if files.empty?
ohai "Searching repository history"
rev, (path,) = Git.last_revision_commit_of_files(repo, pattern)
odie "Could not find #{name}! The formula or version may not have existed." if rev.nil?
file = repo/path
version = formula_at_revision(repo, name, file, rev).version
result = Git.last_revision_of_file(repo, file)
else
file = files.first.realpath
rev = "HEAD"
version = Formulary.factory(file).version
result = File.read(file)
end
end
# The class name has to be renamed to match the new filename,

View File

@ -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,6 +18,28 @@ module Git
out.chomp
end
def last_revision_commit_of_files(repo, files, before_commit: nil)
args = if before_commit.nil?
["--skip=1"]
else
[before_commit.split("..").first]
end
# 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)
relative_file = Pathname(file).relative_path_from(repo)

View File

@ -782,7 +782,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.

View File

@ -981,7 +981,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