lib/logical-construct/resolving-task.rb in logical-construct-0.0.1.localtesting vs lib/logical-construct/resolving-task.rb in logical-construct-0.0.1

- old
+ new

@@ -1,7 +1,8 @@ require 'rake/task' require 'mattock/task' +require 'logical-construct/satisfiable-task' module LogicalConstruct #Ensures that all it's deps are satisfied before proceeding - the action for #ResolvingTasks is all about satisfying deps. # @@ -15,24 +16,126 @@ # and #execute if needed # #So, of note: you'll only get invoked once, ever #You'll only be executed if #needed? #Deps will get invoked (ish) even if not #needed? - # + module SatisfiableManager + def default_configuration(*configurables) + super + self.satisfiables = configurables.find_all do |conf| + conf.is_a? SatisfiableTask + end.map{|sat| sat.rake_task} + end + + def define + super + satisfiables.each do |sat| + sat.enhance([rake_task.name]) + end + end + + def add_satisfiable(task) + task = task.rake_task if task.respond_to? :rake_task + satisfiables << task + task.enhance([rake_task.name]) + end + end + + require 'yaml' + require 'digest' + module ResolutionProtocol + def digest + @digest ||= Digest::SHA2.new + end + + def file_checksum(path) + generate_checksum(File::read(path)) + end + + def generate_checksum(data) + digest.reset + digest << data + digest.hexdigest + end + + def web_path(task_name) + "/" + task_name.gsub(":", "/") + end + end + class ResolvingTask < Rake::Task include Mattock::TaskMixin + include SatisfiableManager + setting :satisfiables, [] + def needed? - prerequisite_tasks.any?{|task| task.needed?} + !unsatisfied.empty? end - def unsatisfied_prerequisites - prerequisite_tasks.find_all{|task| task.needed?} + def unsatisfied + satisfiables.find_all{|task| task.needed?} end def execute(args=nil) super if needed? - raise "Task #{name} failed to satisfy: #{unsatisfied_prerequisites.inspect}" + raise "Task #{name} failed to satisfy: #{unsatisfied.inspect}" end + end + end + + class Manifest < SatisfiableTask + include SatisfiableManager + include ResolutionProtocol + + setting :satisfiables, [] + nil_field :manifest + + default_taskname "Manifest" + + def invalid_checksum(checksum, path) + return false unless File::exists?(path) + return true if checksum.nil? or checksum.empty? + return checksum != file_checksum(path) + end + + def needed? + manifest.nil? + end + + def fulfill(data) + self.manifest = YAML::load(data) + satisfiables.each do |sat| + path = sat.target_path + checksum = manifest[sat.name] + if invalid_checksum(checksum, path) + File::rename(path, path + ".invalid") + end + end + end + end + + class GenerateManifest < Mattock::Task + include ResolutionProtocol + setting :hash, {} + setting :resolutions + setting :receiving_name + + def default_configuration(resolution_host) + super + self.resolutions = resolution_host.resolutions + end + + def data_checksum(path, data) + hash[path] = generate_checksum(data) + end + + def action + resolutions.each_pair do |destination, data| + data = data.call if data.respond_to? :call + data = data.read if data.respond_to? :read + hash[destination] = generate_checksum(data) + end + resolutions[receiving_name] = YAML::dump(hash) end end end