Implement cask renames.

This commit is contained in:
Markus Reiter 2023-04-08 14:10:58 +02:00
parent 8ea287cc07
commit a3231a03fa
No known key found for this signature in database
GPG Key ID: 245293B51702655B
30 changed files with 469 additions and 256 deletions

View File

@ -46,8 +46,15 @@ module Homebrew
json_casks, updated = Homebrew::API.fetch_json_api_file "cask.jws.json", json_casks, updated = Homebrew::API.fetch_json_api_file "cask.jws.json",
target: HOMEBREW_CACHE_API/"cask.jws.json" target: HOMEBREW_CACHE_API/"cask.jws.json"
cache["renames"] = {}
cache["casks"] = json_casks.to_h do |json_cask| cache["casks"] = json_casks.to_h do |json_cask|
[json_cask["token"], json_cask.except("token")] token = json_cask.delete("token")
json_cask.fetch("old_tokens", []).each do |old_token|
cache["renames"][old_token] = token
end
[token, json_cask]
end end
updated updated
@ -61,7 +68,17 @@ module Homebrew
write_names(regenerate: json_updated) write_names(regenerate: json_updated)
end end
cache["casks"] cache.fetch("casks")
end
sig { returns(T::Hash[String, String]) }
def all_renames
unless cache.key?("renames")
json_updated = download_and_cache_data!
write_names(regenerate: json_updated)
end
cache.fetch("renames")
end end
sig { params(regenerate: T::Boolean).void } sig { params(regenerate: T::Boolean).void }

View File

@ -80,7 +80,7 @@ module Homebrew
cache["aliases"] cache["aliases"]
end end
sig { returns(Hash) } sig { returns(T::Hash[String, String]) }
def all_renames def all_renames
unless cache.key?("renames") unless cache.key?("renames")
json_updated = download_and_cache_data! json_updated = download_and_cache_data!

View File

@ -16,6 +16,7 @@ require "cask/dsl"
require "cask/installer" require "cask/installer"
require "cask/macos" require "cask/macos"
require "cask/metadata" require "cask/metadata"
require "cask/migrator"
require "cask/pkg" require "cask/pkg"
require "cask/quarantine" require "cask/quarantine"
require "cask/staged" require "cask/staged"

View File

@ -78,6 +78,17 @@ module Cask
end end
end end
# An old name for the cask.
sig { returns(T::Array[String]) }
def old_tokens
@old_tokens ||= if tap
tap.cask_renames
.flat_map { |old_token, new_token| (new_token == token) ? old_token : [] }
else
[]
end
end
def config=(config) def config=(config)
@config = config @config = config
@ -96,22 +107,18 @@ module Cask
define_method(method_name) { |&block| @dsl.send(method_name, &block) } define_method(method_name) { |&block| @dsl.send(method_name, &block) }
end end
sig { returns(T::Array[[String, String]]) } sig { params(caskroom_path: Pathname).returns(T::Array[[String, String]]) }
def timestamped_versions def timestamped_versions(caskroom_path: self.caskroom_path)
relative_paths = Pathname.glob(metadata_timestamped_path(version: "*", timestamp: "*")) relative_paths = Pathname.glob(metadata_timestamped_path(
version: "*", timestamp: "*",
caskroom_path: caskroom_path
))
.map { |p| p.relative_path_from(p.parent.parent) } .map { |p| p.relative_path_from(p.parent.parent) }
# Sorbet is unaware that Pathname is sortable: https://github.com/sorbet/sorbet/issues/6844 # Sorbet is unaware that Pathname is sortable: https://github.com/sorbet/sorbet/issues/6844
T.unsafe(relative_paths).sort_by(&:basename) # sort by timestamp T.unsafe(relative_paths).sort_by(&:basename) # sort by timestamp
.map { |p| p.split.map(&:to_s) } .map { |p| p.split.map(&:to_s) }
end end
def versions
timestamped_versions.map(&:first)
.reverse
.uniq
.reverse
end
def full_name def full_name
return token if tap.nil? return token if tap.nil?
return token if tap.user == "Homebrew" return token if tap.user == "Homebrew"
@ -119,8 +126,9 @@ module Cask
"#{tap.name}/#{token}" "#{tap.name}/#{token}"
end end
sig { returns(T::Boolean) }
def installed? def installed?
!versions.empty? installed_caskfile&.exist? || false
end end
# The caskfile is needed during installation when there are # The caskfile is needed during installation when there are
@ -131,18 +139,41 @@ module Cask
sig { returns(T.nilable(Time)) } sig { returns(T.nilable(Time)) }
def install_time def install_time
_, time = timestamped_versions.last # <caskroom_path>/.metadata/<version>/<timestamp>/Casks/<token>.{rb,json} -> <timestamp>
return unless time time = installed_caskfile&.dirname&.dirname&.basename&.to_s
Time.strptime(time, Metadata::TIMESTAMP_FORMAT) if time
Time.strptime(time, Metadata::TIMESTAMP_FORMAT)
end end
sig { returns(T.nilable(Pathname)) }
def installed_caskfile def installed_caskfile
installed_version = timestamped_versions.last installed_caskroom_path = caskroom_path
caskfile_dir = metadata_main_container_path.join(*installed_version, "Casks") installed_token = token
return caskfile_dir.join("#{token}.json") if caskfile_dir.join("#{token}.json").exist?
caskfile_dir.join("#{token}.rb") # Check if the cask is installed with an old name.
old_tokens.each do |old_token|
old_caskroom_path = Caskroom.path/old_token
next if !old_caskroom_path.directory? || old_caskroom_path.symlink?
installed_caskroom_path = old_caskroom_path
installed_token = old_token
break
end
installed_version = timestamped_versions(caskroom_path: installed_caskroom_path).last
return unless installed_version
caskfile_dir = metadata_main_container_path(caskroom_path: installed_caskroom_path)
.join(*installed_version, "Casks")
["json", "rb"]
.map { |ext| caskfile_dir.join("#{installed_token}.#{ext}") }
.find(&:exist?)
end
sig { returns(T.nilable(String)) }
def installed_version
# <caskroom_path>/.metadata/<version>/<timestamp>/Casks/<token>.{rb,json} -> <version>
installed_caskfile&.dirname&.dirname&.dirname&.basename&.to_s
end end
def config_path def config_path
@ -173,6 +204,7 @@ module Cask
current_download_sha.blank? || current_download_sha != new_download_sha current_download_sha.blank? || current_download_sha != new_download_sha
end end
sig { returns(Pathname) }
def caskroom_path def caskroom_path
@caskroom_path ||= Caskroom.path.join(token) @caskroom_path ||= Caskroom.path.join(token)
end end
@ -182,26 +214,23 @@ module Cask
greedy_auto_updates: greedy_auto_updates).empty? greedy_auto_updates: greedy_auto_updates).empty?
end end
# TODO: Rename to `outdated_version` and only return one version.
def outdated_versions(greedy: false, greedy_latest: false, greedy_auto_updates: false) def outdated_versions(greedy: false, greedy_latest: false, greedy_auto_updates: false)
# special case: tap version is not available # special case: tap version is not available
return [] if version.nil? return [] if version.nil?
if version.latest? if version.latest?
return versions if (greedy || greedy_latest) && outdated_download_sha? return [installed_version] if (greedy || greedy_latest) && outdated_download_sha?
return [] return []
elsif auto_updates && !greedy && !greedy_auto_updates elsif auto_updates && !greedy && !greedy_auto_updates
return [] return []
end end
installed = versions
current = installed.last
# not outdated unless there is a different version on tap # not outdated unless there is a different version on tap
return [] if current == version return [] if installed_version == version
# collect all installed versions that are different than tap version and return them [installed_version]
installed.reject { |v| v == version }
end end
def outdated_info(greedy, verbose, json, greedy_latest, greedy_auto_updates) def outdated_info(greedy, verbose, json, greedy_latest, greedy_auto_updates)
@ -279,6 +308,7 @@ module Cask
{ {
"token" => token, "token" => token,
"full_token" => full_name, "full_token" => full_name,
"old_tokens" => old_tokens,
"tap" => tap&.name, "tap" => tap&.name,
"name" => name, "name" => name,
"desc" => desc, "desc" => desc,
@ -287,7 +317,7 @@ module Cask
"url_specs" => url_specs, "url_specs" => url_specs,
"appcast" => appcast, "appcast" => appcast,
"version" => version, "version" => version,
"installed" => versions.last, "installed" => installed_version,
"outdated" => outdated?, "outdated" => outdated?,
"sha256" => sha256, "sha256" => sha256,
"artifacts" => artifacts_list, "artifacts" => artifacts_list,
@ -349,7 +379,7 @@ module Cask
def api_to_local_hash(hash) def api_to_local_hash(hash)
hash["token"] = token hash["token"] = token
hash["installed"] = versions.last hash["installed"] = installed_version
hash["outdated"] = outdated? hash["outdated"] = outdated?
hash hash
end end

View File

@ -401,11 +401,11 @@ module Cask
self.for(ref, need_path: true).path self.for(ref, need_path: true).path
end end
def self.load(ref, config: nil) def self.load(ref, config: nil, warn: true)
self.for(ref).load(config: config) self.for(ref, warn: warn).load(config: config)
end end
def self.for(ref, need_path: false) def self.for(ref, need_path: false, warn: true)
[ [
FromInstanceLoader, FromInstanceLoader,
FromContentLoader, FromContentLoader,
@ -422,7 +422,7 @@ module Cask
end end
end end
case (possible_tap_casks = tap_paths(ref)).count case (possible_tap_casks = tap_paths(ref, warn: warn)).count
when 1 when 1
return FromTapPathLoader.new(possible_tap_casks.first) return FromTapPathLoader.new(possible_tap_casks.first)
when 2..Float::INFINITY when 2..Float::INFINITY
@ -441,9 +441,13 @@ module Cask
Tap.default_cask_tap.cask_dir/"#{token.to_s.downcase}.rb" Tap.default_cask_tap.cask_dir/"#{token.to_s.downcase}.rb"
end end
def self.tap_paths(token) def self.tap_paths(token, warn: true)
token = token.to_s.downcase
Tap.map do |tap| Tap.map do |tap|
find_cask_in_tap(token.to_s.downcase, tap) new_token = tap.cask_renames[token]
opoo "Cask #{token} was renamed to #{new_token}." if new_token && warn
find_cask_in_tap(new_token || token, tap)
end.select(&:exist?) end.select(&:exist?)
end end

View File

@ -13,11 +13,18 @@ module Cask
@path ||= HOMEBREW_PREFIX/"Caskroom" @path ||= HOMEBREW_PREFIX/"Caskroom"
end end
# Return all paths for installed casks.
sig { returns(T::Array[Pathname]) }
def self.paths
return [] unless path.exist?
path.children.select { |p| p.directory? && !p.symlink? }
end
private_class_method :paths
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def self.any_casks_installed? def self.any_casks_installed?
return false unless path.exist? paths.any?
path.children.select(&:directory?).any?
end end
sig { void } sig { void }
@ -39,9 +46,7 @@ module Cask
sig { params(config: T.nilable(Config)).returns(T::Array[Cask]) } sig { params(config: T.nilable(Config)).returns(T::Array[Cask]) }
def self.casks(config: nil) def self.casks(config: nil)
return [] unless path.exist? paths.sort.map do |path|
path.children.select(&:directory?).sort.map do |path|
token = path.basename.to_s token = path.basename.to_s
begin begin

View File

@ -39,17 +39,14 @@ module Cask
def self.installation_info(cask) def self.installation_info(cask)
return "Not installed\n" unless cask.installed? return "Not installed\n" unless cask.installed?
install_info = +"" versioned_staged_path = cask.caskroom_path.join(cask.installed_version)
cask.versions.each do |version| path_details = if versioned_staged_path.exist?
versioned_staged_path = cask.caskroom_path.join(version) versioned_staged_path.abv
path_details = if versioned_staged_path.exist? else
versioned_staged_path.abv Formatter.error("does not exist")
else
Formatter.error("does not exist")
end
install_info << "#{versioned_staged_path} (#{path_details})\n"
end end
install_info.freeze
"#{versioned_staged_path} (#{path_details})\n"
end end
def self.name_info(cask) def self.name_info(cask)

View File

@ -7,6 +7,7 @@ require "utils/topological_hash"
require "cask/config" require "cask/config"
require "cask/download" require "cask/download"
require "cask/migrator"
require "cask/quarantine" require "cask/quarantine"
require "cgi" require "cgi"
@ -87,6 +88,8 @@ module Cask
start_time = Time.now start_time = Time.now
odebug "Cask::Installer#install" odebug "Cask::Installer#install"
Migrator.migrate_if_needed(@cask)
old_config = @cask.config old_config = @cask.config
if @cask.installed? && !force? && !reinstall? && !upgrade? if @cask.installed? && !force? && !reinstall? && !upgrade?
return if quiet? return if quiet?
@ -227,8 +230,9 @@ 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(
predecessor: predecessor) command: @command, verbose: verbose?, adopt: adopt?, force: force?, predecessor: predecessor,
)
already_installed_artifacts.unshift(artifact) already_installed_artifacts.unshift(artifact)
end end
@ -382,7 +386,6 @@ on_request: true)
end end
def save_config_file def save_config_file
metadata_subdir
@cask.config_path.atomic_write(@cask.config.to_json) @cask.config_path.atomic_write(@cask.config.to_json)
end end
@ -408,7 +411,8 @@ on_request: true)
end end
def remove_download_sha def remove_download_sha
FileUtils.rm_f @cask.download_sha_path if @cask.download_sha_path.exist? FileUtils.rm_f @cask.download_sha_path
@cask.download_sha_path.parent.rmdir_if_possible
end end
def start_upgrade(successor:) def start_upgrade(successor:)
@ -424,8 +428,8 @@ on_request: true)
def restore_backup def restore_backup
return if !backup_path.directory? || !backup_metadata_path.directory? return if !backup_path.directory? || !backup_metadata_path.directory?
Pathname.new(@cask.staged_path).rmtree if @cask.staged_path.exist? @cask.staged_path.rmtree if @cask.staged_path.exist?
Pathname.new(@cask.metadata_versioned_path).rmtree if @cask.metadata_versioned_path.exist? @cask.metadata_versioned_path.rmtree if @cask.metadata_versioned_path.exist?
backup_path.rename @cask.staged_path backup_path.rename @cask.staged_path
backup_metadata_path.rename @cask.metadata_versioned_path backup_metadata_path.rename @cask.metadata_versioned_path
@ -539,6 +543,12 @@ on_request: true)
# toplevel staged distribution # toplevel staged distribution
@cask.caskroom_path.rmdir_if_possible unless upgrade? @cask.caskroom_path.rmdir_if_possible unless upgrade?
# Remove symlinks for renamed casks if they are now broken.
@cask.old_tokens.each do |old_token|
old_caskroom_path = Caskroom.path/old_token
FileUtils.rm old_caskroom_path if old_caskroom_path.symlink? && !old_caskroom_path.exist?
end
end end
def purge_caskroom_path def purge_caskroom_path
@ -550,9 +560,11 @@ on_request: true)
# load the same cask file that was used for installation, if possible # load the same cask file that was used for installation, if possible
def load_installed_caskfile! def load_installed_caskfile!
Migrator.migrate_if_needed(@cask)
installed_caskfile = @cask.installed_caskfile installed_caskfile = @cask.installed_caskfile
if installed_caskfile.exist? if installed_caskfile&.exist?
begin begin
@cask = CaskLoader.load(installed_caskfile) @cask = CaskLoader.load(installed_caskfile)
return return

View File

@ -43,7 +43,7 @@ module Cask
end end
def self.format_versioned(cask) def self.format_versioned(cask)
cask.to_s.concat(cask.versions.map(&:to_s).join(" ").prepend(" ")) "#{cask}#{cask.installed_version&.prepend(" ")}"
end end
end end
end end

View File

@ -9,26 +9,27 @@ module Cask
METADATA_SUBDIR = ".metadata" METADATA_SUBDIR = ".metadata"
TIMESTAMP_FORMAT = "%Y%m%d%H%M%S.%L" TIMESTAMP_FORMAT = "%Y%m%d%H%M%S.%L"
def metadata_main_container_path def metadata_main_container_path(caskroom_path: self.caskroom_path)
@metadata_main_container_path ||= caskroom_path.join(METADATA_SUBDIR) caskroom_path.join(METADATA_SUBDIR)
end end
def metadata_versioned_path(version: self.version) def metadata_versioned_path(version: self.version, caskroom_path: self.caskroom_path)
cask_version = (version || :unknown).to_s cask_version = (version || :unknown).to_s
raise CaskError, "Cannot create metadata path with empty version." if cask_version.empty? raise CaskError, "Cannot create metadata path with empty version." if cask_version.empty?
metadata_main_container_path.join(cask_version) metadata_main_container_path(caskroom_path: caskroom_path).join(cask_version)
end end
def metadata_timestamped_path(version: self.version, timestamp: :latest, create: false) def metadata_timestamped_path(version: self.version, timestamp: :latest, create: false,
caskroom_path: self.caskroom_path)
raise CaskError, "Cannot create metadata path when timestamp is :latest." if create && timestamp == :latest raise CaskError, "Cannot create metadata path when timestamp is :latest." if create && timestamp == :latest
path = if timestamp == :latest path = if timestamp == :latest
Pathname.glob(metadata_versioned_path(version: version).join("*")).max Pathname.glob(metadata_versioned_path(version: version, caskroom_path: caskroom_path).join("*")).max
else else
timestamp = new_timestamp if timestamp == :now timestamp = new_timestamp if timestamp == :now
metadata_versioned_path(version: version).join(timestamp) metadata_versioned_path(version: version, caskroom_path: caskroom_path).join(timestamp)
end end
if create && !path.directory? if create && !path.directory?
@ -39,11 +40,13 @@ module Cask
path path
end end
def metadata_subdir(leaf, version: self.version, timestamp: :latest, create: false) def metadata_subdir(leaf, version: self.version, timestamp: :latest, create: false,
caskroom_path: self.caskroom_path)
raise CaskError, "Cannot create metadata subdir when timestamp is :latest." if create && timestamp == :latest raise CaskError, "Cannot create metadata subdir when timestamp is :latest." if create && timestamp == :latest
raise CaskError, "Cannot create metadata subdir for empty leaf." if !leaf.respond_to?(:empty?) || leaf.empty? raise CaskError, "Cannot create metadata subdir for empty leaf." if !leaf.respond_to?(:empty?) || leaf.empty?
parent = metadata_timestamped_path(version: version, timestamp: timestamp, create: create) parent = metadata_timestamped_path(version: version, timestamp: timestamp, create: create,
caskroom_path: caskroom_path)
return if parent.nil? return if parent.nil?

View File

@ -0,0 +1,86 @@
# typed: true
# frozen_string_literal: true
require "cask/cask_loader"
require "utils/inreplace"
module Cask
class Migrator
extend ::Utils::Inreplace
attr_reader :old_cask, :new_cask
sig { params(old_cask: Cask, new_cask: Cask).void }
def initialize(old_cask, new_cask)
raise CaskNotInstalledError, new_cask unless new_cask.installed?
@old_cask = old_cask
@new_cask = new_cask
end
sig { params(new_cask: Cask, dry_run: T::Boolean).void }
def self.migrate_if_needed(new_cask, dry_run: false)
old_tokens = new_cask.old_tokens
return if old_tokens.empty?
return unless (installed_caskfile = new_cask.installed_caskfile)
installed_token = installed_caskfile.relative_path_from(Caskroom.path).basename.to_s
return if new_cask.token == installed_token
old_cask = CaskLoader.load(installed_caskfile)
migrator = new(old_cask, new_cask)
migrator.migrate(dry_run: dry_run)
end
sig { params(dry_run: T::Boolean).void }
def migrate(dry_run: false)
old_token = old_cask.token
new_token = new_cask.token
old_caskroom_path = old_cask.caskroom_path
new_caskroom_path = new_cask.caskroom_path
old_installed_caskfile = old_cask.installed_caskfile.relative_path_from(old_caskroom_path)
new_installed_caskfile = old_installed_caskfile.dirname/old_installed_caskfile.basename.sub(
old_token,
new_token,
)
if dry_run
oh1 "Would migrate cask #{Formatter.identifier(old_token)} to #{Formatter.identifier(new_token)}"
puts "cp -r #{old_caskroom_path} #{new_caskroom_path}"
puts "mv #{new_caskroom_path}/#{old_installed_caskfile} #{new_caskroom_path}/#{new_installed_caskfile}"
puts "rm -r #{old_caskroom_path}"
puts "ln -s #{new_caskroom_path.basename} #{old_caskroom_path}"
else
oh1 "Migrating cask #{Formatter.identifier(old_token)} to #{Formatter.identifier(new_token)}"
begin
FileUtils.cp_r old_caskroom_path, new_caskroom_path
FileUtils.mv new_caskroom_path/old_installed_caskfile, new_caskroom_path/new_installed_caskfile
self.class.replace_caskfile_token(new_caskroom_path/new_installed_caskfile, old_token, new_token)
rescue => e
FileUtils.rm_rf new_caskroom_path
raise e
end
FileUtils.rm_r old_caskroom_path
FileUtils.ln_s new_caskroom_path.basename, old_caskroom_path
end
end
sig { params(path: Pathname, old_token: String, new_token: String).void }
def self.replace_caskfile_token(path, old_token, new_token)
case path.extname
when ".rb"
inreplace path, /\A\s*cask\s+"#{Regexp.escape(old_token)}"/, "cask #{new_token.inspect}"
when ".json"
json = JSON.parse(path.read)
json["token"] = new_token
path.atomic_write json.to_json
end
end
end
end

View File

@ -13,13 +13,6 @@ module Cask
raise CaskNotInstalledError, cask if !cask.installed? && !force raise CaskNotInstalledError, cask if !cask.installed? && !force
Installer.new(cask, binaries: binaries, force: force, verbose: verbose).uninstall Installer.new(cask, binaries: binaries, force: force, verbose: verbose).uninstall
next if (versions = cask.versions).empty?
puts <<~EOS
#{cask} #{versions.to_sentence} #{(versions.count == 1) ? "is" : "are"} still installed.
Remove #{(versions.count == 1) ? "it" : "them all"} with `brew uninstall --cask --force #{cask}`.
EOS
end end
end end
end end

View File

@ -95,8 +95,7 @@ module Cask
caught_exceptions = [] caught_exceptions = []
upgradable_casks = outdated_casks.map do |c| upgradable_casks = outdated_casks.map do |c|
if !c.installed_caskfile.exist? && c.tap.to_s == "homebrew/cask" && if !c.installed? && c.tap.to_s == "homebrew/cask" && Homebrew::API::Cask.all_casks.key?(c.token)
Homebrew::API::Cask.all_casks.key?(c.token)
odie <<~EOS odie <<~EOS
The cask '#{c.token}' was affected by a bug and cannot be upgraded as-is. To fix this, run: The cask '#{c.token}' was affected by a bug and cannot be upgraded as-is. To fix this, run:
brew reinstall --cask --force #{c.token} brew reinstall --cask --force #{c.token}
@ -192,7 +191,7 @@ module Cask
new_cask_installer.install_artifacts(predecessor: old_cask) 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(successor: old_cask) if new_artifacts_installed new_cask_installer.uninstall_artifacts(successor: old_cask) if new_artifacts_installed

View File

@ -155,7 +155,7 @@ module Homebrew
return false if cask.blank? return false if cask.blank?
return true unless basename.to_s.match?(/\A#{Regexp.escape(name)}--#{Regexp.escape(cask.version)}\b/) return true unless basename.to_s.match?(/\A#{Regexp.escape(name)}--#{Regexp.escape(cask.version)}\b/)
return true if scrub && cask.versions.exclude?(cask.version) return true if scrub && cask.installed_version != cask.version
if cask.version.latest? if cask.version.latest?
cleanup_threshold = (DateTime.now - CLEANUP_DEFAULT_DAYS).to_time cleanup_threshold = (DateTime.now - CLEANUP_DEFAULT_DAYS).to_time

View File

@ -47,12 +47,14 @@ module Homebrew
ignore_unavailable: T.nilable(T::Boolean), ignore_unavailable: T.nilable(T::Boolean),
method: T.nilable(Symbol), method: T.nilable(Symbol),
uniq: T::Boolean, uniq: T::Boolean,
warn: T::Boolean,
).returns(T::Array[T.any(Formula, Keg, Cask::Cask)]) ).returns(T::Array[T.any(Formula, Keg, Cask::Cask)])
} }
def to_formulae_and_casks(only: parent&.only_formula_or_cask, ignore_unavailable: nil, method: nil, uniq: true) def to_formulae_and_casks(only: parent&.only_formula_or_cask, ignore_unavailable: nil, method: nil, uniq: true,
warn: true)
@to_formulae_and_casks ||= {} @to_formulae_and_casks ||= {}
@to_formulae_and_casks[only] ||= downcased_unique_named.flat_map do |name| @to_formulae_and_casks[only] ||= downcased_unique_named.flat_map do |name|
load_formula_or_cask(name, only: only, method: method) load_formula_or_cask(name, only: only, method: method, warn: warn)
rescue FormulaUnreadableError, FormulaClassUnavailableError, rescue FormulaUnreadableError, FormulaClassUnavailableError,
TapFormulaUnreadableError, TapFormulaClassUnavailableError, TapFormulaUnreadableError, TapFormulaClassUnavailableError,
Cask::CaskUnreadableError Cask::CaskUnreadableError
@ -86,14 +88,14 @@ module Homebrew
end.uniq.freeze end.uniq.freeze
end end
def load_formula_or_cask(name, only: nil, method: nil) def load_formula_or_cask(name, only: nil, method: nil, warn: true)
unreadable_error = nil unreadable_error = nil
if only != :cask if only != :cask
begin begin
formula = case method formula = case method
when nil, :factory when nil, :factory
Formulary.factory(name, *spec, force_bottle: @force_bottle, flags: @flags) Formulary.factory(name, *spec, force_bottle: @force_bottle, flags: @flags, warn: warn)
when :resolve when :resolve
resolve_formula(name) resolve_formula(name)
when :latest_kegs when :latest_kegs
@ -124,7 +126,7 @@ module Homebrew
begin begin
config = Cask::Config.from_args(@parent) if @cask_options config = Cask::Config.from_args(@parent) if @cask_options
cask = Cask::CaskLoader.load(name, config: config) cask = Cask::CaskLoader.load(name, config: config, warn: warn)
if unreadable_error.present? if unreadable_error.present?
onoe <<~EOS onoe <<~EOS
@ -145,7 +147,7 @@ module Homebrew
# If we're trying to get a keg-like Cask, do our best to handle it # If we're trying to get a keg-like Cask, do our best to handle it
# not being readable and return something that can be used. # not being readable and return something that can be used.
if want_keg_like_cask if want_keg_like_cask
cask_version = Cask::Cask.new(name, config: config).versions.first cask_version = Cask::Cask.new(name, config: config).installed_version
cask = Cask::Cask.new(name, config: config) do cask = Cask::Cask.new(name, config: config) do
version cask_version if cask_version version cask_version if cask_version
end end

View File

@ -3,12 +3,11 @@
require "migrator" require "migrator"
require "cli/parser" require "cli/parser"
require "cask/migrator"
module Homebrew module Homebrew
module_function
sig { returns(CLI::Parser) } sig { returns(CLI::Parser) }
def migrate_args def self.migrate_args
Homebrew::CLI::Parser.new do Homebrew::CLI::Parser.new do
description <<~EOS description <<~EOS
Migrate renamed packages to new names, where <formula> are old names of Migrate renamed packages to new names, where <formula> are old names of
@ -19,17 +18,27 @@ module Homebrew
"the same taps and migrate them anyway." "the same taps and migrate them anyway."
switch "-n", "--dry-run", switch "-n", "--dry-run",
description: "Show what would be migrated, but do not actually migrate anything." description: "Show what would be migrated, but do not actually migrate anything."
switch "--formula", "--formulae",
description: "Only migrate formulae."
switch "--cask", "--casks",
description: "Only migrate casks."
named_args :installed_formula, min: 1 conflicts "--formula", "--cask"
named_args [:installed_formula, :installed_cask], min: 1
end end
end end
def migrate def self.migrate
args = migrate_args.parse args = migrate_args.parse
args.named.to_kegs.each do |keg| args.named.to_formulae_and_casks(warn: false).each do |formula_or_cask|
f = Formulary.from_keg(keg) case formula_or_cask
Migrator.migrate_if_needed(f, force: args.force?, dry_run: args.dry_run?) when Formula
Migrator.migrate_if_needed(formula_or_cask, force: args.force?, dry_run: args.dry_run?)
when Cask::Cask
Cask::Migrator.migrate_if_needed(formula_or_cask, dry_run: args.dry_run?)
end
end end
end end
end end

View File

@ -3,6 +3,7 @@
require "migrator" require "migrator"
require "formulary" require "formulary"
require "cask/cask_loader"
require "descriptions" require "descriptions"
require "cleanup" require "cleanup"
require "description_cache_store" require "description_cache_store"
@ -246,6 +247,7 @@ module Homebrew
hub.dump(auto_update: args.auto_update?) unless args.quiet? hub.dump(auto_update: args.auto_update?) unless args.quiet?
hub.reporters.each(&:migrate_tap_migration) hub.reporters.each(&:migrate_tap_migration)
hub.reporters.each(&:migrate_cask_rename)
hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?, verbose: args.verbose?) } hub.reporters.each { |r| r.migrate_formula_rename(force: args.force?, verbose: args.verbose?) }
CacheStoreDatabase.use(:descriptions) do |db| CacheStoreDatabase.use(:descriptions) do |db|
@ -390,6 +392,14 @@ class Reporter
when "M" when "M"
# Report updated casks # Report updated casks
@report[:MC] << tap.formula_file_to_name(src) @report[:MC] << tap.formula_file_to_name(src)
when /^R\d{0,3}/
src_full_name = tap.formula_file_to_name(src)
dst_full_name = tap.formula_file_to_name(dst)
# Don't report formulae that are moved within a tap but not renamed
next if src_full_name == dst_full_name
@report[:DC] << src_full_name
@report[:AC] << dst_full_name
end end
end end
@ -416,6 +426,41 @@ class Reporter
end end
end end
renamed_casks = Set.new
@report[:DC].each do |old_full_name|
old_name = old_full_name.split("/").last
new_name = tap.cask_renames[old_name]
next unless new_name
new_full_name = if tap.name == "homebrew/cask"
new_name
else
"#{tap}/#{new_name}"
end
renamed_casks << [old_full_name, new_full_name] if @report[:AC].include?(new_full_name)
end
@report[:AC].each do |new_full_name|
new_name = new_full_name.split("/").last
old_name = tap.cask_renames.key(new_name)
next unless old_name
old_full_name = if tap.name == "homebrew/cask"
old_name
else
"#{tap}/#{old_name}"
end
renamed_casks << [old_full_name, new_full_name]
end
if renamed_casks.any?
@report[:AC] -= renamed_casks.map(&:last)
@report[:DC] -= renamed_casks.map(&:first)
@report[:RC] = renamed_casks.to_a
end
renamed_formulae = Set.new renamed_formulae = Set.new
@report[:D].each do |old_full_name| @report[:D].each do |old_full_name|
old_name = old_full_name.split("/").last old_name = old_full_name.split("/").last
@ -445,7 +490,7 @@ class Reporter
renamed_formulae << [old_full_name, new_full_name] renamed_formulae << [old_full_name, new_full_name]
end end
if renamed_formulae.present? if renamed_formulae.any?
@report[:A] -= renamed_formulae.map(&:last) @report[:A] -= renamed_formulae.map(&:last)
@report[:D] -= renamed_formulae.map(&:first) @report[:D] -= renamed_formulae.map(&:first)
@report[:R] = renamed_formulae.to_a @report[:R] = renamed_formulae.to_a
@ -541,6 +586,12 @@ class Reporter
end end
end end
def migrate_cask_rename
Cask::Caskroom.casks.each do |cask|
Cask::Migrator.migrate_if_needed(cask)
end
end
def migrate_formula_rename(force:, verbose:) def migrate_formula_rename(force:, verbose:)
Formula.installed.each do |formula| Formula.installed.each do |formula|
next unless Migrator.needs_migration?(formula) next unless Migrator.needs_migration?(formula)
@ -631,6 +682,7 @@ class ReporterHub
dump_new_formula_report dump_new_formula_report
dump_new_cask_report dump_new_cask_report
dump_renamed_formula_report if report_all dump_renamed_formula_report if report_all
dump_renamed_cask_report if report_all
dump_deleted_formula_report(report_all) dump_deleted_formula_report(report_all)
dump_deleted_cask_report(report_all) dump_deleted_cask_report(report_all)
@ -723,6 +775,16 @@ class ReporterHub
output_dump_formula_or_cask_report "Renamed Formulae", formulae output_dump_formula_or_cask_report "Renamed Formulae", formulae
end end
def dump_renamed_cask_report
casks = select_formula_or_cask(:RC).sort.map do |name, new_name|
name = pretty_installed(name) if installed?(name)
new_name = pretty_installed(new_name) if installed?(new_name)
"#{name} -> #{new_name}"
end
output_dump_formula_or_cask_report "Renamed Casks", casks
end
def dump_deleted_formula_report(report_all) def dump_deleted_formula_report(report_all)
formulae = select_formula_or_cask(:D).sort.map do |name| formulae = select_formula_or_cask(:D).sort.map do |name|
if installed?(name) if installed?(name)

View File

@ -502,7 +502,8 @@ class Formula
# Old names for the formula. # Old names for the formula.
def oldnames def oldnames
@oldnames ||= if tap @oldnames ||= if tap
tap.formula_renames.select { |_, oldname| oldname == name }.keys tap.formula_renames
.flat_map { |old_name, new_name| (new_name == name) ? old_name : [] }
else else
[] []
end end

View File

@ -523,8 +523,7 @@ module Formulary
# Loads tapped formulae. # Loads tapped formulae.
class TapLoader < FormulaLoader class TapLoader < FormulaLoader
def initialize(tapped_name, from: nil) def initialize(tapped_name, from: nil, warn: true)
warn = [:keg, :rack].exclude?(from)
name, path, tap = formula_name_path(tapped_name, warn: warn) name, path, tap = formula_name_path(tapped_name, warn: warn)
super name, path, tap: tap super name, path, tap: tap
end end
@ -555,7 +554,7 @@ module Formulary
new_name = new_tap.core_tap? ? name : new_tapped_name new_name = new_tap.core_tap? ? name : new_tapped_name
end end
opoo "Use #{new_name} instead of deprecated #{old_name}" if warn && old_name && new_name opoo "Formula #{old_name} was renamed to #{new_name}." if warn && old_name && new_name
end end
[name, path, tap] [name, path, tap]
@ -649,7 +648,7 @@ module Formulary
# * a formula URL # * a formula URL
# * a local bottle reference # * a local bottle reference
def self.factory( def self.factory(
ref, spec = :stable, alias_path: nil, from: nil, ref, spec = :stable, alias_path: nil, from: nil, warn: true,
force_bottle: false, flags: [], ignore_errors: false force_bottle: false, flags: [], ignore_errors: false
) )
raise ArgumentError, "Formulae must have a ref!" unless ref raise ArgumentError, "Formulae must have a ref!" unless ref
@ -660,7 +659,7 @@ module Formulary
return cache[:formulary_factory][cache_key] return cache[:formulary_factory][cache_key]
end end
formula = loader_for(ref, from: from).get_formula(spec, alias_path: alias_path, formula = loader_for(ref, from: from, warn: warn).get_formula(spec, alias_path: alias_path,
force_bottle: force_bottle, flags: flags, force_bottle: force_bottle, flags: flags,
ignore_errors: ignore_errors) ignore_errors: ignore_errors)
if factory_cached? if factory_cached?
@ -683,7 +682,7 @@ module Formulary
if keg if keg
from_keg(keg, spec, alias_path: alias_path, force_bottle: force_bottle, flags: flags) from_keg(keg, spec, alias_path: alias_path, force_bottle: force_bottle, flags: flags)
else else
factory(rack.basename.to_s, spec || :stable, alias_path: alias_path, from: :rack, factory(rack.basename.to_s, spec || :stable, alias_path: alias_path, from: :rack, warn: false,
force_bottle: force_bottle, flags: flags) force_bottle: force_bottle, flags: flags)
end end
end end
@ -704,15 +703,15 @@ module Formulary
spec ||= tab.spec spec ||= tab.spec
f = if tap.nil? f = if tap.nil?
factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg, factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg, warn: false,
force_bottle: force_bottle, flags: flags) force_bottle: force_bottle, flags: flags)
else else
begin begin
factory("#{tap}/#{keg.rack.basename}", spec, alias_path: alias_path, from: :keg, factory("#{tap}/#{keg.rack.basename}", spec, alias_path: alias_path, from: :keg, warn: false,
force_bottle: force_bottle, flags: flags) force_bottle: force_bottle, flags: flags)
rescue FormulaUnavailableError rescue FormulaUnavailableError
# formula may be migrated to different tap. Try to search in core and all taps. # formula may be migrated to different tap. Try to search in core and all taps.
factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg, factory(keg.rack.basename.to_s, spec, alias_path: alias_path, from: :keg, warn: false,
force_bottle: force_bottle, flags: flags) force_bottle: force_bottle, flags: flags)
end end
end end
@ -757,7 +756,7 @@ module Formulary
loader_for(ref).path loader_for(ref).path
end end
def self.loader_for(ref, from: nil) def self.loader_for(ref, from: nil, warn: true)
case ref case ref
when HOMEBREW_BOTTLES_EXTNAME_REGEX when HOMEBREW_BOTTLES_EXTNAME_REGEX
return BottleLoader.new(ref) return BottleLoader.new(ref)
@ -770,7 +769,7 @@ module Formulary
return AliasAPILoader.new(name) if Homebrew::API::Formula.all_aliases.key?(name) return AliasAPILoader.new(name) if Homebrew::API::Formula.all_aliases.key?(name)
end end
return TapLoader.new(ref, from: from) return TapLoader.new(ref, from: from, warn: warn)
end end
pathname_ref = Pathname.new(ref) pathname_ref = Pathname.new(ref)
@ -800,7 +799,9 @@ module Formulary
return FormulaLoader.new(name, path) return FormulaLoader.new(name, path)
end end
return TapLoader.new("#{CoreTap.instance}/#{ref}", from: from) if CoreTap.instance.formula_renames.key?(ref) if CoreTap.instance.formula_renames.key?(ref)
return TapLoader.new("#{CoreTap.instance}/#{ref}", from: from, warn: warn)
end
possible_taps = Tap.select { |tap| tap.formula_renames.key?(ref) } possible_taps = Tap.select { |tap| tap.formula_renames.key?(ref) }
@ -809,7 +810,7 @@ module Formulary
raise TapFormulaWithOldnameAmbiguityError.new(ref, possible_tap_newname_formulae) raise TapFormulaWithOldnameAmbiguityError.new(ref, possible_tap_newname_formulae)
end end
return TapLoader.new("#{possible_taps.first}/#{ref}", from: from) unless possible_taps.empty? return TapLoader.new("#{possible_taps.first}/#{ref}", from: from, warn: warn) unless possible_taps.empty?
possible_keg_formula = Pathname.new("#{HOMEBREW_PREFIX}/opt/#{ref}/.brew/#{ref}.rb") possible_keg_formula = Pathname.new("#{HOMEBREW_PREFIX}/opt/#{ref}/.brew/#{ref}.rb")
return FormulaLoader.new(ref, possible_keg_formula) if possible_keg_formula.file? return FormulaLoader.new(ref, possible_keg_formula) if possible_keg_formula.file?

View File

@ -106,15 +106,14 @@ class Migrator
def self.migrate_if_needed(formula, force:, dry_run: false) def self.migrate_if_needed(formula, force:, dry_run: false)
oldnames = Migrator.oldnames_needing_migration(formula) oldnames = Migrator.oldnames_needing_migration(formula)
return if oldnames.empty?
begin begin
if dry_run
ohai "Would migrate #{oldnames.to_sentence} to #{formula.name}"
return
end
oldnames.each do |oldname| oldnames.each do |oldname|
if dry_run
oh1 "Would migrate formula #{Formatter.identifier(oldname)} to #{Formatter.identifier(formula.name)}"
next
end
migrator = Migrator.new(formula, oldname, force: force) migrator = Migrator.new(formula, oldname, force: force)
migrator.migrate migrator.migrate
end end
@ -205,7 +204,7 @@ class Migrator
end end
def migrate def migrate
oh1 "Processing #{Formatter.identifier(oldname)} formula rename to #{Formatter.identifier(newname)}" oh1 "Migrating formula #{Formatter.identifier(oldname)} to #{Formatter.identifier(newname)}"
lock lock
unlink_oldname unlink_oldname
unlink_newname if new_cellar.exist? unlink_newname if new_cellar.exist?

View File

@ -18,6 +18,7 @@ class Tap
TAP_DIRECTORY = (HOMEBREW_LIBRARY/"Taps").freeze TAP_DIRECTORY = (HOMEBREW_LIBRARY/"Taps").freeze
HOMEBREW_TAP_CASK_RENAMES_FILE = "cask_renames.json"
HOMEBREW_TAP_FORMULA_RENAMES_FILE = "formula_renames.json" HOMEBREW_TAP_FORMULA_RENAMES_FILE = "formula_renames.json"
HOMEBREW_TAP_MIGRATIONS_FILE = "tap_migrations.json" HOMEBREW_TAP_MIGRATIONS_FILE = "tap_migrations.json"
HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions" HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR = "audit_exceptions"
@ -26,6 +27,7 @@ class Tap
HOMEBREW_TAP_JSON_FILES = %W[ HOMEBREW_TAP_JSON_FILES = %W[
#{HOMEBREW_TAP_FORMULA_RENAMES_FILE} #{HOMEBREW_TAP_FORMULA_RENAMES_FILE}
#{HOMEBREW_TAP_CASK_RENAMES_FILE}
#{HOMEBREW_TAP_MIGRATIONS_FILE} #{HOMEBREW_TAP_MIGRATIONS_FILE}
#{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json #{HOMEBREW_TAP_AUDIT_EXCEPTIONS_DIR}/*.json
#{HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR}/*.json #{HOMEBREW_TAP_STYLE_EXCEPTIONS_DIR}/*.json
@ -687,8 +689,20 @@ class Tap
hash hash
end end
# Hash with tap cask renames.
sig { returns(T::Hash[String, String]) }
def cask_renames
@cask_renames ||= if name == "homebrew/cask" && !Homebrew::EnvConfig.no_install_from_api?
Homebrew::API::Cask.all_renames
elsif (rename_file = path/HOMEBREW_TAP_CASK_RENAMES_FILE).file?
JSON.parse(rename_file.read)
else
{}
end
end
# Hash with tap formula renames. # Hash with tap formula renames.
sig { returns(Hash) } sig { returns(T::Hash[String, String]) }
def formula_renames def formula_renames
@formula_renames ||= if (rename_file = path/HOMEBREW_TAP_FORMULA_RENAMES_FILE).file? @formula_renames ||= if (rename_file = path/HOMEBREW_TAP_FORMULA_RENAMES_FILE).file?
JSON.parse(rename_file.read) JSON.parse(rename_file.read)
@ -931,7 +945,7 @@ class CoreTap < Tap
end end
# @private # @private
sig { returns(Hash) } sig { returns(T::Hash[String, String]) }
def formula_renames def formula_renames
@formula_renames ||= if Homebrew::EnvConfig.no_install_from_api? @formula_renames ||= if Homebrew::EnvConfig.no_install_from_api?
self.class.ensure_installed! self.class.ensure_installed!

View File

@ -4,7 +4,7 @@ describe Cask::Cask, :cask do
let(:cask) { described_class.new("versioned-cask") } let(:cask) { described_class.new("versioned-cask") }
context "when multiple versions are installed" do context "when multiple versions are installed" do
describe "#versions" do describe "#installed_version" do
context "when there are duplicate versions" do context "when there are duplicate versions" do
it "uses the last unique version" do it "uses the last unique version" do
allow(cask).to receive(:timestamped_versions).and_return([ allow(cask).to receive(:timestamped_versions).and_return([
@ -13,11 +13,11 @@ describe Cask::Cask, :cask do
["1.2.2", "1001"], ["1.2.2", "1001"],
]) ])
# Installed caskfile must exist to count as installed.
allow_any_instance_of(Pathname).to receive(:exist?).and_return(true)
expect(cask).to receive(:timestamped_versions) expect(cask).to receive(:timestamped_versions)
expect(cask.versions).to eq([ expect(cask.installed_version).to eq("1.2.2")
"1.2.3",
"1.2.2",
])
end end
end end
end end
@ -104,10 +104,10 @@ describe Cask::Cask, :cask do
let(:cask) { described_class.new("basic-cask") } let(:cask) { described_class.new("basic-cask") }
shared_examples "versioned casks" do |tap_version, expectations| shared_examples "versioned casks" do |tap_version, expectations|
expectations.each do |installed_versions, expected_output| expectations.each do |installed_version, expected_output|
context "when versions #{installed_versions.inspect} are installed and the tap version is #{tap_version}" do context "when version #{installed_version.inspect} is installed and the tap version is #{tap_version}" do
it { it {
allow(cask).to receive(:versions).and_return(installed_versions) allow(cask).to receive(:installed_version).and_return(installed_version)
allow(cask).to receive(:version).and_return(Cask::DSL::Version.new(tap_version)) allow(cask).to receive(:version).and_return(Cask::DSL::Version.new(tap_version))
expect(cask).to receive(:outdated_versions).and_call_original expect(cask).to receive(:outdated_versions).and_call_original
expect(subject).to eq expected_output expect(subject).to eq expected_output
@ -118,16 +118,13 @@ describe Cask::Cask, :cask do
describe "installed version is equal to tap version => not outdated" do describe "installed version is equal to tap version => not outdated" do
include_examples "versioned casks", "1.2.3", include_examples "versioned casks", "1.2.3",
["1.2.3"] => [], "1.2.3" => []
["1.2.4", "1.2.3"] => []
end end
describe "installed version is different than tap version => outdated" do describe "installed version is different than tap version => outdated" do
include_examples "versioned casks", "1.2.4", include_examples "versioned casks", "1.2.4",
["1.2.3"] => ["1.2.3"], "1.2.3" => ["1.2.3"],
["1.2.4", "1.2.3"] => ["1.2.3"], "1.2.4" => []
["1.2.2", "1.2.3"] => ["1.2.2", "1.2.3"],
["1.2.2", "1.2.4", "1.2.3"] => ["1.2.2", "1.2.3"]
end end
end end
@ -142,7 +139,7 @@ describe Cask::Cask, :cask do
subject { cask.outdated_versions(greedy: greedy) } subject { cask.outdated_versions(greedy: greedy) }
it { it {
allow(cask).to receive(:versions).and_return(installed_version) allow(cask).to receive(:installed_version).and_return(installed_version)
allow(cask).to receive(:version).and_return(Cask::DSL::Version.new(tap_version)) allow(cask).to receive(:version).and_return(Cask::DSL::Version.new(tap_version))
allow(cask).to receive(:outdated_download_sha?).and_return(outdated_sha) allow(cask).to receive(:outdated_download_sha?).and_return(outdated_sha)
expect(cask).to receive(:outdated_versions).and_call_original expect(cask).to receive(:outdated_versions).and_call_original
@ -154,29 +151,29 @@ describe Cask::Cask, :cask do
describe ":latest version installed, :latest version in tap" do describe ":latest version installed, :latest version in tap" do
include_examples ":latest cask", false, false, "latest", include_examples ":latest cask", false, false, "latest",
["latest"] => [] "latest" => []
include_examples ":latest cask", true, false, "latest", include_examples ":latest cask", true, false, "latest",
["latest"] => [] "latest" => []
include_examples ":latest cask", true, true, "latest", include_examples ":latest cask", true, true, "latest",
["latest"] => ["latest"] "latest" => ["latest"]
end end
describe "numbered version installed, :latest version in tap" do describe "numbered version installed, :latest version in tap" do
include_examples ":latest cask", false, false, "latest", include_examples ":latest cask", false, false, "latest",
["1.2.3"] => [] "1.2.3" => []
include_examples ":latest cask", true, false, "latest", include_examples ":latest cask", true, false, "latest",
["1.2.3"] => [] "1.2.3" => []
include_examples ":latest cask", true, true, "latest", include_examples ":latest cask", true, true, "latest",
["1.2.3"] => ["1.2.3"] "1.2.3" => ["1.2.3"]
end end
describe "latest version installed, numbered version in tap" do describe "latest version installed, numbered version in tap" do
include_examples ":latest cask", false, false, "1.2.3", include_examples ":latest cask", false, false, "1.2.3",
["latest"] => ["latest"] "latest" => ["latest"]
include_examples ":latest cask", true, false, "1.2.3", include_examples ":latest cask", true, false, "1.2.3",
["latest"] => ["latest"] "latest" => ["latest"]
include_examples ":latest cask", true, true, "1.2.3", include_examples ":latest cask", true, true, "1.2.3",
["latest"] => ["latest"] "latest" => ["latest"]
end end
end end
end end

View File

@ -313,7 +313,7 @@ describe Cask::Installer, :cask do
caffeine = Cask::CaskLoader.load(path) caffeine = Cask::CaskLoader.load(path)
expect(caffeine).to receive(:loaded_from_api?).twice.and_return(true) expect(caffeine).to receive(:loaded_from_api?).twice.and_return(true)
expect(caffeine).to receive(:caskfile_only?).twice.and_return(true) expect(caffeine).to receive(:caskfile_only?).twice.and_return(true)
expect(caffeine).to receive(:installed_caskfile).once.and_return(invalid_path) expect(caffeine).to receive(:installed_caskfile).twice.and_return(invalid_path)
described_class.new(caffeine).install described_class.new(caffeine).install
expect(Cask::CaskLoader.load(path)).to be_installed expect(Cask::CaskLoader.load(path)).to be_installed

View File

@ -112,14 +112,6 @@ describe Cask::Uninstall, :cask do
expect(caskroom_path.join(first_installed_version)).not_to exist expect(caskroom_path.join(first_installed_version)).not_to exist
expect(caskroom_path).not_to exist expect(caskroom_path).not_to exist
end end
it "displays a message when versions remain installed" do
expect do
expect do
described_class.uninstall_casks(Cask::Cask.new("versioned-cask"))
end.not_to output.to_stderr
end.to output(/#{token} #{first_installed_version} is still installed./).to_stdout
end
end end
context "when Casks in Taps have been renamed or removed" do context "when Casks in Taps have been renamed or removed" do

View File

@ -3,8 +3,12 @@
require "cask/upgrade" require "cask/upgrade"
describe Cask::Upgrade, :cask do describe Cask::Upgrade, :cask do
let(:version_latest_path_second) { version_latest.config.appdir.join("Caffeine Pro.app") } let(:version_latest_paths) do
let(:version_latest_path_first) { version_latest.config.appdir.join("Caffeine Mini.app") } [
version_latest.config.appdir.join("Caffeine Mini.app"),
version_latest.config.appdir.join("Caffeine Pro.app"),
]
end
let(:version_latest) { Cask::CaskLoader.load("version-latest") } let(:version_latest) { Cask::CaskLoader.load("version-latest") }
let(:auto_updates_path) { auto_updates.config.appdir.join("MyFancyApp.app") } let(:auto_updates_path) { auto_updates.config.appdir.join("MyFancyApp.app") }
let(:auto_updates) { Cask::CaskLoader.load("auto-updates") } let(:auto_updates) { Cask::CaskLoader.load("auto-updates") }
@ -38,81 +42,81 @@ describe Cask::Upgrade, :cask do
it "updates all the installed Casks when no token is provided" do it "updates all the installed Casks when no token is provided" do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
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.installed_version).to eq "2.60"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.3") expect(local_caffeine.installed_version).to eq "1.2.3"
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.installed_version).to eq "2.61"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).not_to be_a_directory expect(renamed_app_old_path).not_to be_a_directory
expect(renamed_app_new_path).to be_a_directory expect(renamed_app_new_path).to be_a_directory
expect(renamed_app.versions).to include("2.0.0") expect(renamed_app.installed_version).to eq "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
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
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.installed_version).to eq "2.60"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.3") expect(local_caffeine.installed_version).to eq "1.2.3"
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.installed_version).to eq "2.60"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
described_class.upgrade_casks(local_caffeine, auto_updates, args: args) described_class.upgrade_casks(local_caffeine, auto_updates, args: args)
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.3") expect(local_caffeine.installed_version).to eq "1.2.3"
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.61") expect(auto_updates.installed_version).to eq "2.61"
end end
end end
@ -120,24 +124,24 @@ describe Cask::Upgrade, :cask do
it 'includes the Casks with "auto_updates true" or "version latest"' do it 'includes the Casks with "auto_updates true" or "version latest"' do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
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.installed_version).to eq "2.60"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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_paths).to all be_a_directory
expect(version_latest.versions).to include("latest") expect(version_latest.installed_version).to eq "latest"
# 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")
expect(version_latest.outdated_download_sha?).to be(true) expect(version_latest.outdated_download_sha?).to be(true)
@ -146,50 +150,49 @@ describe Cask::Upgrade, :cask do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.3") expect(local_caffeine.installed_version).to eq "1.2.3"
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.61") expect(auto_updates.installed_version).to eq "2.61"
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.installed_version).to eq "2.61"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).not_to be_a_directory expect(renamed_app_old_path).not_to be_a_directory
expect(renamed_app_new_path).to be_a_directory expect(renamed_app_new_path).to be_a_directory
expect(renamed_app.versions).to include("2.0.0") expect(renamed_app.installed_version).to eq "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_paths).to all be_a_directory
expect(version_latest.versions).to include("latest") expect(version_latest.installed_version).to eq "latest"
expect(version_latest.outdated_download_sha?).to be(false) expect(version_latest.outdated_download_sha?).to be(false)
end end
it 'does not include the Casks with "auto_updates true" or "version latest" when the version did not change' do it 'does not include the Casks with "auto_updates true" or "version latest" when the version did not change' do
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
described_class.upgrade_casks(auto_updates, greedy: true, args: args) described_class.upgrade_casks(auto_updates, greedy: true, args: args)
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.61") expect(auto_updates.installed_version).to eq "2.61"
described_class.upgrade_casks(auto_updates, greedy: true, args: args) described_class.upgrade_casks(auto_updates, greedy: true, args: args)
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
expect(auto_updates_path).to be_a_directory expect(auto_updates_path).to be_a_directory
expect(auto_updates.versions).to include("2.61") expect(auto_updates.installed_version).to eq "2.61"
end end
it 'does not include the Casks with "version latest" when the version did not change' do it 'does not include the Casks with "version latest" when the version did not change' do
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_first).to be_a_directory expect(version_latest_paths).to all be_a_directory
expect(version_latest_path_second).to be_a_directory expect(version_latest.installed_version).to eq "latest"
expect(version_latest.versions).to include("latest")
# 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")
expect(version_latest.outdated_download_sha?).to be(true) expect(version_latest.outdated_download_sha?).to be(true)
@ -197,17 +200,15 @@ describe Cask::Upgrade, :cask do
described_class.upgrade_casks(version_latest, greedy: true, args: args) described_class.upgrade_casks(version_latest, greedy: true, args: args)
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_first).to be_a_directory expect(version_latest_paths).to all be_a_directory
expect(version_latest_path_second).to be_a_directory expect(version_latest.installed_version).to eq "latest"
expect(version_latest.versions).to include("latest")
expect(version_latest.outdated_download_sha?).to be(false) expect(version_latest.outdated_download_sha?).to be(false)
described_class.upgrade_casks(version_latest, greedy: true, args: args) described_class.upgrade_casks(version_latest, greedy: true, args: args)
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_first).to be_a_directory expect(version_latest_paths).to all be_a_directory
expect(version_latest_path_second).to be_a_directory expect(version_latest.installed_version).to eq "latest"
expect(version_latest.versions).to include("latest")
expect(version_latest.outdated_download_sha?).to be(false) expect(version_latest.outdated_download_sha?).to be(false)
end end
end end
@ -236,34 +237,31 @@ describe Cask::Upgrade, :cask do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
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.installed_version).to eq "2.60"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(local_caffeine.versions).not_to include("1.2.3")
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.installed_version).to eq "2.60"
expect(local_transmission.versions).not_to include("2.61")
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
@ -271,23 +269,21 @@ describe Cask::Upgrade, :cask do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
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.installed_version).to eq "2.60"
described_class.upgrade_casks(local_caffeine, dry_run: true, args: args) described_class.upgrade_casks(local_caffeine, dry_run: true, args: args)
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(local_caffeine.versions).not_to include("1.2.3")
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.installed_version).to eq "2.60"
expect(local_transmission.versions).not_to include("2.61")
end end
it 'would update "auto_updates" and "latest" Casks when their tokens are provided in the command line' do it 'would update "auto_updates" and "latest" Casks when their tokens are provided in the command line' do
@ -295,34 +291,31 @@ describe Cask::Upgrade, :cask do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(local_caffeine.versions).not_to include("1.2.3")
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
expect(auto_updates.versions).not_to include("2.61")
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "1.0.0"
expect(renamed_app.versions).not_to include("2.0.0")
end end
end end
@ -332,20 +325,20 @@ describe Cask::Upgrade, :cask do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
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.installed_version).to eq "2.60"
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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
@ -356,24 +349,20 @@ describe Cask::Upgrade, :cask do
expect(local_caffeine).to be_installed expect(local_caffeine).to be_installed
expect(local_caffeine_path).to be_a_directory expect(local_caffeine_path).to be_a_directory
expect(local_caffeine.versions).to include("1.2.2") expect(local_caffeine.installed_version).to eq "1.2.2"
expect(local_caffeine.versions).not_to include("1.2.3")
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
expect(auto_updates.versions).not_to include("2.61")
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.installed_version).to eq "2.60"
expect(local_transmission.versions).not_to include("2.61")
expect(renamed_app).to be_installed expect(renamed_app).to be_installed
expect(renamed_app_old_path).to be_a_directory expect(renamed_app_old_path).to be_a_directory
expect(renamed_app_new_path).not_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.installed_version).to eq "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)
@ -384,23 +373,21 @@ describe Cask::Upgrade, :cask do
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
described_class.upgrade_casks(auto_updates, dry_run: true, greedy: true, args: args) described_class.upgrade_casks(auto_updates, dry_run: true, greedy: true, args: args)
expect(auto_updates).to be_installed expect(auto_updates).to be_installed
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.installed_version).to eq "2.57"
expect(auto_updates.versions).not_to include("2.61")
end end
it 'would update outdated Casks with "version latest"' do it 'would update outdated Casks with "version latest"' do
expect(described_class).not_to receive(:upgrade_cask) expect(described_class).not_to receive(:upgrade_cask)
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_first).to be_a_directory expect(version_latest_paths).to all be_a_directory
expect(version_latest_path_second).to be_a_directory expect(version_latest.installed_version).to eq "latest"
expect(version_latest.versions).to include("latest")
# 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")
expect(version_latest.outdated_download_sha?).to be(true) expect(version_latest.outdated_download_sha?).to be(true)
@ -408,9 +395,8 @@ describe Cask::Upgrade, :cask do
described_class.upgrade_casks(version_latest, dry_run: true, greedy: true, args: args) described_class.upgrade_casks(version_latest, dry_run: true, greedy: true, args: args)
expect(version_latest).to be_installed expect(version_latest).to be_installed
expect(version_latest_path_first).to be_a_directory expect(version_latest_paths).to all be_a_directory
expect(version_latest_path_second).to be_a_directory expect(version_latest.installed_version).to eq "latest"
expect(version_latest.versions).to include("latest")
expect(version_latest.outdated_download_sha?).to be(true) expect(version_latest.outdated_download_sha?).to be(true)
end end
end end
@ -440,7 +426,7 @@ describe Cask::Upgrade, :cask do
expect(will_fail_if_upgraded).to be_installed expect(will_fail_if_upgraded).to be_installed
expect(will_fail_if_upgraded_path).to be_a_file expect(will_fail_if_upgraded_path).to be_a_file
expect(will_fail_if_upgraded.versions).to include("1.2.2") expect(will_fail_if_upgraded.installed_version).to eq "1.2.2"
expect do expect do
described_class.upgrade_casks(will_fail_if_upgraded, args: args) described_class.upgrade_casks(will_fail_if_upgraded, args: args)
@ -448,7 +434,7 @@ describe Cask::Upgrade, :cask do
expect(will_fail_if_upgraded).to be_installed expect(will_fail_if_upgraded).to be_installed
expect(will_fail_if_upgraded_path).to be_a_file expect(will_fail_if_upgraded_path).to be_a_file
expect(will_fail_if_upgraded.versions).to include("1.2.2") expect(will_fail_if_upgraded.installed_version).to eq "1.2.2"
expect(will_fail_if_upgraded.staged_path).not_to exist expect(will_fail_if_upgraded.staged_path).not_to exist
end end
@ -458,7 +444,7 @@ describe Cask::Upgrade, :cask do
expect(bad_checksum).to be_installed expect(bad_checksum).to be_installed
expect(bad_checksum_path).to be_a_directory expect(bad_checksum_path).to be_a_directory
expect(bad_checksum.versions).to include("1.2.2") expect(bad_checksum.installed_version).to eq "1.2.2"
expect do expect do
described_class.upgrade_casks(bad_checksum, args: args) described_class.upgrade_casks(bad_checksum, args: args)
@ -466,7 +452,7 @@ describe Cask::Upgrade, :cask do
expect(bad_checksum).to be_installed expect(bad_checksum).to be_installed
expect(bad_checksum_path).to be_a_directory expect(bad_checksum_path).to be_a_directory
expect(bad_checksum.versions).to include("1.2.2") expect(bad_checksum.installed_version).to eq "1.2.2"
expect(bad_checksum.staged_path).not_to exist expect(bad_checksum.staged_path).not_to exist
end end
end end
@ -495,15 +481,15 @@ describe Cask::Upgrade, :cask do
expect(bad_checksum).to be_installed expect(bad_checksum).to be_installed
expect(bad_checksum_path).to be_a_directory expect(bad_checksum_path).to be_a_directory
expect(bad_checksum.versions).to include("1.2.2") expect(bad_checksum.installed_version).to eq "1.2.2"
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.installed_version).to eq "2.60"
expect(bad_checksum_2).to be_installed expect(bad_checksum_2).to be_installed
expect(bad_checksum_2_path).to be_a_file expect(bad_checksum_2_path).to be_a_file
expect(bad_checksum_2.versions).to include("1.2.2") expect(bad_checksum_2.installed_version).to eq "1.2.2"
expect do expect do
described_class.upgrade_casks(args: args) described_class.upgrade_casks(args: args)
@ -511,16 +497,16 @@ describe Cask::Upgrade, :cask do
expect(bad_checksum).to be_installed expect(bad_checksum).to be_installed
expect(bad_checksum_path).to be_a_directory expect(bad_checksum_path).to be_a_directory
expect(bad_checksum.versions).to include("1.2.2") expect(bad_checksum.installed_version).to eq "1.2.2"
expect(bad_checksum.staged_path).not_to exist expect(bad_checksum.staged_path).not_to exist
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.installed_version).to eq "2.61"
expect(bad_checksum_2).to be_installed expect(bad_checksum_2).to be_installed
expect(bad_checksum_2_path).to be_a_file expect(bad_checksum_2_path).to be_a_file
expect(bad_checksum_2.versions).to include("1.2.2") expect(bad_checksum_2.installed_version).to eq "1.2.2"
expect(bad_checksum_2.staged_path).not_to exist expect(bad_checksum_2.staged_path).not_to exist
end end
end end

View File

@ -4,17 +4,17 @@ require "cli/named_args"
def setup_unredable_formula(name) def setup_unredable_formula(name)
error = FormulaUnreadableError.new(name, RuntimeError.new("testing")) error = FormulaUnreadableError.new(name, RuntimeError.new("testing"))
allow(Formulary).to receive(:factory).with(name, force_bottle: false, flags: []).and_raise(error) allow(Formulary).to receive(:factory).with(name, force_bottle: false, flags: [], warn: true).and_raise(error)
end end
def setup_unredable_cask(name) def setup_unredable_cask(name)
error = Cask::CaskUnreadableError.new(name, "testing") error = Cask::CaskUnreadableError.new(name, "testing")
allow(Cask::CaskLoader).to receive(:load).with(name).and_raise(error) allow(Cask::CaskLoader).to receive(:load).with(name).and_raise(error)
allow(Cask::CaskLoader).to receive(:load).with(name, config: nil).and_raise(error) allow(Cask::CaskLoader).to receive(:load).with(name, config: nil, warn: true).and_raise(error)
config = instance_double(Cask::Config) config = instance_double(Cask::Config)
allow(Cask::Config).to receive(:from_args).and_return(config) allow(Cask::Config).to receive(:from_args).and_return(config)
allow(Cask::CaskLoader).to receive(:load).with(name, config: config).and_raise(error) allow(Cask::CaskLoader).to receive(:load).with(name, config: config, warn: true).and_raise(error)
end end
describe Homebrew::CLI::NamedArgs do describe Homebrew::CLI::NamedArgs do

View File

@ -11,7 +11,7 @@ describe "brew migrate" do
install_and_rename_coretap_formula "testball1", "testball2" install_and_rename_coretap_formula "testball1", "testball2"
expect { brew "migrate", "testball1" } expect { brew "migrate", "testball1" }
.to output(/Processing testball1 formula rename to testball2/).to_stdout .to output(/Migrating formula testball1 to testball2/).to_stdout
.and not_to_output.to_stderr .and not_to_output.to_stderr
.and be_a_success .and be_a_success
end end

View File

@ -1,6 +1,9 @@
{ {
"token": "everything", "token": "everything",
"full_token": "everything", "full_token": "everything",
"old_tokens": [
],
"tap": "homebrew/cask", "tap": "homebrew/cask",
"name": [ "name": [
"Everything" "Everything"

View File

@ -9,7 +9,7 @@ module Test
allow(::Cask::CaskLoader).to receive(:for).and_call_original if call_original allow(::Cask::CaskLoader).to receive(:for).and_call_original if call_original
loader = ::Cask::CaskLoader::FromInstanceLoader.new cask loader = ::Cask::CaskLoader::FromInstanceLoader.new cask
allow(::Cask::CaskLoader).to receive(:for).with(ref).and_return(loader) allow(::Cask::CaskLoader).to receive(:for).with(ref, warn: true).and_return(loader)
end end
end end
end end

View File

@ -15,8 +15,8 @@ module Test
allow(Formulary).to receive(:loader_for).and_call_original if call_original allow(Formulary).to receive(:loader_for).and_call_original if call_original
loader = double(get_formula: formula) loader = double(get_formula: formula)
allow(Formulary).to receive(:loader_for).with(ref, from: :keg).and_return(loader) allow(Formulary).to receive(:loader_for).with(ref, from: :keg, warn: false).and_return(loader)
allow(Formulary).to receive(:loader_for).with(ref, from: nil).and_return(loader) allow(Formulary).to receive(:loader_for).with(ref, from: nil, warn: true).and_return(loader)
end end
end end
end end