Merge pull request #15138 from JBYoshi/cask-move-contents

Don't remove cask directories when upgrading.
This commit is contained in:
Mike McQuaid 2023-05-04 11:43:44 +01:00 committed by GitHub
commit 0e387fee8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 306 additions and 55 deletions

View File

@ -285,8 +285,8 @@ module Cask
end end
end end
def uninstall_login_item(*login_items, command: nil, upgrade: false, **_) def uninstall_login_item(*login_items, command: nil, successor: nil, **_)
return if upgrade return if successor
apps = cask.artifacts.select { |a| a.class.dsl_key == :app } apps = cask.artifacts.select { |a| a.class.dsl_key == :app }
derived_login_items = apps.map { |a| { path: a.target } } derived_login_items = apps.map { |a| { path: a.target } }

View File

@ -2,6 +2,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require "cask/artifact/relocated" require "cask/artifact/relocated"
require "cask/quarantine"
module Cask module Cask
module Artifact module Artifact
@ -32,39 +33,51 @@ module Cask
private private
def move(adopt: false, force: false, verbose: false, command: nil, **options) def move(adopt: false, force: false, verbose: false, predecessor: nil, reinstall: false,
command: nil, **options)
unless source.exist? unless source.exist?
raise CaskError, "It seems the #{self.class.english_name} source '#{source}' is not there." raise CaskError, "It seems the #{self.class.english_name} source '#{source}' is not there."
end end
if Utils.path_occupied?(target) if Utils.path_occupied?(target)
if adopt if target.directory? && target.children.empty? && matching_artifact?(predecessor)
ohai "Adopting existing #{self.class.english_name} at '#{target}'" # An upgrade removed the directory contents but left the directory itself (see below).
same = command.run( unless source.directory?
"/usr/bin/diff", if target.parent.writable? && !force
args: ["--recursive", "--brief", source, target], target.rmdir
verbose: verbose, else
print_stdout: verbose, Utils.gain_permissions_remove(target, command: command)
).success? end
end
else
if adopt
ohai "Adopting existing #{self.class.english_name} at '#{target}'"
same = command.run(
"/usr/bin/diff",
args: ["--recursive", "--brief", source, target],
verbose: verbose,
print_stdout: verbose,
).success?
unless same unless same
raise CaskError, raise CaskError,
"It seems the existing #{self.class.english_name} is different from " \ "It seems the existing #{self.class.english_name} is different from " \
"the one being installed." "the one being installed."
end
# Remove the source as we don't need to move it to the target location
source.rmtree
return post_move(command)
end end
# Remove the source as we don't need to move it to the target location message = "It seems there is already #{self.class.english_article} " \
source.rmtree "#{self.class.english_name} at '#{target}'"
raise CaskError, "#{message}." unless force
return post_move(command) opoo "#{message}; overwriting."
delete(target, force: force, command: command, **options)
end end
message = "It seems there is already #{self.class.english_article} " \
"#{self.class.english_name} at '#{target}'"
raise CaskError, "#{message}." unless force
opoo "#{message}; overwriting."
delete(target, force: force, command: command, **options)
end end
ohai "Moving #{self.class.english_name} '#{source.basename}' to '#{target}'" ohai "Moving #{self.class.english_name} '#{source.basename}' to '#{target}'"
@ -77,7 +90,16 @@ module Cask
end end
end end
if target.dirname.writable? if target.directory?
if target.writable?
source.children.each { |child| FileUtils.move(child, target + child.basename) }
else
command.run!("/bin/cp", args: ["-pR", "#{source}/*", "#{source}/.*", "#{target}/"],
sudo: true)
end
Quarantine.copy_xattrs(source, target)
source.rmtree
elsif target.dirname.writable?
FileUtils.move(source, target) FileUtils.move(source, target)
else else
# default sudo user isn't necessarily able to write to Homebrew's locations # default sudo user isn't necessarily able to write to Homebrew's locations
@ -96,6 +118,14 @@ module Cask
add_altname_metadata(target, source.basename, command: command) add_altname_metadata(target, source.basename, command: command)
end end
def matching_artifact?(cask)
return false unless cask
cask.artifacts.any? do |a|
a.instance_of?(self.class) && instance_of?(a.class) && a.target == target
end
end
def move_back(skip: false, force: false, command: nil, **options) def move_back(skip: false, force: false, command: nil, **options)
FileUtils.rm source if source.symlink? && source.dirname.join(source.readlink) == target FileUtils.rm source if source.symlink? && source.dirname.join(source.readlink) == target
@ -123,13 +153,23 @@ module Cask
delete(target, force: force, command: command, **options) delete(target, force: force, command: command, **options)
end end
def delete(target, force: false, command: nil, **_) def delete(target, force: false, successor: nil, command: nil, **_)
ohai "Removing #{self.class.english_name} '#{target}'" ohai "Removing #{self.class.english_name} '#{target}'"
raise CaskError, "Cannot remove undeletable #{self.class.english_name}." if MacOS.undeletable?(target) raise CaskError, "Cannot remove undeletable #{self.class.english_name}." if MacOS.undeletable?(target)
return unless Utils.path_occupied?(target) return unless Utils.path_occupied?(target)
if target.parent.writable? && !force if target.directory? && matching_artifact?(successor)
# If an app folder is deleted, macOS considers the app uninstalled and removes some data.
# Remove only the contents to handle this case.
target.children.each do |child|
if target.writable? && !force
child.rmtree
else
Utils.gain_permissions_remove(child, command: command)
end
end
elsif target.parent.writable? && !force
target.rmtree target.rmtree
else else
Utils.gain_permissions_remove(target, command: command) Utils.gain_permissions_remove(target, command: command)

View File

@ -20,7 +20,7 @@ module Cask
def initialize(cask, command: SystemCommand, force: false, adopt: false, def initialize(cask, command: SystemCommand, force: false, adopt: false,
skip_cask_deps: false, binaries: true, verbose: false, skip_cask_deps: false, binaries: true, verbose: false,
zap: false, require_sha: false, upgrade: false, zap: false, require_sha: false, upgrade: false, reinstall: false,
installed_as_dependency: false, quarantine: true, installed_as_dependency: false, quarantine: true,
verify_download_integrity: true, quiet: false) verify_download_integrity: true, quiet: false)
@cask = cask @cask = cask
@ -32,7 +32,7 @@ module Cask
@verbose = verbose @verbose = verbose
@zap = zap @zap = zap
@require_sha = require_sha @require_sha = require_sha
@reinstall = false @reinstall = reinstall
@upgrade = upgrade @upgrade = upgrade
@installed_as_dependency = installed_as_dependency @installed_as_dependency = installed_as_dependency
@quarantine = quarantine @quarantine = quarantine
@ -93,6 +93,7 @@ module Cask
raise CaskAlreadyInstalledError, @cask raise CaskAlreadyInstalledError, @cask
end end
predecessor = @cask if reinstall? && @cask.installed?
check_conflicts check_conflicts
@ -108,7 +109,7 @@ module Cask
@cask.config = @cask.default_config.merge(old_config) @cask.config = @cask.default_config.merge(old_config)
install_artifacts install_artifacts(predecessor: predecessor)
if (tap = @cask.tap) && tap.should_report_analytics? if (tap = @cask.tap) && tap.should_report_analytics?
::Utils::Analytics.report_event(:cask_install, package_name: @cask.token, tap_name: tap.name, ::Utils::Analytics.report_event(:cask_install, package_name: @cask.token, tap_name: tap.name,
@ -141,18 +142,12 @@ on_request: true)
end end
end end
def reinstall
odebug "Cask::Installer#reinstall"
@reinstall = true
install
end
def uninstall_existing_cask def uninstall_existing_cask
return unless @cask.installed? return unless @cask.installed?
# Always force uninstallation, ignore method parameter # Always force uninstallation, ignore method parameter
cask_installer = Installer.new(@cask, verbose: verbose?, force: true, upgrade: upgrade?) cask_installer = Installer.new(@cask, verbose: verbose?, force: true, upgrade: upgrade?, reinstall: true)
zap? ? cask_installer.zap : cask_installer.uninstall zap? ? cask_installer.zap : cask_installer.uninstall(successor: @cask)
end end
sig { returns(String) } sig { returns(String) }
@ -219,7 +214,7 @@ on_request: true)
Quarantine.propagate(from: primary_container.path, to: to) Quarantine.propagate(from: primary_container.path, to: to)
end end
def install_artifacts def install_artifacts(predecessor: nil)
artifacts = @cask.artifacts artifacts = @cask.artifacts
already_installed_artifacts = [] already_installed_artifacts = []
@ -232,7 +227,8 @@ on_request: true)
next if artifact.is_a?(Artifact::Binary) && !binaries? next if artifact.is_a?(Artifact::Binary) && !binaries?
artifact.install_phase(command: @command, verbose: verbose?, adopt: adopt?, force: force?) artifact.install_phase(command: @command, verbose: verbose?, adopt: adopt?, force: force?,
predecessor: predecessor)
already_installed_artifacts.unshift(artifact) already_installed_artifacts.unshift(artifact)
end end
@ -394,10 +390,10 @@ on_request: true)
@cask.download_sha_path.atomic_write(@cask.new_download_sha) if @cask.checksumable? @cask.download_sha_path.atomic_write(@cask.new_download_sha) if @cask.checksumable?
end end
def uninstall def uninstall(successor: nil)
load_installed_caskfile! load_installed_caskfile!
oh1 "Uninstalling Cask #{Formatter.identifier(@cask)}" oh1 "Uninstalling Cask #{Formatter.identifier(@cask)}"
uninstall_artifacts(clear: true) uninstall_artifacts(clear: true, successor: successor)
if !reinstall? && !upgrade? if !reinstall? && !upgrade?
remove_download_sha remove_download_sha
remove_config_file remove_config_file
@ -415,8 +411,8 @@ on_request: true)
FileUtils.rm_f @cask.download_sha_path if @cask.download_sha_path.exist? FileUtils.rm_f @cask.download_sha_path if @cask.download_sha_path.exist?
end end
def start_upgrade def start_upgrade(successor:)
uninstall_artifacts uninstall_artifacts(successor: successor)
backup backup
end end
@ -435,10 +431,10 @@ on_request: true)
backup_metadata_path.rename @cask.metadata_versioned_path backup_metadata_path.rename @cask.metadata_versioned_path
end end
def revert_upgrade def revert_upgrade(predecessor)
opoo "Reverting upgrade for Cask #{@cask}" opoo "Reverting upgrade for Cask #{@cask}"
restore_backup restore_backup
install_artifacts install_artifacts(predecessor: predecessor)
end end
def finalize_upgrade def finalize_upgrade
@ -449,7 +445,7 @@ on_request: true)
puts summary puts summary
end end
def uninstall_artifacts(clear: false) def uninstall_artifacts(clear: false, successor: nil)
artifacts = @cask.artifacts artifacts = @cask.artifacts
odebug "Uninstalling artifacts" odebug "Uninstalling artifacts"
@ -459,7 +455,11 @@ on_request: true)
if artifact.respond_to?(:uninstall_phase) if artifact.respond_to?(:uninstall_phase)
odebug "Uninstalling artifact of class #{artifact.class}" odebug "Uninstalling artifact of class #{artifact.class}"
artifact.uninstall_phase( artifact.uninstall_phase(
command: @command, verbose: verbose?, skip: clear, force: force?, upgrade: upgrade?, command: @command,
verbose: verbose?,
skip: clear,
force: force?,
successor: successor,
) )
end end
@ -467,7 +467,11 @@ on_request: true)
odebug "Post-uninstalling artifact of class #{artifact.class}" odebug "Post-uninstalling artifact of class #{artifact.class}"
artifact.post_uninstall_phase( artifact.post_uninstall_phase(
command: @command, verbose: verbose?, skip: clear, force: force?, upgrade: upgrade?, command: @command,
verbose: verbose?,
skip: clear,
force: force?,
successor: successor,
) )
end end
end end

View File

@ -12,6 +12,7 @@ module Cask
QUARANTINE_ATTRIBUTE = "com.apple.quarantine" QUARANTINE_ATTRIBUTE = "com.apple.quarantine"
QUARANTINE_SCRIPT = (HOMEBREW_LIBRARY_PATH/"cask/utils/quarantine.swift").freeze QUARANTINE_SCRIPT = (HOMEBREW_LIBRARY_PATH/"cask/utils/quarantine.swift").freeze
COPY_XATTRS_SCRIPT = (HOMEBREW_LIBRARY_PATH/"cask/utils/copy-xattrs.swift").freeze
def self.swift def self.swift
@swift ||= DevelopmentTools.locate("swift") @swift ||= DevelopmentTools.locate("swift")
@ -172,5 +173,19 @@ module Cask
raise CaskQuarantinePropagationError.new(to, quarantiner.stderr) raise CaskQuarantinePropagationError.new(to, quarantiner.stderr)
end end
def self.copy_xattrs(from, to)
odebug "Copying xattrs from #{from} to #{to}"
system_command!(
swift,
args: [
*swift_target_args,
COPY_XATTRS_SCRIPT,
from,
to,
],
)
end
end end
end end

View File

@ -26,8 +26,9 @@ module Cask
force: force, force: force,
skip_cask_deps: skip_cask_deps, skip_cask_deps: skip_cask_deps,
require_sha: require_sha, require_sha: require_sha,
reinstall: true,
quarantine: quarantine, quarantine: quarantine,
zap: zap).reinstall zap: zap).install
end end
end end
end end

View File

@ -180,22 +180,22 @@ module Cask
new_cask_installer.fetch new_cask_installer.fetch
# Move the old cask's artifacts back to staging # Move the old cask's artifacts back to staging
old_cask_installer.start_upgrade old_cask_installer.start_upgrade(successor: new_cask)
# And flag it so in case of error # And flag it so in case of error
started_upgrade = true started_upgrade = true
# Install the new cask # Install the new cask
new_cask_installer.stage new_cask_installer.stage
new_cask_installer.install_artifacts new_cask_installer.install_artifacts(predecessor: old_cask)
new_artifacts_installed = true new_artifacts_installed = true
# If successful, wipe the old cask from staging # If successful, wipe the old cask from staging
old_cask_installer.finalize_upgrade old_cask_installer.finalize_upgrade
rescue => e rescue => e
new_cask_installer.uninstall_artifacts if new_artifacts_installed new_cask_installer.uninstall_artifacts(successor: old_cask) if new_artifacts_installed
new_cask_installer.purge_versioned_files new_cask_installer.purge_versioned_files
old_cask_installer.revert_upgrade if started_upgrade old_cask_installer.revert_upgrade(predecessor: new_cask) if started_upgrade
raise e raise e
end end

View File

@ -0,0 +1,80 @@
#!/usr/bin/swift
import Foundation
struct SwiftErr: TextOutputStream {
public static var stream = SwiftErr()
mutating func write(_ string: String) {
fputs(string, stderr)
}
}
guard CommandLine.arguments.count >= 3 else {
print("Usage: swift copy-xattrs.swift <source> <dest>")
exit(2)
}
CommandLine.arguments[2].withCString { destinationPath in
let destinationNamesLength = listxattr(destinationPath, nil, 0, 0)
if destinationNamesLength == -1 {
print("listxattr for destination failed: \(errno)", to: &SwiftErr.stream)
exit(1)
}
let destinationNamesBuffer = UnsafeMutablePointer<Int8>.allocate(capacity: destinationNamesLength)
if listxattr(destinationPath, destinationNamesBuffer, destinationNamesLength, 0) != destinationNamesLength {
print("Attributes changed during system call", to: &SwiftErr.stream)
exit(1)
}
var destinationNamesIndex = 0
while destinationNamesIndex < destinationNamesLength {
let attribute = destinationNamesBuffer + destinationNamesIndex
if removexattr(destinationPath, attribute, 0) != 0 {
print("removexattr for \(String(cString: attribute)) failed: \(errno)", to: &SwiftErr.stream)
exit(1)
}
destinationNamesIndex += strlen(attribute) + 1
}
destinationNamesBuffer.deallocate()
CommandLine.arguments[1].withCString { sourcePath in
let sourceNamesLength = listxattr(sourcePath, nil, 0, 0)
if sourceNamesLength == -1 {
print("listxattr for source failed: \(errno)", to: &SwiftErr.stream)
exit(1)
}
let sourceNamesBuffer = UnsafeMutablePointer<Int8>.allocate(capacity: sourceNamesLength)
if listxattr(sourcePath, sourceNamesBuffer, sourceNamesLength, 0) != sourceNamesLength {
print("Attributes changed during system call", to: &SwiftErr.stream)
exit(1)
}
var sourceNamesIndex = 0
while sourceNamesIndex < sourceNamesLength {
let attribute = sourceNamesBuffer + sourceNamesIndex
let valueLength = getxattr(sourcePath, attribute, nil, 0, 0, 0)
if valueLength == -1 {
print("getxattr for \(String(cString: attribute)) failed: \(errno)", to: &SwiftErr.stream)
exit(1)
}
let valueBuffer = UnsafeMutablePointer<Int8>.allocate(capacity: valueLength)
if getxattr(sourcePath, attribute, valueBuffer, valueLength, 0, 0) != valueLength {
print("Attributes changed during system call", to: &SwiftErr.stream)
exit(1)
}
if setxattr(destinationPath, attribute, valueBuffer, valueLength, 0, 0) != 0 {
print("setxattr for \(String(cString: attribute)) failed: \(errno)", to: &SwiftErr.stream)
exit(1)
}
valueBuffer.deallocate()
sourceNamesIndex += strlen(attribute) + 1
}
sourceNamesBuffer.deallocate()
}
}

View File

@ -310,4 +310,29 @@ describe Cask::Artifact::App, :cask do
end end
end end
end end
describe "upgrade" do
# Fix for https://github.com/Homebrew/homebrew-cask/issues/102721
it "reuses the same directory" do
install_phase
contents_path = target_path.join("Contents/Info.plist")
expect(target_path).to exist
inode = target_path.stat.ino
expect(contents_path).to exist
app.uninstall_phase(command: command, force: force, successor: cask)
expect(target_path).to exist
expect(target_path.children).to be_empty
expect(contents_path).not_to exist
app.install_phase(command: command, adopt: adopt, force: force, predecessor: cask)
expect(target_path).to exist
expect(target_path.stat.ino).to eq(inode)
expect(contents_path).to exist
end
end
end end

View File

@ -12,6 +12,9 @@ describe Cask::Upgrade, :cask do
let(:local_transmission) { Cask::CaskLoader.load("local-transmission") } let(:local_transmission) { Cask::CaskLoader.load("local-transmission") }
let(:local_caffeine_path) { local_caffeine.config.appdir.join("Caffeine.app") } let(:local_caffeine_path) { local_caffeine.config.appdir.join("Caffeine.app") }
let(:local_caffeine) { Cask::CaskLoader.load("local-caffeine") } let(:local_caffeine) { Cask::CaskLoader.load("local-caffeine") }
let(:renamed_app) { Cask::CaskLoader.load("renamed-app") }
let(:renamed_app_old_path) { renamed_app.config.appdir.join("OldApp.app") }
let(:renamed_app_new_path) { renamed_app.config.appdir.join("NewApp.app") }
let(:args) { Homebrew::CLI::Args.new } let(:args) { Homebrew::CLI::Args.new }
context "when the upgrade is successful" do context "when the upgrade is successful" do
@ -21,6 +24,7 @@ describe Cask::Upgrade, :cask do
"outdated/local-transmission", "outdated/local-transmission",
"outdated/auto-updates", "outdated/auto-updates",
"outdated/version-latest", "outdated/version-latest",
"outdated/renamed-app",
] ]
end end
@ -40,6 +44,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
described_class.upgrade_casks(args: args) described_class.upgrade_casks(args: args)
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
@ -49,6 +58,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission).to be_installed expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.61") expect(local_transmission.versions).to include("2.61")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).not_to be_a_directory
expect(renamed_app_new_path).to be_a_directory
expect(renamed_app.versions).to include("2.0.0")
end end
it "updates only the Casks specified in the command line" do it "updates only the Casks specified in the command line" do
@ -60,6 +74,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
described_class.upgrade_casks(local_caffeine, args: args) described_class.upgrade_casks(local_caffeine, args: args)
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
@ -69,6 +88,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission).to be_installed expect(local_transmission).to be_installed
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
end end
it 'updates "auto_updates" and "latest" Casks when their tokens are provided in the command line' do it 'updates "auto_updates" and "latest" Casks when their tokens are provided in the command line' do
@ -106,6 +130,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_first).to be_a_directory expect(version_latest_path_first).to be_a_directory
expect(version_latest.versions).to include("latest") expect(version_latest.versions).to include("latest")
@ -127,6 +156,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.61") expect(local_transmission.versions).to include("2.61")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).not_to be_a_directory
expect(renamed_app_new_path).to be_a_directory
expect(renamed_app.versions).to include("2.0.0")
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_second).to be_a_directory expect(version_latest_path_second).to be_a_directory
expect(version_latest.versions).to include("latest") expect(version_latest.versions).to include("latest")
@ -186,6 +220,7 @@ describe Cask::Upgrade, :cask do
"outdated/local-transmission", "outdated/local-transmission",
"outdated/auto-updates", "outdated/auto-updates",
"outdated/version-latest", "outdated/version-latest",
"outdated/renamed-app",
] ]
end end
@ -207,6 +242,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
described_class.upgrade_casks(dry_run: true, args: args) described_class.upgrade_casks(dry_run: true, args: args)
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
@ -218,6 +258,12 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(local_transmission.versions).not_to include("2.61") expect(local_transmission.versions).not_to include("2.61")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
expect(renamed_app.versions).not_to include("2.0.0")
end end
it "would update only the Casks specified in the command line" do it "would update only the Casks specified in the command line" do
@ -255,6 +301,11 @@ describe Cask::Upgrade, :cask do
expect(auto_updates_path).to be_a_directory expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57") expect(auto_updates.versions).to include("2.57")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
described_class.upgrade_casks(local_caffeine, auto_updates, dry_run: true, args: args) described_class.upgrade_casks(local_caffeine, auto_updates, dry_run: true, args: args)
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
@ -266,6 +317,12 @@ describe Cask::Upgrade, :cask do
expect(auto_updates_path).to be_a_directory expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.57") expect(auto_updates.versions).to include("2.57")
expect(auto_updates.versions).not_to include("2.61") expect(auto_updates.versions).not_to include("2.61")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
expect(renamed_app.versions).not_to include("2.0.0")
end end
end end
@ -285,6 +342,11 @@ describe Cask::Upgrade, :cask do
expect(local_transmission_path).to be_a_directory expect(local_transmission_path).to be_a_directory
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
expect(version_latest).to be_installed expect(version_latest).to be_installed
# Change download sha so that :latest cask decides to update itself # Change download sha so that :latest cask decides to update itself
version_latest.download_sha_path.write("fake download sha") version_latest.download_sha_path.write("fake download sha")
@ -307,6 +369,12 @@ describe Cask::Upgrade, :cask do
expect(local_transmission.versions).to include("2.60") expect(local_transmission.versions).to include("2.60")
expect(local_transmission.versions).not_to include("2.61") expect(local_transmission.versions).not_to include("2.61")
expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_to be_a_directory
expect(renamed_app.versions).to include("1.0.0")
expect(renamed_app.versions).not_to include("2.0.0")
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest.outdated_download_sha?).to be(true) expect(version_latest.outdated_download_sha?).to be(true)
end end

View File

@ -0,0 +1,9 @@
cask "renamed-app" do
version "1.0.0"
sha256 "cf001ed6c81820e049dc7a353957dab8936b91f1956ee74ff0b3eb59791f1ad9"
url "file://#{TEST_FIXTURE_DIR}/cask/old-app.tar.gz"
homepage "https://brew.sh/"
app "OldApp.app"
end

View File

@ -0,0 +1,9 @@
cask "renamed-app" do
version "2.0.0"
sha256 "9f88a6f3d8a7977cd3c116c56ee7a20a3c69e838a1d4946f815a926a57883299"
url "file://#{TEST_FIXTURE_DIR}/cask/new-app.tar.gz"
homepage "https://brew.sh/"
app "NewApp.app"
end