aboutsummaryrefslogtreecommitdiffstats
path: root/Library/Homebrew/cask
diff options
context:
space:
mode:
authorMarkus Reiter2017-06-28 17:53:59 +0200
committerMarkus Reiter2017-06-30 02:20:50 +0200
commit6a1fa87191bfef31ff1b2d47d3ebf281398a210f (patch)
tree10efb928a0477fe63510425cff4af8303b65af82 /Library/Homebrew/cask
parent96271aaa89c47cf4f0ff10e8e9a165c1ac2cdb73 (diff)
downloadbrew-6a1fa87191bfef31ff1b2d47d3ebf281398a210f.tar.bz2
Refactor Formula/Cask dependencies.
Diffstat (limited to 'Library/Homebrew/cask')
-rw-r--r--Library/Homebrew/cask/lib/hbc/cask.rb9
-rw-r--r--Library/Homebrew/cask/lib/hbc/cask_dependencies.rb37
-rw-r--r--Library/Homebrew/cask/lib/hbc/dsl.rb4
-rw-r--r--Library/Homebrew/cask/lib/hbc/dsl/depends_on.rb4
-rw-r--r--Library/Homebrew/cask/lib/hbc/exceptions.rb12
-rw-r--r--Library/Homebrew/cask/lib/hbc/installer.rb67
6 files changed, 82 insertions, 51 deletions
diff --git a/Library/Homebrew/cask/lib/hbc/cask.rb b/Library/Homebrew/cask/lib/hbc/cask.rb
index 4a410f4c7..672d18954 100644
--- a/Library/Homebrew/cask/lib/hbc/cask.rb
+++ b/Library/Homebrew/cask/lib/hbc/cask.rb
@@ -71,6 +71,15 @@ module Hbc
@token
end
+ def hash
+ token.hash
+ end
+
+ def eql?(other)
+ token == other.token
+ end
+ alias == eql?
+
def dumpcask
odebug "Cask instance dumps in YAML:"
odebug "Cask instance toplevel:", to_yaml
diff --git a/Library/Homebrew/cask/lib/hbc/cask_dependencies.rb b/Library/Homebrew/cask/lib/hbc/cask_dependencies.rb
index 8bba5df8e..0edda074e 100644
--- a/Library/Homebrew/cask/lib/hbc/cask_dependencies.rb
+++ b/Library/Homebrew/cask/lib/hbc/cask_dependencies.rb
@@ -1,35 +1,36 @@
+require "delegate"
+
require "hbc/topological_hash"
module Hbc
- class CaskDependencies
- attr_reader :cask, :graph, :sorted
+ class CaskDependencies < DelegateClass(Array)
+ attr_reader :cask, :graph
def initialize(cask)
@cask = cask
@graph = graph_dependencies
- @sorted = sort
+ super(sort)
end
- def graph_dependencies
- deps_in = ->(csk) { csk.depends_on ? csk.depends_on.cask || [] : [] }
- walk = lambda do |acc, deps|
- deps.each do |dep|
- next if acc.key?(dep)
- succs = deps_in.call CaskLoader.load(dep)
- acc[dep] = succs
- walk.call(acc, succs)
- end
- acc
- end
+ private
- graphed = walk.call({}, @cask.depends_on.cask)
- TopologicalHash[graphed]
+ def graph_dependencies(cask = self.cask, acc = TopologicalHash.new)
+ return acc if acc.key?(cask)
+ deps = cask.depends_on.cask.map(&CaskLoader.public_method(:load))
+ acc[cask] = deps
+ deps.each do |dep|
+ graph_dependencies(dep, acc)
+ end
+ acc
end
def sort
- @graph.tsort
+ raise CaskSelfReferencingDependencyError, cask.token if graph[cask].include?(cask)
+ graph.tsort - [cask]
rescue TSort::Cyclic
- raise CaskCyclicCaskDependencyError, @cask.token
+ strongly_connected_components = graph.strongly_connected_components.sort_by(&:count)
+ cyclic_dependencies = strongly_connected_components.last - [cask]
+ raise CaskCyclicDependencyError.new(cask.token, cyclic_dependencies.join(", "))
end
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/dsl.rb b/Library/Homebrew/cask/lib/hbc/dsl.rb
index 92245e8fb..112ceb943 100644
--- a/Library/Homebrew/cask/lib/hbc/dsl.rb
+++ b/Library/Homebrew/cask/lib/hbc/dsl.rb
@@ -211,10 +211,10 @@ module Hbc
# depends_on uses a load method so that multiple stanzas can be merged
def depends_on(*args)
- return @depends_on if args.empty?
@depends_on ||= DSL::DependsOn.new
+ return @depends_on if args.empty?
begin
- @depends_on.load(*args) unless args.empty?
+ @depends_on.load(*args)
rescue RuntimeError => e
raise CaskInvalidError.new(token, e)
end
diff --git a/Library/Homebrew/cask/lib/hbc/dsl/depends_on.rb b/Library/Homebrew/cask/lib/hbc/dsl/depends_on.rb
index a8c1a1b73..bdef4239a 100644
--- a/Library/Homebrew/cask/lib/hbc/dsl/depends_on.rb
+++ b/Library/Homebrew/cask/lib/hbc/dsl/depends_on.rb
@@ -24,6 +24,8 @@ module Hbc
def initialize
@pairs ||= {}
+ @cask ||= []
+ @formula ||= []
end
def load(pairs = {})
@@ -53,12 +55,10 @@ module Hbc
end
def formula=(*args)
- @formula ||= []
@formula.concat(args)
end
def cask=(*args)
- @cask ||= []
@cask.concat(args)
end
diff --git a/Library/Homebrew/cask/lib/hbc/exceptions.rb b/Library/Homebrew/cask/lib/hbc/exceptions.rb
index d9e1b07db..1a246be65 100644
--- a/Library/Homebrew/cask/lib/hbc/exceptions.rb
+++ b/Library/Homebrew/cask/lib/hbc/exceptions.rb
@@ -77,9 +77,15 @@ module Hbc
end
end
- class CaskCyclicCaskDependencyError < AbstractCaskErrorWithToken
+ class CaskCyclicDependencyError < AbstractCaskErrorWithToken
def to_s
- "Cask '#{token}' includes cyclic dependencies on other Casks and could not be installed."
+ "Cask '#{token}' includes cyclic dependencies on other Casks" << (reason.empty? ? "." : ": #{reason}")
+ end
+ end
+
+ class CaskSelfReferencingDependencyError < CaskCyclicDependencyError
+ def to_s
+ "Cask '#{token}' depends on itself."
end
end
@@ -91,7 +97,7 @@ module Hbc
class CaskInvalidError < AbstractCaskErrorWithToken
def to_s
- "Cask '#{token}' definition is invalid" << (reason.empty? ? ".": ": #{reason}")
+ "Cask '#{token}' definition is invalid" << (reason.empty? ? "." : ": #{reason}")
end
end
diff --git a/Library/Homebrew/cask/lib/hbc/installer.rb b/Library/Homebrew/cask/lib/hbc/installer.rb
index 0477cbd22..252205a3b 100644
--- a/Library/Homebrew/cask/lib/hbc/installer.rb
+++ b/Library/Homebrew/cask/lib/hbc/installer.rb
@@ -1,5 +1,7 @@
require "rubygems"
+require "formula_installer"
+
require "hbc/cask_dependencies"
require "hbc/staged"
require "hbc/verify"
@@ -197,7 +199,6 @@ module Hbc
x11_dependencies
formula_dependencies
cask_dependencies unless skip_cask_deps?
- puts "complete"
end
def macos_dependencies
@@ -234,36 +235,50 @@ module Hbc
end
def formula_dependencies
- return unless @cask.depends_on.formula && !@cask.depends_on.formula.empty?
- ohai "Installing Formula dependencies from Homebrew"
- @cask.depends_on.formula.each do |dep_name|
- print "#{dep_name} ... "
- installed = @command.run(HOMEBREW_BREW_FILE,
- args: ["list", "--versions", dep_name],
- print_stderr: false).stdout.include?(dep_name)
- if installed
- puts "already installed"
- else
- @command.run!(HOMEBREW_BREW_FILE,
- args: ["install", dep_name])
- puts "done"
+ formulae = @cask.depends_on.formula.map { |f| Formula[f] }
+ return if formulae.empty?
+
+ if formulae.all?(&:any_version_installed?)
+ puts "All Formula dependencies satisfied."
+ return
+ end
+
+ not_installed = formulae.reject(&:any_version_installed?)
+
+ ohai "Installing Formula dependencies: #{not_installed.map(&:to_s).join(", ")}"
+ not_installed.each do |formula|
+ begin
+ old_argv = ARGV.dup
+ ARGV.replace([])
+ FormulaInstaller.new(formula).tap do |fi|
+ fi.installed_as_dependency = true
+ fi.installed_on_request = false
+ fi.show_header = true
+ fi.verbose = verbose?
+ fi.prelude
+ fi.install
+ fi.finish
+ end
+ ensure
+ ARGV.replace(old_argv)
end
end
end
def cask_dependencies
- return unless @cask.depends_on.cask && !@cask.depends_on.cask.empty?
- ohai "Installing Cask dependencies: #{@cask.depends_on.cask.join(", ")}"
- deps = CaskDependencies.new(@cask)
- deps.sorted.each do |dep_token|
- puts "#{dep_token} ..."
- dep = CaskLoader.load(dep_token)
- if dep.installed?
- puts "already installed"
- else
- Installer.new(dep, binaries: binaries?, verbose: verbose?, skip_cask_deps: true, force: false).install
- puts "done"
- end
+ return if @cask.depends_on.cask.empty?
+ casks = CaskDependencies.new(@cask)
+
+ if casks.all?(&:installed?)
+ puts "All Cask dependencies satisfied."
+ return
+ end
+
+ not_installed = casks.reject(&:installed?)
+
+ ohai "Installing Cask dependencies: #{not_installed.map(&:to_s).join(", ")}"
+ not_installed.each do |cask|
+ Installer.new(cask, binaries: binaries?, verbose: verbose?, skip_cask_deps: true, force: false).install
end
end