| 
									
										
										
										
											2023-03-06 09:49:53 -08:00
										 |  |  | # typed: true | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  | require "abstract_command" | 
					
						
							| 
									
										
										
										
											2015-08-03 13:09:07 +01:00
										 |  |  | require "formula" | 
					
						
							|  |  |  | require "keg" | 
					
						
							| 
									
										
										
										
											2020-07-06 17:24:20 -04:00
										 |  |  | require "cask/caskroom" | 
					
						
							| 
									
										
										
										
											2021-08-06 02:30:44 -04:00
										 |  |  | require "api" | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 22:41:47 -05:00
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |   module Cmd | 
					
						
							|  |  |  |     class Outdated < AbstractCommand | 
					
						
							|  |  |  |       cmd_args do | 
					
						
							|  |  |  |         description <<~EOS | 
					
						
							|  |  |  |           List installed casks and formulae that have an updated version available. By default, version | 
					
						
							|  |  |  |           information is displayed in interactive shells, and suppressed otherwise. | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         switch "-q", "--quiet", | 
					
						
							|  |  |  |                description: "List only the names of outdated kegs (takes precedence over `--verbose`)." | 
					
						
							|  |  |  |         switch "-v", "--verbose", | 
					
						
							|  |  |  |                description: "Include detailed version information." | 
					
						
							|  |  |  |         switch "--formula", "--formulae", | 
					
						
							|  |  |  |                description: "List only outdated formulae." | 
					
						
							|  |  |  |         switch "--cask", "--casks", | 
					
						
							|  |  |  |                description: "List only outdated casks." | 
					
						
							|  |  |  |         flag   "--json", | 
					
						
							|  |  |  |                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 "-g", "--greedy", | 
					
						
							|  |  |  |                description: "Also include outdated casks with `auto_updates true` or `version :latest`." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch "--greedy-latest", | 
					
						
							|  |  |  |                description: "Also include outdated casks including those with `version :latest`." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch "--greedy-auto-updates", | 
					
						
							|  |  |  |                description: "Also include outdated casks including those with `auto_updates true`." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts "--quiet", "--verbose", "--json" | 
					
						
							|  |  |  |         conflicts "--formula", "--cask" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         named_args [:formula, :cask] | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-06 18:59:44 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       sig { override.void } | 
					
						
							|  |  |  |       def run | 
					
						
							|  |  |  |         case json_version(args.json) | 
					
						
							|  |  |  |         when :v1 | 
					
						
							|  |  |  |           odie "`brew outdated --json=v1` is no longer supported. Use brew outdated --json=v2 instead." | 
					
						
							|  |  |  |         when :v2, :default | 
					
						
							|  |  |  |           formulae, casks = if args.formula? | 
					
						
							|  |  |  |             [outdated_formulae, []] | 
					
						
							|  |  |  |           elsif args.cask? | 
					
						
							|  |  |  |             [[], outdated_casks] | 
					
						
							| 
									
										
										
										
											2021-07-06 09:33:16 -04:00
										 |  |  |           else | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |             outdated_formulae_casks | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |           json = { | 
					
						
							|  |  |  |             "formulae" => json_info(formulae), | 
					
						
							|  |  |  |             "casks"    => json_info(casks), | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           puts JSON.pretty_generate(json) | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |           outdated = formulae + casks | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-22 12:47:47 +03:00
										 |  |  |         else | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |           outdated = if args.formula? | 
					
						
							|  |  |  |             outdated_formulae | 
					
						
							|  |  |  |           elsif args.cask? | 
					
						
							|  |  |  |             outdated_casks | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             outdated_formulae_casks.flatten | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           print_outdated(outdated) | 
					
						
							| 
									
										
										
										
											2016-07-22 12:47:47 +03:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |         Homebrew.failed = args.named.present? && outdated.present? | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-07-06 11:41:03 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       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? && !f.latest_formula.latest_version_installed? | 
					
						
							|  |  |  |                 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 | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |             puts c.outdated_info(args.greedy?, verbose?, false, args.greedy_latest?, args.greedy_auto_updates?) | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2016-07-22 12:47:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             { name:               f.full_name, | 
					
						
							|  |  |  |               installed_versions: outdated_versions.map(&:to_s), | 
					
						
							|  |  |  |               current_version:, | 
					
						
							|  |  |  |               pinned:             f.pinned?, | 
					
						
							|  |  |  |               pinned_version:     f.pinned_version } | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             c = formula_or_cask | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |             c.outdated_info(args.greedy?, verbose?, true, args.greedy_latest?, args.greedy_auto_updates?) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2014-07-06 11:41:03 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       def verbose? | 
					
						
							|  |  |  |         ($stdout.tty? || Context.current.verbose?) && !Context.current.quiet? | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-06 17:24:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       def json_version(version) | 
					
						
							|  |  |  |         version_hash = { | 
					
						
							|  |  |  |           nil  => nil, | 
					
						
							|  |  |  |           true => :default, | 
					
						
							|  |  |  |           "v1" => :v1, | 
					
						
							|  |  |  |           "v2" => :v2, | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-07-06 17:24:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |         raise UsageError, "invalid JSON version: #{version}" unless version_hash.include?(version) | 
					
						
							| 
									
										
										
										
											2020-07-06 17:24:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |         version_hash[version] | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-06 17:24:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       def outdated_formulae | 
					
						
							|  |  |  |         select_outdated((args.named.to_resolved_formulae.presence || Formula.installed)).sort | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       def outdated_casks | 
					
						
							|  |  |  |         if args.named.present? | 
					
						
							|  |  |  |           select_outdated(args.named.to_casks) | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           select_outdated(Cask::Caskroom.casks) | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       def outdated_formulae_casks | 
					
						
							|  |  |  |         formulae, casks = args.named.to_resolved_formulae_to_casks | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |         if formulae.blank? && casks.blank? | 
					
						
							|  |  |  |           formulae = Formula.installed | 
					
						
							|  |  |  |           casks = Cask::Caskroom.casks | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |         [select_outdated(formulae).sort, select_outdated(casks)] | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 09:15:53 -07:00
										 |  |  |       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?(greedy: args.greedy?, greedy_latest: args.greedy_latest?, | 
					
						
							|  |  |  |                                       greedy_auto_updates: args.greedy_auto_updates?) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-07-22 22:06:48 -04:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-17 08:53:19 -04:00
										 |  |  |     end | 
					
						
							| 
									
										
										
										
											2020-07-06 17:24:20 -04:00
										 |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-09-11 13:06:05 -07:00
										 |  |  | end |