Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow references to casks when running uninstall and reinstall #7853

Merged
merged 23 commits into from Jul 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cbfea6c
args: Add field for kegs and unknowns
whoiswillma Jun 24, 2020
90c26da
uninstall: Add ability to reference casks from brew uninstall
whoiswillma Jun 24, 2020
16f16f3
uninstall: Add test for uninstalling cask
whoiswillma Jun 24, 2020
5900263
args: Add resolved_formulae_and_unknowns
whoiswillma Jun 24, 2020
d1004c8
reinstall: Add ability to reference casks from brew reinstall
whoiswillma Jun 24, 2020
e733fa1
uninstall: Refactor to use AbstractCommand instead of declaring a cla…
whoiswillma Jun 24, 2020
f03336b
uninstall: Clean up cask-appdir after tests
whoiswillma Jun 25, 2020
1044cb9
Merge branch 'master' into integrate-uninstall-reinstall
whoiswillma Jun 26, 2020
4dc2df6
uninstall: Run cask uninstall tests only on macos
whoiswillma Jun 29, 2020
8a05b52
args: Refactor to load casks directly
whoiswillma Jun 30, 2020
dff61c9
style: Fix style issues
whoiswillma Jun 30, 2020
f3ae2fd
reinstall: Replace with more specific imports
whoiswillma Jun 30, 2020
bb93932
Merge branch 'master' into integrate-uninstall-reinstall
whoiswillma Jun 30, 2020
72dcbd6
style: Dedent cask uninstall block
whoiswillma Jun 30, 2020
ac5f0c1
style: Dedent some autoformatted code in uninstall test case
whoiswillma Jun 30, 2020
26d7dd7
uninstall: remove tests
whoiswillma Jul 2, 2020
3459931
Merge branch 'master' into integrate-uninstall-reinstall
whoiswillma Jul 2, 2020
eb1ea00
uninstall: Refactor when using --force
whoiswillma Jul 2, 2020
1826be8
style: Replace Hash.new with {}
whoiswillma Jul 2, 2020
1ae38fb
Delete IDE files (oops)
whoiswillma Jul 3, 2020
525d1ac
Fix PR issues
whoiswillma Jul 3, 2020
6e8f5d0
Modify MultipleVersionsInstalledError to have a generic message
whoiswillma Jul 3, 2020
df8d22a
Remove debugging markers (oops)
whoiswillma Jul 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
131 changes: 87 additions & 44 deletions Library/Homebrew/cli/args.rb
Expand Up @@ -36,9 +36,11 @@ def freeze_named_args!(named_args)
# Reset cache values reliant on named_args
@formulae = nil
@resolved_formulae = nil
@resolved_formulae_casks = nil
@formulae_paths = nil
@casks = nil
@kegs = nil
@kegs_casks = nil

self[:named_args] = named_args
self[:named_args].freeze
Expand Down Expand Up @@ -96,6 +98,25 @@ def resolved_formulae
end.uniq(&:name).freeze
end

def resolved_formulae_casks
@resolved_formulae_casks ||= begin
resolved_formulae = []
casks = []

downcased_unique_named.each do |name|
resolved_formulae << Formulary.resolve(name, spec: spec(nil))
rescue FormulaUnavailableError
begin
casks << Cask::CaskLoader.load(name)
rescue Cask::CaskUnavailableError
raise "No available formula or cask with the name \"#{name}\""
end
end

[resolved_formulae.freeze, casks.freeze].freeze
end
end

def formulae_paths
@formulae_paths ||= (downcased_unique_named - casks).map do |name|
Formulary.path(name)
Expand All @@ -108,55 +129,33 @@ def casks
end

def kegs
require "keg"
require "formula"
require "missing_formula"

@kegs ||= downcased_unique_named.map do |name|
raise UsageError if name.empty?

rack = Formulary.to_rack(name.downcase)

dirs = rack.directory? ? rack.subdirs : []

if dirs.empty?
if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall"))
$stderr.puts reason
end
raise NoSuchKegError, rack.basename
resolve_keg name
rescue NoSuchKegError => e
if (reason = Homebrew::MissingFormula.suggest_command(name, "uninstall"))
$stderr.puts reason
end
raise e
end.freeze
end

linked_keg_ref = HOMEBREW_LINKED_KEGS/rack.basename
opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}"

begin
if opt_prefix.symlink? && opt_prefix.directory?
Keg.new(opt_prefix.resolved_path)
elsif linked_keg_ref.symlink? && linked_keg_ref.directory?
Keg.new(linked_keg_ref.resolved_path)
elsif dirs.length == 1
Keg.new(dirs.first)
else
f = if name.include?("/") || File.exist?(name)
Formulary.factory(name)
else
Formulary.from_rack(rack)
end

unless (prefix = f.installed_prefix).directory?
raise MultipleVersionsInstalledError, rack.basename
end

Keg.new(prefix)
def kegs_casks
@kegs_casks ||= begin
kegs = []
casks = []

downcased_unique_named.each do |name|
kegs << resolve_keg(name)
rescue NoSuchKegError
begin
casks << Cask::CaskLoader.load(name)
rescue Cask::CaskUnavailableError
raise "No installed keg or cask with the name \"#{name}\""
end
rescue FormulaUnavailableError
raise <<~EOS
Multiple kegs installed to #{rack}
However we don't know which one you refer to.
Please delete (with rm -rf!) all but one and then try again.
EOS
end
end.freeze

[kegs.freeze, casks.freeze].freeze
end
end

def build_stable?
Expand Down Expand Up @@ -241,6 +240,50 @@ def spec(default = :stable)
default
end
end

def resolve_keg(name)
require "keg"
require "formula"
require "missing_formula"

raise UsageError if name.blank?

rack = Formulary.to_rack(name.downcase)

dirs = rack.directory? ? rack.subdirs : []
raise NoSuchKegError, rack.basename if dirs.empty?

linked_keg_ref = HOMEBREW_LINKED_KEGS/rack.basename
opt_prefix = HOMEBREW_PREFIX/"opt/#{rack.basename}"

begin
if opt_prefix.symlink? && opt_prefix.directory?
Keg.new(opt_prefix.resolved_path)
elsif linked_keg_ref.symlink? && linked_keg_ref.directory?
Keg.new(linked_keg_ref.resolved_path)
elsif dirs.length == 1
Keg.new(dirs.first)
else
f = if name.include?("/") || File.exist?(name)
Formulary.factory(name)
else
Formulary.from_rack(rack)
end

unless (prefix = f.installed_prefix).directory?
raise MultipleVersionsInstalledError, "#{rack.basename} has multiple installed versions"
end

Keg.new(prefix)
end
rescue FormulaUnavailableError
whoiswillma marked this conversation as resolved.
Show resolved Hide resolved
raise MultipleVersionsInstalledError, <<~EOS
Multiple kegs installed to #{rack}
However we don't know which one you refer to.
Please delete (with rm -rf!) all but one and then try again.
EOS
end
end
end
end
end
13 changes: 12 additions & 1 deletion Library/Homebrew/cmd/reinstall.rb
Expand Up @@ -6,6 +6,9 @@
require "reinstall"
require "cli/parser"
require "cleanup"
require "cask/cmd"
require "cask/utils"
require "cask/macos"
require "upgrade"

module Homebrew
Expand Down Expand Up @@ -57,7 +60,8 @@ def reinstall

Install.perform_preinstall_checks

args.resolved_formulae.each do |f|
resolved_formulae, casks = args.resolved_formulae_casks
whoiswillma marked this conversation as resolved.
Show resolved Hide resolved
resolved_formulae.each do |f|
if f.pinned?
onoe "#{f.full_name} is pinned. You must unpin it to reinstall."
next
Expand All @@ -70,5 +74,12 @@ def reinstall
check_installed_dependents

Homebrew.messages.display_messages

return if casks.blank?

reinstall_cmd = Cask::Cmd::Reinstall.new(casks)
reinstall_cmd.verbose = args.verbose?
reinstall_cmd.force = args.force?
reinstall_cmd.run
end
end
33 changes: 27 additions & 6 deletions Library/Homebrew/cmd/uninstall.rb
Expand Up @@ -5,6 +5,9 @@
require "diagnostic"
require "migrator"
require "cli/parser"
require "cask/all"
require "cask/cmd"
require "cask/cask_loader"

module Homebrew
module_function
Expand All @@ -29,15 +32,26 @@ def uninstall_args
def uninstall
uninstall_args.parse

kegs_by_rack = if args.force?
Hash[args.named.map do |name|
if args.force?
casks = []
kegs_by_rack = {}

args.named.each do |name|
rack = Formulary.to_rack(name)
next unless rack.directory?

[rack, rack.subdirs.map { |d| Keg.new(d) }]
end]
if rack.directory?
kegs_by_rack[rack] = rack.subdirs.map { |d| Keg.new(d) }
else
begin
casks << Cask::CaskLoader.load(name)
rescue Cask::CaskUnavailableError
# Since the uninstall was forced, ignore any unavailable casks
end
end
end
else
args.kegs.group_by(&:rack)
all_kegs, casks = args.kegs_casks
kegs_by_rack = all_kegs.group_by(&:rack)
end

handle_unsatisfied_dependents(kegs_by_rack)
Expand Down Expand Up @@ -108,6 +122,13 @@ def uninstall
end
end
end

return if casks.blank?

cask_uninstall = Cask::Cmd::Uninstall.new(casks)
cask_uninstall.force = args.force?
cask_uninstall.verbose = args.verbose?
cask_uninstall.run
rescue MultipleVersionsInstalledError => e
ofail e
puts "Run `brew uninstall --force #{e.name}` to remove all versions."
Expand Down
9 changes: 1 addition & 8 deletions Library/Homebrew/exceptions.rb
Expand Up @@ -29,14 +29,7 @@ def initialize
end
end

class MultipleVersionsInstalledError < RuntimeError
attr_reader :name

def initialize(name)
@name = name
super "#{name} has multiple installed versions"
end
end
class MultipleVersionsInstalledError < RuntimeError; end

class NotAKegError < RuntimeError; end

Expand Down
2 changes: 1 addition & 1 deletion Library/Homebrew/test/exceptions_spec.rb
Expand Up @@ -3,7 +3,7 @@
require "exceptions"

describe MultipleVersionsInstalledError do
subject { described_class.new("foo") }
subject { described_class.new("foo has multiple installed versions") }

its(:to_s) { is_expected.to eq("foo has multiple installed versions") }
end
Expand Down