Last active
September 17, 2017 23:56
-
-
Save jca02266/419dba35f9a96fb5508208f691039e0a to your computer and use it in GitHub Desktop.
sample code of tsort library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'tsort' | |
# usage | |
=begin | |
$ cat depends | |
t1: t2 | |
t2: t3 | |
t3: | |
t4: t1 | |
$ ruby make.rb | |
t3: | |
#<Proc:[email protected]:90> | |
t2: t3 | |
#<Proc:[email protected]:90> | |
t1: t2 | |
#<Proc:[email protected]:90> | |
t4: t1 | |
#<Proc:[email protected]:90> | |
$ date > t3 | |
$ date > t2 | |
$ date > t1 | |
$ date > t4 | |
$ ls | |
depends make.rb t1 t2 t3 t4 | |
=end | |
class Make | |
include TSort | |
attr_accessor :ignore_case | |
def initialize | |
@ignore_case = true | |
@dep = {} | |
end | |
def rule(outputs, inputs=[], &block) | |
if @ignore_case | |
outputs = outputs.collect {|v| | |
if Symbol === v | |
v | |
else | |
v.downcase | |
end | |
} | |
inputs = inputs.collect(&:downcase) | |
end | |
inputs = inputs.flat_map {|v| | |
Dir.glob(v) | |
} | |
triple = [outputs, inputs, block] | |
outputs.each {|f| | |
dep = @dep[f] | |
if dep | |
old_outputs, old_inputs, old_block = old_triple = dep[0] | |
new_inputs = old_inputs + inputs | |
new_triple = [old_outputs, new_inputs, old_block] | |
@dep.delete(old_triple) | |
@dep[new_triple] = new_inputs | |
@dep[f] = [new_triple] | |
else | |
@dep[f] = [triple] | |
end | |
} | |
@dep[triple] = inputs | |
end | |
def each(target) | |
each_strongly_connected_component_from(target) {|ns| | |
if ns.length != 1 | |
fs = ns.delete_if {|n| Array === n} | |
raise TSort::Cyclic.new("cyclic dependencies: #{fs.join ', '}") | |
end | |
n = ns.first | |
if Array === n | |
yield n | |
end | |
} | |
end | |
def list(target) | |
each(target) {|outputs, inputs, block| | |
puts "#{outputs.join(", ")}: #{inputs.join(", ")}" | |
puts " #{block}" if block | |
} | |
end | |
def build(target) | |
each(target) {|outputs, inputs, block| | |
outputs.each {|out| | |
next if Symbol === out | |
inputs_time = inputs.map {|f| File.mtime f}.max | |
begin | |
output_time = File.mtime out | |
rescue Errno::ENOENT | |
output_time = nil | |
end | |
if block | |
if output_time == nil || | |
inputs_time != nil && output_time <= inputs_time | |
block.call(out, inputs) | |
end | |
end | |
} | |
} | |
end | |
def tsort_each_child(node, &block) | |
@dep.fetch(node).each(&block) | |
end | |
def load(file, &func) | |
File.foreach(file) do |line| | |
next if /^[ \t]*#/ =~ line # comment | |
m = /^(?<targets>.*?):(?<depends>.*)/.match(line) | |
if m | |
targets = m[:targets].strip.split(/,/).map(&:strip) | |
depends = m[:depends].strip.split(/,/).map(&:strip) | |
rule(targets, depends, &func) | |
rule([:all], targets) | |
end | |
end | |
end | |
end | |
def command(arg) | |
print "$ ", arg, "\n" | |
system arg | |
end | |
m = Make.new | |
m.load('depends') {|target, depends| | |
command "date > #{target}" | |
} | |
begin | |
m.list(:all) | |
m.build(:all) | |
rescue => e | |
puts "Error: " + e.message | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment