class Terraspace::Dependency::Graph

Constants

MAX_CYCLE_DEPTH

Attributes

nodes[R]

Public Class Methods

new(stack_names, dependencies, options={}) click to toggle source
# File lib/terraspace/dependency/graph.rb, line 6
def initialize(stack_names, dependencies, options={})
  @stack_names, @dependencies, @options = stack_names, dependencies, options
  @nodes = []
  @batches = []
end

Public Instance Methods

apply_filter(parent, keep=false) click to toggle source
# File lib/terraspace/dependency/graph.rb, line 116
def apply_filter(parent, keep=false)
  keep ||= @options[:stacks].blank?
  keep ||= @options[:stacks].include?(parent.name)  # apply filter
  if keep
    parent.filtered = true
    @filtered << parent
  end
  parent.children.sort_by(&:name).each do |child|
    apply_filter(child, keep)
  end
end
build() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 12
def build
  precreate_all_nodes
  build_nodes_with_dependencies # @nodes has dependency graph info afterwards
  check_circular_dependencies!
  @nodes = filter_nodes
  check_empty_nodes!
  build_batches
  clean_batches
  @batches
end
build_batch(leaf, depth=1) click to toggle source
# File lib/terraspace/dependency/graph.rb, line 92
def build_batch(leaf, depth=1)
  @batches[depth] ||= Set.new
  @batches[depth] << leaf
  leaf.parents.each do |parent|
    build_batch(parent, depth+1)
  end
end
build_batches() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 69
def build_batches
  @batches[0] = Set.new(leaves)
  leaves.each do |leaf|
    leaf.parents.each do |parent|
      build_batch(parent)
    end
  end
end
build_nodes_with_dependencies() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 54
def build_nodes_with_dependencies
  @dependencies.each do |item|
    parent_name, child_name = item.split(':')
    save_node_parent(parent_name, child_name)
  end
end
check_circular_dependencies!() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 30
def check_circular_dependencies!
  @nodes.each do |node|
    check_cycle(node)
  end
end
check_cycle(node, depth=0, list=[]) click to toggle source
# File lib/terraspace/dependency/graph.rb, line 37
def check_cycle(node, depth=0, list=[])
  if depth > MAX_CYCLE_DEPTH
    logger.error "ERROR: It seems like there is a circular dependency! Stacks involved: #{list.uniq}".color(:red)
    exit 1
  end
  node.parents.each do |parent|
    check_cycle(parent, depth+1, list += [parent])
  end
end
check_empty_nodes!() click to toggle source

Only check when stacks option is pass. Edge case: There can be app/modules but no app/stacks yet

# File lib/terraspace/dependency/graph.rb, line 24
def check_empty_nodes!
  return unless @nodes.empty? && @options[:stacks]
  logger.error "ERROR: No stacks were found that match: #{@options[:stacks].join(' ')}".color(:red)
  exit 1
end
clean_batches() click to toggle source

So stack nodes dont get deployed more than once and too early

# File lib/terraspace/dependency/graph.rb, line 79
def clean_batches
  all = Set.new
  # batch is a set
  @batches.reverse.each do |batch|
    batch.each do |node|
      batch.delete(node) if all.include?(node)
    end
    all += batch
  end
  @batches.reject! { |batch| batch.empty? }
  @batches
end
filter_nodes() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 100
def filter_nodes
  @filtered = []
  top_nodes.each { |node| apply_filter(node) }
  # draw_full_graph option is only used internally by All::Grapher
  update_parents! unless @options[:draw_full_graph]
  @options[:draw_full_graph] ? @nodes : @filtered
end
leaves() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 128
def leaves
  @nodes.select { |n| n.children.empty? }.sort_by(&:name)
end
precreate_all_nodes() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 47
def precreate_all_nodes
  @stack_names.each do |name|
    node = Node.find_or_create_by(name: name)
    save_node(node)
  end
end
save_node(node) click to toggle source
# File lib/terraspace/dependency/graph.rb, line 136
def save_node(node)
  @nodes << node unless @nodes.detect { |n| n.name == node.name }
end
save_node_parent(parent_name, child_name) click to toggle source
# File lib/terraspace/dependency/graph.rb, line 61
def save_node_parent(parent_name, child_name)
  parent = Node.find_by(name: parent_name)
  child = Node.find_by(name: child_name)
  child.parent!(parent)
  save_node(parent)
  save_node(child)
end
top_nodes() click to toggle source
# File lib/terraspace/dependency/graph.rb, line 132
def top_nodes
  @nodes.select { |n| n.parents.empty? }.sort_by(&:name)
end
update_parents!() click to toggle source

remove missing parents references since they will be filtered out

# File lib/terraspace/dependency/graph.rb, line 109
def update_parents!
  @filtered.each do |node|
    new_parents = node.parents & @filtered
    node.parents = new_parents
  end
end