deps: print cask dependencies

* Allow references to commands when using `brew deps`, e.g. `brew deps
cellery`
* Fix crash when using `brew deps <formula> --installed
--include-requirements`
* Do not include runtime dependencies as direct dependencies when using
`--tree`
This commit is contained in:
William Ma 2020-07-27 19:12:16 -04:00
parent 97cf1750f3
commit cc63cece76
4 changed files with 133 additions and 35 deletions

View File

@ -35,6 +35,7 @@ module Homebrew
def freeze_named_args!(named_args) def freeze_named_args!(named_args)
# Reset cache values reliant on named_args # Reset cache values reliant on named_args
@formulae = nil @formulae = nil
@formulae_and_casks = nil
@resolved_formulae = nil @resolved_formulae = nil
@resolved_formulae_casks = nil @resolved_formulae_casks = nil
@formulae_paths = nil @formulae_paths = nil
@ -90,6 +91,24 @@ module Homebrew
end.uniq(&:name).freeze end.uniq(&:name).freeze
end end
def formulae_and_casks
@formulae_and_casks ||= begin
formulae_and_casks = []
downcased_unique_named.each do |name|
formulae_and_casks << Formulary.factory(name, spec)
rescue FormulaUnavailableError
begin
formulae_and_casks << Cask::CaskLoader.load(name)
rescue Cask::CaskUnavailableError
raise "No available formula or cask with the name \"#{name}\""
end
end
formulae_and_casks.freeze
end
end
def resolved_formulae def resolved_formulae
require "formula" require "formula"

View File

@ -3,6 +3,7 @@
require "formula" require "formula"
require "ostruct" require "ostruct"
require "cli/parser" require "cli/parser"
require "cask/caskroom"
module Homebrew module Homebrew
extend DependenciesHelpers extend DependenciesHelpers
@ -64,51 +65,68 @@ module Homebrew
Formulary.enable_factory_cache! Formulary.enable_factory_cache!
recursive = !args.send("1?") recursive = !args.send("1?")
installed = args.installed? || args.formulae.all?(&:opt_or_installed_prefix_keg) installed = args.installed? || dependents(args.formulae_and_casks).all?(&:any_version_installed?)
@use_runtime_dependencies = installed && recursive && @use_runtime_dependencies = installed && recursive &&
!args.tree? &&
!args.include_build? && !args.include_build? &&
!args.include_test? && !args.include_test? &&
!args.include_optional? && !args.include_optional? &&
!args.skip_recommended? !args.skip_recommended?
if args.tree? if args.tree?
if args.installed? dependents = if args.named.present?
puts_deps_tree Formula.installed.sort, recursive sorted_dependents(args.formulae_and_casks)
elsif args.installed?
sorted_dependents(Formula.installed + Cask::Caskroom.casks)
else else
raise FormulaUnspecifiedError if args.no_named? raise FormulaUnspecifiedError
puts_deps_tree args.formulae, recursive
end end
puts_deps_tree dependents, recursive
return return
elsif args.all? elsif args.all?
puts_deps Formula.sort, recursive puts_deps sorted_dependents(Formula.to_a + Cask::Cask.to_a), recursive
return return
elsif !args.no_named? && args.for_each? elsif !args.no_named? && args.for_each?
puts_deps args.formulae, recursive puts_deps sorted_dependents(args.formulae_and_casks), recursive
return return
end end
if args.no_named? if args.no_named?
raise FormulaUnspecifiedError unless args.installed? raise FormulaUnspecifiedError unless args.installed?
puts_deps Formula.installed.sort, recursive puts_deps sorted_dependents(Formula.installed + Cask::Caskroom.casks), recursive
return return
end end
all_deps = deps_for_formulae(args.formulae, recursive, &(args.union? ? :| : :&)) dependents = dependents(args.formulae_and_casks)
all_deps = condense_requirements(all_deps)
all_deps.select!(&:installed?) if args.installed? all_deps = deps_for_dependents(dependents, recursive, &(args.union? ? :| : :&))
condense_requirements(all_deps)
all_deps.map!(&method(:dep_display_name)) all_deps.map!(&method(:dep_display_name))
all_deps.uniq! all_deps.uniq!
all_deps.sort! unless args.n? all_deps.sort! unless args.n?
puts all_deps puts all_deps
end end
def condense_requirements(deps) def dependents(formulae_or_casks)
return deps if args.include_requirements? formulae_or_casks.map do |formula_or_cask|
if formula_or_cask.is_a?(Formula)
formula_or_cask
else
Dependent.new(formula_or_cask)
end
end
end
deps.select { |dep| dep.is_a? Dependency } def sorted_dependents(formulae_or_casks)
dependents(formulae_or_casks).sort_by(&:name)
end
def condense_requirements(deps)
deps.select! { |dep| dep.is_a?(Dependency) } unless args.include_requirements?
deps.select! { |dep| dep.is_a?(Requirement) || dep.installed? } if args.installed?
end end
def dep_display_name(dep) def dep_display_name(dep)
@ -136,41 +154,41 @@ module Homebrew
str str
end end
def deps_for_formula(f, recursive = false) def deps_for_dependent(d, recursive = false)
includes, ignores = argv_includes_ignores(ARGV) includes, ignores = argv_includes_ignores(ARGV)
deps = f.runtime_dependencies if @use_runtime_dependencies deps = d.runtime_dependencies if @use_runtime_dependencies
if recursive if recursive
deps ||= recursive_includes(Dependency, f, includes, ignores) deps ||= recursive_includes(Dependency, d, includes, ignores)
reqs = recursive_includes(Requirement, f, includes, ignores) reqs = recursive_includes(Requirement, d, includes, ignores)
else else
deps ||= reject_ignores(f.deps, ignores, includes) deps ||= reject_ignores(d.deps, ignores, includes)
reqs = reject_ignores(f.requirements, ignores, includes) reqs = reject_ignores(d.requirements, ignores, includes)
end end
deps + reqs.to_a deps + reqs.to_a
end end
def deps_for_formulae(formulae, recursive = false, &block) def deps_for_dependents(dependents, recursive = false, &block)
formulae.map { |f| deps_for_formula(f, recursive) }.reduce(&block) dependents.map { |d| deps_for_dependent(d, recursive) }.reduce(&block)
end end
def puts_deps(formulae, recursive = false) def puts_deps(dependents, recursive = false)
formulae.each do |f| dependents.each do |d|
deps = deps_for_formula(f, recursive) deps = deps_for_dependent(d, recursive)
deps = condense_requirements(deps) condense_requirements(deps)
deps.sort_by!(&:name) deps.sort_by!(&:name)
deps.map!(&method(:dep_display_name)) deps.map!(&method(:dep_display_name))
puts "#{f.full_name}: #{deps.join(" ")}" puts "#{d.full_name}: #{deps.join(" ")}"
end end
end end
def puts_deps_tree(formulae, recursive = false) def puts_deps_tree(dependents, recursive = false)
formulae.each do |f| dependents.each do |d|
puts f.full_name puts d.full_name
@dep_stack = [] @dep_stack = []
recursive_deps_tree(f, "", recursive) recursive_deps_tree(d, "", recursive)
puts puts
end end
end end
@ -211,4 +229,61 @@ module Homebrew
@dep_stack.pop @dep_stack.pop
end end
class Dependent
def initialize(cask)
@cask = cask
end
def name
@cask.token
end
def full_name
@cask.full_name
end
def runtime_dependencies
recursive_dependencies
end
def deps
@deps ||= begin
@cask.depends_on.formula.map do |f|
Dependency.new f
end
end
end
def requirements
@requirements ||= begin
requirements = []
dsl_reqs = @cask.depends_on
dsl_reqs.arch&.each do |arch|
requirements << ArchRequirement.new([:x86_64]) if arch[:bits] == 64
requirements << ArchRequirement.new([arch[:type]])
end
dsl_reqs.cask.each do |cask_ref|
requirements << Requirement.new([{ cask: cask_ref }])
end
requirements << dsl_reqs.macos if dsl_reqs.macos
requirements << X11Requirement.new if dsl_reqs.x11
requirements
end
end
def recursive_dependencies(&block)
Dependency.expand(self, &block)
end
def recursive_requirements(&block)
Requirement.expand(self, &block)
end
def any_version_installed?
@cask.installed?
end
end
end end

View File

@ -84,7 +84,7 @@ module DependenciesHelpers
[includes, ignores] [includes, ignores]
end end
def recursive_includes(klass, formula, includes, ignores) def recursive_includes(klass, root_dependent, includes, ignores)
type = if klass == Dependency type = if klass == Dependency
:dependencies :dependencies
elsif klass == Requirement elsif klass == Requirement
@ -93,7 +93,7 @@ module DependenciesHelpers
raise ArgumentError, "Invalid class argument: #{klass}" raise ArgumentError, "Invalid class argument: #{klass}"
end end
formula.send("recursive_#{type}") do |dependent, dep| root_dependent.send("recursive_#{type}") do |dependent, dep|
if dep.recommended? if dep.recommended?
klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep) klass.prune if ignores.include?("recommended?") || dependent.build.without?(dep)
elsif dep.optional? elsif dep.optional?

View File

@ -135,7 +135,11 @@ class Requirement
klass = self.class.name || self.class.to_s klass = self.class.name || self.class.to_s
klass.sub!(/(Dependency|Requirement)$/, "") klass.sub!(/(Dependency|Requirement)$/, "")
klass.sub!(/^(\w+::)*/, "") klass.sub!(/^(\w+::)*/, "")
klass.downcase return klass.downcase if klass.present?
return @cask if @cask.present?
""
end end
def which(cmd) def which(cmd)