tap: support --full even if installed

Makes `tap` re-runnable and unshallows when requested with `--full`.
Tapping with a different URL raises an exception.

The homebrew/core tap cannot be untapped with `untap` so running
`brew tap --full homebrew/core` is now a built-in way to get a full
clone of this tap without resorting to workarounds.

Closes #17.

Signed-off-by: ilovezfs <ilovezfs@icloud.com>
This commit is contained in:
ilovezfs 2016-04-04 03:18:55 -07:00
parent 1b7e13df4f
commit fad235d8e8
7 changed files with 101 additions and 11 deletions

View File

@ -17,8 +17,10 @@ module Homebrew
tap.install :clone_target => ARGV.named[1], tap.install :clone_target => ARGV.named[1],
:full_clone => ARGV.include?("--full"), :full_clone => ARGV.include?("--full"),
:quiet => ARGV.quieter? :quiet => ARGV.quieter?
rescue TapAlreadyTappedError => e rescue TapRemoteMismatchError => e
opoo e odie e
rescue TapAlreadyTappedError, TapAlreadyUnshallowError
# Do nothing.
end end
end end
end end

View File

@ -119,6 +119,23 @@ class TapUnavailableError < RuntimeError
end end
end end
class TapRemoteMismatchError < RuntimeError
attr_reader :name
attr_reader :expected_remote
attr_reader :actual_remote
def initialize(name, expected_remote, actual_remote)
@name = name
@expected_remote = expected_remote
@actual_remote = actual_remote
super <<-EOS.undent
Tap #{name} remote mismatch.
#{expected_remote} != #{actual_remote}
EOS
end
end
class TapAlreadyTappedError < RuntimeError class TapAlreadyTappedError < RuntimeError
attr_reader :name attr_reader :name
@ -131,6 +148,18 @@ class TapAlreadyTappedError < RuntimeError
end end
end end
class TapAlreadyUnshallowError < RuntimeError
attr_reader :name
def initialize(name)
@name = name
super <<-EOS.undent
Tap #{name} already a full clone.
EOS
end
end
class TapPinStatusError < RuntimeError class TapPinStatusError < RuntimeError
attr_reader :name, :pinned attr_reader :name, :pinned

View File

@ -394,7 +394,12 @@ With `--verbose` or `-v`, many commands print extra debugging information. Note
using protocols other than HTTPS, e.g., SSH, GIT, HTTP, FTP(S), RSYNC. using protocols other than HTTPS, e.g., SSH, GIT, HTTP, FTP(S), RSYNC.
By default, the repository is cloned as a shallow copy (`--depth=1`), but By default, the repository is cloned as a shallow copy (`--depth=1`), but
if `--full` is passed, a full clone will be used. if `--full` is passed, a full clone will be used. To convert a shallow copy
to a full copy, you can retap passing `--full` without first untapping.
`tap` is re-runnable and exits successfully if there's nothing to do.
However, retapping with a different <URL> will cause an exception, so first
`untap` if you need to modify the <URL>.
* `tap` `--repair`: * `tap` `--repair`:
Migrate tapped formulae from symlink-based to directory-based structure. Migrate tapped formulae from symlink-based to directory-based structure.

View File

@ -158,6 +158,11 @@ class Tap
path.directory? path.directory?
end end
# True if this {Tap} is not a full clone.
def shallow?
(path/".git/shallow").exist?
end
# @private # @private
def core_tap? def core_tap?
false false
@ -171,17 +176,33 @@ class Tap
# @option options [Boolean] :quiet If set, suppress all output. # @option options [Boolean] :quiet If set, suppress all output.
def install(options = {}) def install(options = {})
require "descriptions" require "descriptions"
raise TapAlreadyTappedError, name if installed?
clear_cache
full_clone = options.fetch(:full_clone, false)
quiet = options.fetch(:quiet, false) quiet = options.fetch(:quiet, false)
requested_remote = options[:clone_target] || "https://github.com/#{user}/homebrew-#{repo}"
if installed?
raise TapRemoteMismatchError.new(name, @remote, requested_remote) unless remote == requested_remote
raise TapAlreadyTappedError, name unless full_clone
raise TapAlreadyUnshallowError, name unless shallow?
end
# ensure git is installed # ensure git is installed
Utils.ensure_git_installed! Utils.ensure_git_installed!
if installed?
ohai "Unshallowing #{name}" unless quiet
args = %W[fetch --unshallow]
args << "-q" if quiet
path.cd { safe_system "git", *args }
return
end
clear_cache
ohai "Tapping #{name}" unless quiet ohai "Tapping #{name}" unless quiet
remote = options[:clone_target] || "https://github.com/#{user}/homebrew-#{repo}" args = %W[clone #{requested_remote} #{path} --config core.autocrlf=false]
args = %W[clone #{remote} #{path} --config core.autocrlf=false] args << "--depth=1" unless full_clone
args << "--depth=1" unless options.fetch(:full_clone, false)
args << "-q" if quiet args << "-q" if quiet
begin begin

View File

@ -164,7 +164,32 @@ class TapTest < Homebrew::TestCase
end end
def test_install_tap_already_tapped_error def test_install_tap_already_tapped_error
assert_raises(TapAlreadyTappedError) { @tap.install } setup_git_repo
already_tapped_tap = Tap.new("Homebrew", "foo")
assert_equal true, already_tapped_tap.installed?
assert_raises(TapAlreadyTappedError) { already_tapped_tap.install }
end
def test_install_tap_remote_match_already_tapped_error
setup_git_repo
already_tapped_tap = Tap.new("Homebrew", "foo")
assert_equal true, already_tapped_tap.installed?
right_remote = "#{@tap.remote}"
assert_raises(TapAlreadyTappedError) { already_tapped_tap.install :clone_target => right_remote }
end
def test_install_tap_remote_mismatch_error
setup_git_repo
already_tapped_tap = Tap.new("Homebrew", "foo")
assert_equal true, already_tapped_tap.installed?
wrong_remote = "#{@tap.remote}-oops"
assert_raises(TapRemoteMismatchError) { already_tapped_tap.install :clone_target => wrong_remote }
end
def test_install_tap_already_unshallow_error
setup_git_repo
already_tapped_tap = Tap.new("Homebrew", "foo")
assert_raises(TapAlreadyUnshallowError) { already_tapped_tap.install :full_clone => true }
end end
def test_uninstall_tap_unavailable_error def test_uninstall_tap_unavailable_error

View File

@ -303,7 +303,12 @@ assumptions, so taps can be cloned from places other than GitHub and
using protocols other than HTTPS, e.g., SSH, GIT, HTTP, FTP(S), RSYNC.</p> using protocols other than HTTPS, e.g., SSH, GIT, HTTP, FTP(S), RSYNC.</p>
<p>By default, the repository is cloned as a shallow copy (<code>--depth=1</code>), but <p>By default, the repository is cloned as a shallow copy (<code>--depth=1</code>), but
if <code>--full</code> is passed, a full clone will be used.</p></dd> if <code>--full</code> is passed, a full clone will be used. To convert a shallow copy
to a full copy, you can retap passing <code>--full</code> without first untapping.</p>
<p><code>tap</code> is re-runnable and exits successfully if there's nothing to do.
However, retapping with a different <var>URL</var> will cause an exception, so first
<code>untap</code> if you need to modify the <var>URL</var>.</p></dd>
<dt><code>tap</code> <code>--repair</code></dt><dd><p>Migrate tapped formulae from symlink-based to directory-based structure.</p></dd> <dt><code>tap</code> <code>--repair</code></dt><dd><p>Migrate tapped formulae from symlink-based to directory-based structure.</p></dd>
<dt><code>tap</code> <code>--list-official</code></dt><dd><p>List all official taps.</p></dd> <dt><code>tap</code> <code>--list-official</code></dt><dd><p>List all official taps.</p></dd>
<dt><code>tap</code> <code>--list-pinned</code></dt><dd><p>List all pinned taps.</p></dd> <dt><code>tap</code> <code>--list-pinned</code></dt><dd><p>List all pinned taps.</p></dd>

View File

@ -416,7 +416,10 @@ With \fIURL\fR unspecified, taps a formula repository from GitHub using HTTPS\.
With \fIURL\fR specified, taps a formula repository from anywhere, using any transport protocol that \fBgit\fR handles\. The one\-argument form of \fBtap\fR simplifies but also limits\. This two\-argument command makes no assumptions, so taps can be cloned from places other than GitHub and using protocols other than HTTPS, e\.g\., SSH, GIT, HTTP, FTP(S), RSYNC\. With \fIURL\fR specified, taps a formula repository from anywhere, using any transport protocol that \fBgit\fR handles\. The one\-argument form of \fBtap\fR simplifies but also limits\. This two\-argument command makes no assumptions, so taps can be cloned from places other than GitHub and using protocols other than HTTPS, e\.g\., SSH, GIT, HTTP, FTP(S), RSYNC\.
. .
.IP .IP
By default, the repository is cloned as a shallow copy (\fB\-\-depth=1\fR), but if \fB\-\-full\fR is passed, a full clone will be used\. By default, the repository is cloned as a shallow copy (\fB\-\-depth=1\fR), but if \fB\-\-full\fR is passed, a full clone will be used\. To convert a shallow copy to a full copy, you can retap passing \fB\-\-full\fR without first untapping\.
.
.IP
\fBtap\fR is re\-runnable and exits successfully if there\'s nothing to do\. However, retapping with a different \fIURL\fR will cause an exception, so first \fBuntap\fR if you need to modify the \fIURL\fR\.
. .
.TP .TP
\fBtap\fR \fB\-\-repair\fR \fBtap\fR \fB\-\-repair\fR