lib/hx.rb in hx-0.15.0 vs lib/hx.rb in hx-0.16.0
- old
+ new
@@ -25,10 +25,11 @@
require 'set'
require 'pathname'
require 'tempfile'
require 'yaml'
require 'hx/path'
+require 'set'
module Hx
VERSION = (Pathname.new(__FILE__).parent.parent + 'VERSION').read.strip
@@ -335,10 +336,11 @@
def Chain.new(input, options)
filters = options[:chain] || []
options = options.dup
options.delete(:chain) # prevent inheritance
for raw_filter in filters
+ raw_filter = Hx.expand_chain(raw_filter)
input = Hx.build_source(options, input, {}, raw_filter)
end
input
end
@@ -407,22 +409,34 @@
end
end
raw_input
end
-def self.build_source(options, default_input, sources, raw_source)
- raw_source = expand_chain(raw_source)
-
+def self.get_input_names(raw_source)
if raw_source.has_key? 'input'
- input_name = raw_source['input']
+ return Array(raw_source['input'])
+ else
+ []
+ end
+end
+
+def self.build_source(options, default_input, sources, raw_source)
+ input_names = get_input_names(raw_source)
+ input_sources = input_names.map do |input_name|
begin
- source = sources.fetch(input_name)
+ sources.fetch(input_name)
rescue IndexError
raise NameError, "No source named #{input_name} in scope"
end
- else
+ end
+ case input_sources.length
+ when 0
source = default_input
+ when 1
+ source = input_sources.first
+ else
+ source = Overlay.new(*input_sources)
end
if raw_source.has_key? 'filter'
if raw_source.has_key? 'options'
filter_options = options.dup
@@ -498,43 +512,51 @@
end
end
raw_sources_by_name = raw_config.fetch('sources', {})
raw_outputs = raw_config.fetch('output', [])
- source_names = raw_sources_by_name.keys
+ for name, raw_source in raw_sources_by_name
+ raw_sources_by_name[name] = Hx.expand_chain(raw_source)
+ end
+ raw_outputs = raw_outputs.map! do |raw_output|
+ Hx.expand_chain(raw_output)
+ end
# build input dependency graph
- source_dependencies = {}
+ source_dependencies = Hash.new { |h,k| h[k] = Set.new }
source_count_by_dependency = Hash.new(0)
for name, raw_source in raw_sources_by_name
- raw_source = Hx.expand_chain(raw_source)
- if raw_source.has_key? 'input'
- input_name = raw_source['input']
- source_dependencies[name] = input_name
+ for input_name in Hx.get_input_names(raw_source)
+ source_dependencies[name].add input_name
source_count_by_dependency[input_name] += 1
end
end
for raw_output in raw_outputs
- raw_output = Hx.expand_chain(raw_output)
- if raw_output.has_key? 'input'
- input_name = raw_source['input']
+ for input_name in Hx.get_input_names(raw_source)
source_count_by_dependency[input_name] += 1
end
end
+ source_names = raw_sources_by_name.keys
+
# calculate depth for each input in the graph
source_depths = Hash.new(0)
- for name in source_names
- seen = Set[] # for cycle detection
- while source_dependencies.has_key? name
- if seen.include? name
- raise RuntimeError, "cycle in source graph at #{name}"
- end
- seen.add name
+ to_process = Set.new(source_names)
+ until to_process.empty?
+ need_updating = Set.new
+ for name in to_process
depth = source_depths[name] + 1
- name = source_dependencies[name]
- source_depths[name] = depth if depth > source_depths[name]
+ if depth >= source_names.length
+ raise "cycle in source graph involving #{name}"
+ end
+ for input_name in source_dependencies[name]
+ if depth > source_depths[input_name]
+ source_depths[input_name] = depth
+ need_updating.add input_name
+ end
+ end
end
+ to_process = need_updating
end
# depth-first topological sort
depth_first_names = source_names.sort_by { |n| -source_depths[n] }