Merge pull request #12221 from XuehaiPan/brew-retap
tap: allow to change tap remote with `brew tap --custom-remote`
This commit is contained in:
commit
cc2c19be98
@ -293,6 +293,9 @@ module Homebrew
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def write_only?; end
|
||||
|
||||
sig { returns(T::Boolean) }
|
||||
def custom_remote?; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -35,6 +35,8 @@ module Homebrew
|
||||
switch "--force-auto-update",
|
||||
description: "Auto-update tap even if it is not hosted on GitHub. By default, only taps "\
|
||||
"hosted on GitHub are auto-updated (for performance reasons)."
|
||||
switch "--custom-remote",
|
||||
description: "Install or change a tap with a custom remote. Useful for mirrors."
|
||||
switch "--repair",
|
||||
description: "Migrate tapped formulae from symlink-based to directory-based structure."
|
||||
switch "--list-pinned",
|
||||
@ -64,8 +66,9 @@ module Homebrew
|
||||
begin
|
||||
tap.install clone_target: args.named.second,
|
||||
force_auto_update: force_auto_update?(args: args),
|
||||
custom_remote: args.custom_remote?,
|
||||
quiet: args.quiet?
|
||||
rescue TapRemoteMismatchError => e
|
||||
rescue TapRemoteMismatchError, TapNoCustomRemoteError => e
|
||||
odie e
|
||||
rescue TapAlreadyTappedError
|
||||
nil
|
||||
|
@ -324,13 +324,28 @@ class TapRemoteMismatchError < RuntimeError
|
||||
@expected_remote = expected_remote
|
||||
@actual_remote = actual_remote
|
||||
|
||||
super <<~EOS
|
||||
super message
|
||||
end
|
||||
|
||||
def message
|
||||
<<~EOS
|
||||
Tap #{name} remote mismatch.
|
||||
#{expected_remote} != #{actual_remote}
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when the remote of Homebrew/core does not match HOMEBREW_CORE_GIT_REMOTE.
|
||||
class TapCoreRemoteMismatchError < TapRemoteMismatchError
|
||||
def message
|
||||
<<~EOS
|
||||
Tap #{name} remote does mot match HOMEBREW_CORE_GIT_REMOTE.
|
||||
#{expected_remote} != #{actual_remote}
|
||||
Please set HOMEBREW_CORE_GIT_REMOTE="#{actual_remote}" and run `brew update` instead.
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when a tap is already installed.
|
||||
class TapAlreadyTappedError < RuntimeError
|
||||
attr_reader :name
|
||||
@ -344,6 +359,19 @@ class TapAlreadyTappedError < RuntimeError
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when run `brew tap --custom-remote` without a remote URL.
|
||||
class TapNoCustomRemoteError < RuntimeError
|
||||
attr_reader :name
|
||||
|
||||
def initialize(name)
|
||||
@name = name
|
||||
|
||||
super <<~EOS
|
||||
Tap #{name} with option `--custom-remote` but without a remote URL.
|
||||
EOS
|
||||
end
|
||||
end
|
||||
|
||||
# Raised when another Homebrew operation is already in progress.
|
||||
class OperationInProgressError < RuntimeError
|
||||
def initialize(name)
|
||||
|
@ -246,7 +246,8 @@ class Tap
|
||||
# @param force_auto_update [Boolean, nil] If present, whether to override the
|
||||
# logic that skips non-GitHub repositories during auto-updates.
|
||||
# @param quiet [Boolean] If set, suppress all output.
|
||||
def install(quiet: false, clone_target: nil, force_auto_update: nil)
|
||||
# @param custom_remote [Boolean] If set, change the tap's remote if already installed.
|
||||
def install(quiet: false, clone_target: nil, force_auto_update: nil, custom_remote: false)
|
||||
require "descriptions"
|
||||
require "readall"
|
||||
|
||||
@ -257,9 +258,11 @@ class Tap
|
||||
odie "#{name} was moved. Tap homebrew/#{new_repo} instead."
|
||||
end
|
||||
|
||||
raise TapNoCustomRemoteError, name if custom_remote && clone_target.nil?
|
||||
|
||||
requested_remote = clone_target || default_remote
|
||||
|
||||
if installed?
|
||||
if installed? && !custom_remote
|
||||
raise TapRemoteMismatchError.new(name, @remote, requested_remote) if clone_target && requested_remote != remote
|
||||
raise TapAlreadyTappedError, name if force_auto_update.nil? && !shallow?
|
||||
end
|
||||
@ -268,6 +271,10 @@ class Tap
|
||||
Utils::Git.ensure_installed!
|
||||
|
||||
if installed?
|
||||
if requested_remote != remote # we are sure that clone_target is not nil and custom_remote is true here
|
||||
fix_remote_configuration(requested_remote: requested_remote, quiet: quiet)
|
||||
end
|
||||
|
||||
unless force_auto_update.nil?
|
||||
config["forceautoupdate"] = force_auto_update
|
||||
return
|
||||
@ -358,20 +365,33 @@ class Tap
|
||||
end
|
||||
end
|
||||
|
||||
def fix_remote_configuration
|
||||
return unless remote.include? "github.com"
|
||||
def fix_remote_configuration(requested_remote: nil, quiet: false)
|
||||
if requested_remote.present?
|
||||
path.cd do
|
||||
safe_system "git", "remote", "set-url", "origin", requested_remote
|
||||
safe_system "git", "config", "remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*"
|
||||
end
|
||||
$stderr.ohai "#{name}: changed remote from #{remote} to #{requested_remote}" unless quiet
|
||||
end
|
||||
|
||||
current_upstream_head = path.git_origin_branch
|
||||
return if path.git_origin_has_branch? current_upstream_head
|
||||
return if requested_remote.blank? && path.git_origin_has_branch?(current_upstream_head)
|
||||
|
||||
safe_system "git", "-C", path, "fetch", "origin"
|
||||
args = %w[fetch]
|
||||
args << "--quiet" if quiet
|
||||
args << "origin"
|
||||
safe_system "git", "-C", path, *args
|
||||
path.git_origin_set_head_auto
|
||||
|
||||
new_upstream_head = path.git_origin_branch
|
||||
return if new_upstream_head == old_upstream_head
|
||||
|
||||
path.git_rename_branch old: current_upstream_head, new: new_upstream_head
|
||||
path.git_branch_set_upstream local: new_upstream_head, origin: new_upstream_head
|
||||
|
||||
ohai "#{name}: changed default branch name from #{current_upstream_head} to #{new_upstream_head}!"
|
||||
return if quiet
|
||||
|
||||
$stderr.ohai "#{name}: changed default branch name from #{current_upstream_head} to #{new_upstream_head}!"
|
||||
end
|
||||
|
||||
# Uninstall this {Tap}.
|
||||
@ -741,12 +761,18 @@ class CoreTap < Tap
|
||||
end
|
||||
|
||||
# CoreTap never allows shallow clones (on request from GitHub).
|
||||
def install(quiet: false, clone_target: nil, force_auto_update: nil)
|
||||
def install(quiet: false, clone_target: nil, force_auto_update: nil, custom_remote: false)
|
||||
remote = Homebrew::EnvConfig.core_git_remote
|
||||
requested_remote = clone_target || default_remote
|
||||
|
||||
# The remote will changed again on `brew update` since remotes for Homebrew/core are mismatched
|
||||
raise TapCoreRemoteMismatchError.new(name, remote, requested_remote) if requested_remote != remote
|
||||
|
||||
if remote != default_remote
|
||||
$stderr.puts "HOMEBREW_CORE_GIT_REMOTE set: using #{remote} for Homebrew/core Git remote URL."
|
||||
$stderr.puts "HOMEBREW_CORE_GIT_REMOTE set: using #{remote} for Homebrew/core Git remote."
|
||||
end
|
||||
super(quiet: quiet, clone_target: remote, force_auto_update: force_auto_update)
|
||||
|
||||
super(quiet: quiet, clone_target: remote, force_auto_update: force_auto_update, custom_remote: custom_remote)
|
||||
end
|
||||
|
||||
# @private
|
||||
|
@ -289,6 +289,33 @@ describe Tap do
|
||||
}.to raise_error(TapRemoteMismatchError)
|
||||
end
|
||||
|
||||
it "raises an error when the remote for Homebrew/core doesn't match HOMEBREW_CORE_GIT_REMOTE" do
|
||||
core_tap = described_class.fetch("Homebrew", "core")
|
||||
wrong_remote = "#{Homebrew::EnvConfig.core_git_remote}-oops"
|
||||
expect {
|
||||
core_tap.install clone_target: wrong_remote
|
||||
}.to raise_error(TapCoreRemoteMismatchError)
|
||||
end
|
||||
|
||||
it "raises an error when run `brew tap --custom-remote` without a custom remote (already installed)" do
|
||||
setup_git_repo
|
||||
already_tapped_tap = described_class.new("Homebrew", "foo")
|
||||
expect(already_tapped_tap).to be_installed
|
||||
|
||||
expect {
|
||||
already_tapped_tap.install clone_target: nil, custom_remote: true
|
||||
}.to raise_error(TapNoCustomRemoteError)
|
||||
end
|
||||
|
||||
it "raises an error when run `brew tap --custom-remote` without a custom remote (not installed)" do
|
||||
not_tapped_tap = described_class.new("Homebrew", "bar")
|
||||
expect(not_tapped_tap).not_to be_installed
|
||||
|
||||
expect {
|
||||
not_tapped_tap.install clone_target: nil, custom_remote: true
|
||||
}.to raise_error(TapNoCustomRemoteError)
|
||||
end
|
||||
|
||||
describe "force_auto_update" do
|
||||
before do
|
||||
setup_git_repo
|
||||
|
@ -1902,6 +1902,7 @@ _brew_tap() {
|
||||
case "${cur}" in
|
||||
-*)
|
||||
__brewcomp "
|
||||
--custom-remote
|
||||
--debug
|
||||
--force-auto-update
|
||||
--full
|
||||
|
@ -1288,6 +1288,7 @@ __fish_brew_complete_arg 'style; and not __fish_seen_argument -l formula -l form
|
||||
|
||||
|
||||
__fish_brew_complete_cmd 'tap' 'Tap a formula repository'
|
||||
__fish_brew_complete_arg 'tap' -l custom-remote -d 'Install or change a tap with a custom remote. Useful for mirrors'
|
||||
__fish_brew_complete_arg 'tap' -l debug -d 'Display any debugging information'
|
||||
__fish_brew_complete_arg 'tap' -l force-auto-update -d 'Auto-update tap even if it is not hosted on GitHub. By default, only taps hosted on GitHub are auto-updated (for performance reasons)'
|
||||
__fish_brew_complete_arg 'tap' -l full -d 'Convert a shallow clone to a full clone without untapping. Taps are only cloned as shallow clones if `--shallow` was originally passed'
|
||||
|
@ -1579,6 +1579,7 @@ _brew_style() {
|
||||
# brew tap
|
||||
_brew_tap() {
|
||||
_arguments \
|
||||
'--custom-remote[Install or change a tap with a custom remote. Useful for mirrors]' \
|
||||
'--debug[Display any debugging information]' \
|
||||
'--force-auto-update[Auto-update tap even if it is not hosted on GitHub. By default, only taps hosted on GitHub are auto-updated (for performance reasons)]' \
|
||||
'--full[Convert a shallow clone to a full clone without untapping. Taps are only cloned as shallow clones if `--shallow` was originally passed]' \
|
||||
|
@ -600,6 +600,8 @@ using protocols other than HTTPS, e.g. SSH, git, HTTP, FTP(S), rsync.
|
||||
Fetch tap as a shallow clone rather than a full clone. Useful for continuous integration.
|
||||
* `--force-auto-update`:
|
||||
Auto-update tap even if it is not hosted on GitHub. By default, only taps hosted on GitHub are auto-updated (for performance reasons).
|
||||
* `--custom-remote`:
|
||||
Install or change a tap with a custom remote. Useful for mirrors.
|
||||
* `--repair`:
|
||||
Migrate tapped formulae from symlink-based to directory-based structure.
|
||||
* `--list-pinned`:
|
||||
|
@ -831,6 +831,10 @@ Fetch tap as a shallow clone rather than a full clone\. Useful for continuous in
|
||||
Auto\-update tap even if it is not hosted on GitHub\. By default, only taps hosted on GitHub are auto\-updated (for performance reasons)\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-custom\-remote\fR
|
||||
Install or change a tap with a custom remote\. Useful for mirrors\.
|
||||
.
|
||||
.TP
|
||||
\fB\-\-repair\fR
|
||||
Migrate tapped formulae from symlink\-based to directory\-based structure\.
|
||||
.
|
||||
|
Loading…
x
Reference in New Issue
Block a user