| 
									
										
										
										
											2024-08-10 23:39:19 +01:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  | require "abstract_command" | 
					
						
							| 
									
										
										
										
											2019-09-04 00:07:27 -04:00
										 |  |  | require "formula" | 
					
						
							| 
									
										
										
										
											2020-07-30 12:59:01 -04:00
										 |  |  | require "cask/caskroom" | 
					
						
							| 
									
										
										
										
											2020-07-31 11:35:45 -04:00
										 |  |  | require "dependencies_helpers" | 
					
						
							| 
									
										
										
										
											2019-09-04 00:07:27 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 22:41:47 -05:00
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |   module Cmd | 
					
						
							|  |  |  |     # `brew uses foo bar` returns formulae that use both foo and bar | 
					
						
							|  |  |  |     # If you want the union, run the command twice and concatenate the results. | 
					
						
							|  |  |  |     # The intersection is harder to achieve with shell tools. | 
					
						
							|  |  |  |     class Uses < AbstractCommand | 
					
						
							|  |  |  |       include DependenciesHelpers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-22 18:06:49 -08:00
										 |  |  |       class UnavailableFormula < T::Struct | 
					
						
							|  |  |  |         const :name, String | 
					
						
							|  |  |  |         const :full_name, String | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |       cmd_args do | 
					
						
							|  |  |  |         description <<~EOS | 
					
						
							|  |  |  |           Show formulae and casks that specify <formula> as a dependency; that is, show dependents | 
					
						
							|  |  |  |           of <formula>. When given multiple formula arguments, show the intersection | 
					
						
							|  |  |  |           of formulae that use <formula>. By default, `uses` shows all formulae and casks that | 
					
						
							|  |  |  |           specify <formula> as a required or recommended dependency for their stable builds. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           *Note:* `--missing` and `--skip-recommended` have precedence over `--include-*`. | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         switch "--recursive", | 
					
						
							|  |  |  |                description: "Resolve more than one level of dependencies." | 
					
						
							|  |  |  |         switch "--installed", | 
					
						
							|  |  |  |                description: "Only list formulae and casks that are currently installed." | 
					
						
							|  |  |  |         switch "--missing", | 
					
						
							|  |  |  |                description: "Only list formulae and casks that are not currently installed." | 
					
						
							|  |  |  |         switch "--eval-all", | 
					
						
							|  |  |  |                description: "Evaluate all available formulae and casks, whether installed or not, to show " \ | 
					
						
							| 
									
										
										
										
											2025-07-03 12:42:57 -04:00
										 |  |  |                             "their dependents.", | 
					
						
							|  |  |  |                env:         :eval_all | 
					
						
							| 
									
										
										
										
											2024-12-24 12:50:31 -05:00
										 |  |  |         switch "--include-implicit", | 
					
						
							| 
									
										
										
										
											2025-02-03 17:40:17 +01:00
										 |  |  |                description: "Include formulae that have <formula> as an implicit dependency for " \ | 
					
						
							|  |  |  |                             "downloading and unpacking source files." | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         switch "--include-build", | 
					
						
							|  |  |  |                description: "Include formulae that specify <formula> as a `:build` dependency." | 
					
						
							|  |  |  |         switch "--include-test", | 
					
						
							|  |  |  |                description: "Include formulae that specify <formula> as a `:test` dependency." | 
					
						
							|  |  |  |         switch "--include-optional", | 
					
						
							|  |  |  |                description: "Include formulae that specify <formula> as an `:optional` dependency." | 
					
						
							|  |  |  |         switch "--skip-recommended", | 
					
						
							|  |  |  |                description: "Skip all formulae that specify <formula> as a `:recommended` dependency." | 
					
						
							|  |  |  |         switch "--formula", "--formulae", | 
					
						
							|  |  |  |                description: "Include only formulae." | 
					
						
							|  |  |  |         switch "--cask", "--casks", | 
					
						
							|  |  |  |                description: "Include only casks." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         conflicts "--formula", "--cask" | 
					
						
							| 
									
										
										
										
											2025-09-05 08:53:26 +01:00
										 |  |  |         conflicts "--installed", "--eval-all" | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         conflicts "--missing", "--installed" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         named_args :formula, min: 1
 | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2018-11-11 19:03:08 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |       sig { override.void } | 
					
						
							|  |  |  |       def run | 
					
						
							|  |  |  |         Formulary.enable_factory_cache! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         used_formulae_missing = false | 
					
						
							|  |  |  |         used_formulae = begin | 
					
						
							|  |  |  |           args.named.to_formulae | 
					
						
							|  |  |  |         rescue FormulaUnavailableError => e | 
					
						
							|  |  |  |           opoo e | 
					
						
							|  |  |  |           used_formulae_missing = true | 
					
						
							|  |  |  |           # If the formula doesn't exist: fake the needed formula object name. | 
					
						
							| 
									
										
										
										
											2024-11-22 18:06:49 -08:00
										 |  |  |           args.named.map { |name| UnavailableFormula.new name:, full_name: name } | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2017-04-17 15:06:24 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         use_runtime_dependents = args.installed? && | 
					
						
							|  |  |  |                                  !used_formulae_missing && | 
					
						
							| 
									
										
										
										
											2024-12-24 12:50:31 -05:00
										 |  |  |                                  !args.include_implicit? && | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |                                  !args.include_build? && | 
					
						
							|  |  |  |                                  !args.include_test? && | 
					
						
							|  |  |  |                                  !args.include_optional? && | 
					
						
							|  |  |  |                                  !args.skip_recommended? | 
					
						
							| 
									
										
										
										
											2018-03-24 16:55:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         uses = intersection_of_dependents(use_runtime_dependents, used_formulae) | 
					
						
							| 
									
										
										
										
											2020-07-31 10:46:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         return if uses.empty? | 
					
						
							| 
									
										
										
										
											2020-07-31 10:46:02 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         puts Formatter.columns(uses.map(&:full_name).sort) | 
					
						
							|  |  |  |         odie "Missing formulae should not have dependents!" if used_formulae_missing | 
					
						
							| 
									
										
										
										
											2020-12-05 18:19:56 -05:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |       private | 
					
						
							| 
									
										
										
										
											2022-09-05 13:57:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-23 10:25:45 -08:00
										 |  |  |       sig { | 
					
						
							|  |  |  |         params(use_runtime_dependents: T::Boolean, used_formulae: T::Array[T.any(Formula, UnavailableFormula)]) | 
					
						
							| 
									
										
										
										
											2025-02-15 23:04:04 -08:00
										 |  |  |           .returns(T::Array[T.any(Formula, CaskDependent)]) | 
					
						
							| 
									
										
										
										
											2024-11-23 10:25:45 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |       def intersection_of_dependents(use_runtime_dependents, used_formulae) | 
					
						
							|  |  |  |         recursive = args.recursive? | 
					
						
							|  |  |  |         show_formulae_and_casks = !args.formula? && !args.cask? | 
					
						
							|  |  |  |         includes, ignores = args_includes_ignores(args) | 
					
						
							| 
									
										
										
										
											2023-07-06 16:47:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |         deps = [] | 
					
						
							|  |  |  |         if use_runtime_dependents | 
					
						
							| 
									
										
										
										
											2024-11-23 10:25:45 -08:00
										 |  |  |           # We can only get here if `used_formulae_missing` is false, thus there are no UnavailableFormula. | 
					
						
							|  |  |  |           used_formulae = T.cast(used_formulae, T::Array[Formula]) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           if show_formulae_and_casks || args.formula? | 
					
						
							| 
									
										
										
										
											2025-02-16 22:20:37 -08:00
										 |  |  |             deps += T.must(used_formulae.map(&:runtime_installed_formula_dependents) | 
					
						
							|  |  |  |                      .reduce(&:&)) | 
					
						
							|  |  |  |                      .select(&:any_version_installed?) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           end | 
					
						
							|  |  |  |           if show_formulae_and_casks || args.cask? | 
					
						
							|  |  |  |             deps += select_used_dependents( | 
					
						
							|  |  |  |               dependents(Cask::Caskroom.casks), | 
					
						
							|  |  |  |               used_formulae, recursive, includes, ignores | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           deps | 
					
						
							|  |  |  |         else | 
					
						
							| 
									
										
										
										
											2025-07-03 12:42:57 -04:00
										 |  |  |           eval_all = args.eval_all? | 
					
						
							| 
									
										
										
										
											2020-07-30 12:59:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-03 12:42:57 -04:00
										 |  |  |           if !args.installed? && !eval_all | 
					
						
							| 
									
										
										
										
											2025-08-02 23:27:59 -04:00
										 |  |  |             raise UsageError, "`brew uses` needs `--installed` or `--eval-all` passed or `HOMEBREW_EVAL_ALL=1` set!" | 
					
						
							| 
									
										
										
										
											2023-08-27 13:50:53 -07:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           if show_formulae_and_casks || args.formula? | 
					
						
							| 
									
										
										
										
											2025-07-03 12:42:57 -04:00
										 |  |  |             deps += args.installed? ? Formula.installed : Formula.all(eval_all:) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           end | 
					
						
							|  |  |  |           if show_formulae_and_casks || args.cask? | 
					
						
							| 
									
										
										
										
											2025-07-03 12:42:57 -04:00
										 |  |  |             deps += args.installed? ? Cask::Caskroom.casks : Cask::Cask.all(eval_all:) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if args.missing? | 
					
						
							|  |  |  |             deps.reject! do |dep| | 
					
						
							|  |  |  |               case dep | 
					
						
							|  |  |  |               when Formula | 
					
						
							|  |  |  |                 dep.any_version_installed? | 
					
						
							|  |  |  |               when Cask::Cask | 
					
						
							|  |  |  |                 dep.installed? | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |             ignores.delete(:satisfied?) | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-07-30 12:59:01 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           select_used_dependents(dependents(deps), used_formulae, recursive, includes, ignores) | 
					
						
							|  |  |  |         end | 
					
						
							| 
									
										
										
										
											2020-07-30 12:59:01 -04:00
										 |  |  |       end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-10 23:39:19 +01:00
										 |  |  |       sig { | 
					
						
							|  |  |  |         params( | 
					
						
							| 
									
										
										
										
											2025-02-15 23:04:04 -08:00
										 |  |  |           dependents:    T::Array[T.any(Formula, CaskDependent)], | 
					
						
							|  |  |  |           used_formulae: T::Array[T.any(Formula, UnavailableFormula)], | 
					
						
							|  |  |  |           recursive:     T::Boolean, | 
					
						
							|  |  |  |           includes:      T::Array[Symbol], | 
					
						
							|  |  |  |           ignores:       T::Array[Symbol], | 
					
						
							|  |  |  |         ).returns(T::Array[T.any(Formula, CaskDependent)]) | 
					
						
							| 
									
										
										
										
											2024-08-10 23:39:19 +01:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |       def select_used_dependents(dependents, used_formulae, recursive, includes, ignores) | 
					
						
							|  |  |  |         dependents.select do |d| | 
					
						
							|  |  |  |           deps = if recursive | 
					
						
							| 
									
										
										
										
											2025-02-15 23:04:04 -08:00
										 |  |  |             recursive_dep_includes(d, includes, ignores) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           else | 
					
						
							|  |  |  |             select_includes(d.deps, ignores, includes) | 
					
						
							| 
									
										
										
										
											2020-07-30 12:59:01 -04:00
										 |  |  |           end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |           used_formulae.all? do |ff| | 
					
						
							|  |  |  |             deps.any? do |dep| | 
					
						
							| 
									
										
										
										
											2025-02-15 23:04:04 -08:00
										 |  |  |               match = case dep | 
					
						
							|  |  |  |               when Dependency | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |                 dep.to_formula.full_name == ff.full_name if dep.name.include?("/") | 
					
						
							| 
									
										
										
										
											2025-02-16 13:11:22 -08:00
										 |  |  |               when Requirement | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |                 nil | 
					
						
							| 
									
										
										
										
											2025-02-15 23:04:04 -08:00
										 |  |  |               else | 
					
						
							|  |  |  |                 T.absurd(dep) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:01:37 -07:00
										 |  |  |               end | 
					
						
							|  |  |  |               next match unless match.nil? | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |               dep.name == ff.name | 
					
						
							|  |  |  |             end | 
					
						
							|  |  |  |           rescue FormulaUnavailableError | 
					
						
							|  |  |  |             # Silently ignore this case as we don't care about things used in | 
					
						
							|  |  |  |             # taps that aren't currently tapped. | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2020-07-30 12:59:01 -04:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2010-09-11 20:22:54 +01:00
										 |  |  | end |