diff --git a/Library/Homebrew/cmd/outdated.rb b/Library/Homebrew/cmd/outdated.rb index ae065b1bcf0ea..7c5f078716cf0 100644 --- a/Library/Homebrew/cmd/outdated.rb +++ b/Library/Homebrew/cmd/outdated.rb @@ -3,6 +3,8 @@ require "formula" require "keg" require "cli/parser" +require "cask/cmd" +require "cask/caskroom" module Homebrew module_function @@ -20,94 +22,183 @@ def outdated_args switch :verbose, description: "Include detailed version information." flag "--json", - description: "Print output in JSON format. Currently the default and only accepted "\ - "value for is `v1`. See the docs for examples of using the JSON "\ - "output: " + description: "Print output in JSON format. There are two versions: v1 and v2. " \ + "v1 is deprecated and is currently the default if no version is specified. " \ + "v2 prints outdated formulae and casks. " switch "--fetch-HEAD", description: "Fetch the upstream repository to detect if the HEAD installation of the "\ "formula is outdated. Otherwise, the repository's HEAD will only be checked for "\ "updates when a new stable or development version has been released." + switch "--greedy", + description: "Print outdated casks with `auto_updates` or `version :latest`." + switch "--formula", + description: "Treat all arguments as formulae." + switch "--cask", + description: "Treat all arguments as casks." switch :debug conflicts "--quiet", "--verbose", "--json" + conflicts "--formula", "--cask" end end def outdated outdated_args.parse - formulae = if args.resolved_formulae.blank? - Formula.installed - else - args.resolved_formulae - end - if args.json - raise UsageError, "invalid JSON version: #{args.json}" unless ["v1", true].include? args.json + case json_version + when :v1, :default + # TODO: enable for next major/minor release + # odeprecated "brew outdated --json#{json_version == :v1 ? "=v1" : ""}", "brew outdated --json=v2" + + outdated = if args.formula? || !args.cask? + outdated_formulae + else + outdated_casks + end + + puts JSON.generate(json_info(outdated)) + + when :v2 + formulae, casks = if args.formula? + [outdated_formulae, []] + elsif args.cask? + [[], outdated_casks] + else + outdated_formulae_casks + end + + json = { + "formulae" => json_info(formulae), + "casks" => json_info(casks), + } + puts JSON.generate(json) + + outdated = formulae + casks - outdated = print_outdated_json(formulae) else - outdated = print_outdated(formulae) + outdated = if args.formula? + outdated_formulae + elsif args.cask? + outdated_casks + else + outdated_formulae_casks.flatten + end + + print_outdated(outdated) end - Homebrew.failed = args.resolved_formulae.present? && !outdated.empty? + + Homebrew.failed = args.named.present? && outdated.present? end - def print_outdated(formulae) - verbose = ($stdout.tty? || args.verbose?) && !args.quiet? - fetch_head = args.fetch_HEAD? + def print_outdated(formulae_or_casks) + formulae_or_casks.each do |formula_or_cask| + if formula_or_cask.is_a?(Formula) + f = formula_or_cask + + if verbose? + outdated_kegs = f.outdated_kegs(fetch_head: args.fetch_HEAD?) + + current_version = if f.alias_changed? + latest = f.latest_formula + "#{latest.name} (#{latest.pkg_version})" + elsif f.head? && outdated_kegs.any? { |k| k.version.to_s == f.pkg_version.to_s } + # There is a newer HEAD but the version number has not changed. + "latest HEAD" + else + f.pkg_version.to_s + end + + outdated_versions = outdated_kegs.group_by { |keg| Formulary.from_keg(keg).full_name } + .sort_by { |full_name, _kegs| full_name } + .map do |full_name, kegs| + "#{full_name} (#{kegs.map(&:version).join(", ")})" + end.join(", ") + + pinned_version = " [pinned at #{f.pinned_version}]" if f.pinned? + + puts "#{outdated_versions} < #{current_version}#{pinned_version}" + else + puts f.full_installed_specified_name + end + else + c = formula_or_cask - outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) } - .sort + puts c.outdated_info(args.greedy?, verbose?, false) + end + end + end - outdated_formulae.each do |f| - if verbose - outdated_kegs = f.outdated_kegs(fetch_head: fetch_head) + def json_info(formulae_or_casks) + formulae_or_casks.map do |formula_or_cask| + if formula_or_cask.is_a?(Formula) + f = formula_or_cask - current_version = if f.alias_changed? - latest = f.latest_formula - "#{latest.name} (#{latest.pkg_version})" - elsif f.head? && outdated_kegs.any? { |k| k.version.to_s == f.pkg_version.to_s } - # There is a newer HEAD but the version number has not changed. - "latest HEAD" + outdated_versions = f.outdated_kegs(fetch_head: args.fetch_HEAD?).map(&:version) + current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s } + "HEAD" else f.pkg_version.to_s end - outdated_versions = outdated_kegs - .group_by { |keg| Formulary.from_keg(keg).full_name } - .sort_by { |full_name, _kegs| full_name } - .map do |full_name, kegs| - "#{full_name} (#{kegs.map(&:version).join(", ")})" - end.join(", ") - - pinned_version = " [pinned at #{f.pinned_version}]" if f.pinned? - - puts "#{outdated_versions} < #{current_version}#{pinned_version}" + { name: f.full_name, + installed_versions: outdated_versions.map(&:to_s), + current_version: current_version, + pinned: f.pinned?, + pinned_version: f.pinned_version } else - puts f.full_installed_specified_name + c = formula_or_cask + + c.outdated_info(args.greedy?, verbose?, true) end end end - def print_outdated_json(formulae) - json = [] - fetch_head = args.fetch_HEAD? - outdated_formulae = formulae.select { |f| f.outdated?(fetch_head: fetch_head) } + def verbose? + ($stdout.tty? || args.verbose?) && !args.quiet? + end - outdated = outdated_formulae.each do |f| - outdated_versions = f.outdated_kegs(fetch_head: fetch_head).map(&:version) - current_version = if f.head? && outdated_versions.any? { |v| v.to_s == f.pkg_version.to_s } - "HEAD" - else - f.pkg_version.to_s - end + def json_version + version_hash = { + nil => nil, + true => :default, + "v1" => :v1, + "v2" => :v2, + } + + raise UsageError, "invalid JSON version: #{args.json}" unless version_hash.include? args.json + + version_hash[args.json] + end + + def outdated_formulae + select_outdated((args.resolved_formulae.presence || Formula.installed)).sort + end - json << { name: f.full_name, - installed_versions: outdated_versions.map(&:to_s), - current_version: current_version, - pinned: f.pinned?, - pinned_version: f.pinned_version } + def outdated_casks + if args.named.present? + select_outdated(args.named.uniq.map(&Cask::CaskLoader.method(:load))) + else + select_outdated(Cask::Caskroom.casks) + end + end + + def outdated_formulae_casks + formulae, casks = args.resolved_formulae_casks + + if formulae.blank? && casks.blank? + formulae = Formula.installed + casks = Cask::Caskroom.casks end - puts JSON.generate(json) - outdated + [select_outdated(formulae), select_outdated(casks)] + end + + def select_outdated(formulae_or_casks) + formulae_or_casks.select do |formula_or_cask| + if formula_or_cask.is_a?(Formula) + formula_or_cask.outdated?(fetch_head: args.fetch_HEAD?) + else + formula_or_cask.outdated?(args.greedy?) + end + end end end diff --git a/Library/Homebrew/cmd/upgrade.rb b/Library/Homebrew/cmd/upgrade.rb index 66a804916513e..5a2ae625bfb7b 100644 --- a/Library/Homebrew/cmd/upgrade.rb +++ b/Library/Homebrew/cmd/upgrade.rb @@ -4,6 +4,9 @@ require "formula_installer" require "install" require "upgrade" +require "cask/cmd" +require "cask/utils" +require "cask/macos" module Homebrew module_function @@ -50,6 +53,8 @@ def upgrade_args description: "Print install times for each formula at the end of the run." switch "-n", "--dry-run", description: "Show what would be upgraded, but do not actually upgrade anything." + switch "--greedy", + description: "Upgrade casks with `auto_updates` or `version :latest`" conflicts "--build-from-source", "--force-bottle" formula_options end @@ -58,22 +63,27 @@ def upgrade_args def upgrade upgrade_args.parse + formulae, casks = args.resolved_formulae_casks + + upgrade_outdated_formulae(formulae) + upgrade_outdated_casks(casks) + end + + def upgrade_outdated_formulae(formulae) FormulaInstaller.prevent_build_flags unless DevelopmentTools.installed? Install.perform_preinstall_checks - if args.no_named? + if formulae.blank? outdated = Formula.installed.select do |f| f.outdated?(fetch_head: args.fetch_HEAD?) end - - exit 0 if outdated.empty? else - outdated = args.resolved_formulae.select do |f| + outdated, not_outdated = formulae.partition do |f| f.outdated?(fetch_head: args.fetch_HEAD?) end - (args.resolved_formulae - outdated).each do |f| + not_outdated.each do |f| versions = f.installed_kegs.map(&:version) if versions.empty? ofail "#{f.full_specified_name} not installed" @@ -82,9 +92,10 @@ def upgrade opoo "#{f.full_specified_name} #{version} already installed" end end - return if outdated.empty? end + return if outdated.blank? + pinned = outdated.select(&:pinned?) outdated -= pinned formulae_to_install = outdated.map(&:latest_formula) @@ -115,4 +126,12 @@ def upgrade Homebrew.messages.display_messages end + + def upgrade_outdated_casks(casks) + cask_upgrade = Cask::Cmd::Upgrade.new(casks) + cask_upgrade.force = args.force? + cask_upgrade.dry_run = args.dry_run? + cask_upgrade.greedy = args.greedy? + cask_upgrade.run + end end diff --git a/Library/Homebrew/test/cmd/outdated_spec.rb b/Library/Homebrew/test/cmd/outdated_spec.rb index 54a65932851c5..bb594a1aae1a4 100644 --- a/Library/Homebrew/test/cmd/outdated_spec.rb +++ b/Library/Homebrew/test/cmd/outdated_spec.rb @@ -23,7 +23,6 @@ expect { brew "outdated", "--json=v1" } .to output(expected_json + "\n").to_stdout - .and not_to_output.to_stderr .and be_a_success end end diff --git a/docs/Manpage.md b/docs/Manpage.md index fffec405be15b..32e270a75ec50 100644 --- a/docs/Manpage.md +++ b/docs/Manpage.md @@ -356,9 +356,15 @@ otherwise. * `-v`, `--verbose`: Include detailed version information. * `--json`: - Print output in JSON format. Currently the default and only accepted value for *`version`* is `v1`. See the docs for examples of using the JSON output: + Print output in JSON format. There are two versions: v1 and v2. v1 is deprecated and is currently the default if no version is specified. v2 prints outdated formulae and casks. * `--fetch-HEAD`: Fetch the upstream repository to detect if the HEAD installation of the formula is outdated. Otherwise, the repository's HEAD will only be checked for updates when a new stable or development version has been released. +* `--greedy`: + Print outdated casks with `auto_updates` or `version :latest`. +* `--formula`: + Treat all arguments as formulae. +* `--cask`: + Treat all arguments as casks. ### `pin` *`formula`* @@ -556,6 +562,8 @@ the upgraded formulae or, every 30 days, for all formulae. Print install times for each formula at the end of the run. * `-n`, `--dry-run`: Show what would be upgraded, but do not actually upgrade anything. +* `--greedy`: + Upgrade casks with `auto_updates` or `version :latest` ### `uses` [*`options`*] *`formula`* diff --git a/manpages/brew.1 b/manpages/brew.1 index b2805d9c8468e..7d57c2c11b438 100644 --- a/manpages/brew.1 +++ b/manpages/brew.1 @@ -477,12 +477,24 @@ Include detailed version information\. . .TP \fB\-\-json\fR -Print output in JSON format\. Currently the default and only accepted value for \fIversion\fR is \fBv1\fR\. See the docs for examples of using the JSON output: \fIhttps://docs\.brew\.sh/Querying\-Brew\fR +Print output in JSON format\. There are two versions: v1 and v2\. v1 is deprecated and is currently the default if no version is specified\. v2 prints outdated formulae and casks\. . .TP \fB\-\-fetch\-HEAD\fR Fetch the upstream repository to detect if the HEAD installation of the formula is outdated\. Otherwise, the repository\'s HEAD will only be checked for updates when a new stable or development version has been released\. . +.TP +\fB\-\-greedy\fR +Print outdated casks with \fBauto_updates\fR or \fBversion :latest\fR\. +. +.TP +\fB\-\-formula\fR +Treat all arguments as formulae\. +. +.TP +\fB\-\-cask\fR +Treat all arguments as casks\. +. .SS "\fBpin\fR \fIformula\fR" Pin the specified \fIformula\fR, preventing them from being upgraded when issuing the \fBbrew upgrade\fR \fIformula\fR command\. See also \fBunpin\fR\. . @@ -722,6 +734,10 @@ Print install times for each formula at the end of the run\. \fB\-n\fR, \fB\-\-dry\-run\fR Show what would be upgraded, but do not actually upgrade anything\. . +.TP +\fB\-\-greedy\fR +Upgrade casks with \fBauto_updates\fR or \fBversion :latest\fR +. .SS "\fBuses\fR [\fIoptions\fR] \fIformula\fR" Show formulae that specify \fIformula\fR as a dependency\. When given multiple formula arguments, show the intersection of formulae that use \fIformula\fR\. By default, \fBuses\fR shows all formulae that specify \fIformula\fR as a required or recommended dependency for their stable builds\. .