Skip to content

Instantly share code, notes, and snippets.

@manveru
Created April 5, 2009 06:37
Show Gist options
  • Save manveru/90392 to your computer and use it in GitHub Desktop.
Save manveru/90392 to your computer and use it in GitHub Desktop.
Raku is a tiny rake-task manager
#!/usr/bin/env ruby
require 'optparse'
require 'ostruct'
require 'pathname'
require 'fileutils'
require 'digest/sha1'
ACTIONS = []
TARGETS = []
OPTIONS = OpenStruct.new(
:force => false,
:verbose => false,
:quiet => false,
:noop => false,
:color => false,
:proto => Pathname('~/.config/raku/tasks'),
:target => Pathname('./tasks')
)
target = OPTIONS.target
proto = OPTIONS.proto
op = OptionParser.new{|o|
o.separator(" ")
o.separator("Target modes:")
o.on('-P', '--proto', "run commands against #{proto} as target"){ TARGETS << :proto }
o.on('-T', '--tasks', "run commands against #{target} as target"){ TARGETS << :tasks }
o.separator(" ")
o.separator("Target commands:")
o.on('-u', '--update',
"Update all files in target"){ ACTIONS << :update }
o.on('-d', '--diff',
"Diff files between targets"){ ACTIONS << :diff }
o.on('-l', '--list',
"List files in target"){ ACTIONS << :list }
o.on('-i', '--init',
"Copy the Rakefile to target"){ ACTIONS << :init }
o.on('-p', '--put FILE1,FILE2,...', Array,
"Put given file(s) into target"){|p| ACTIONS << [:put, *p] }
o.on('-r', '--remove FILE!,FILE2,...', Array,
"Remove given files from target"){|r| ACTIONS << [:remove, *r] }
o.separator(" ")
o.separator("Configuration:")
o.on('-t', '--target-dir DIR',
"Location for project tasks, default is #{target}"){|t| OPTIONS.target = t }
o.on( '--proto-dir DIR',
"Location of PROTO, default is #{proto}"){|p| OPTIONS.proto = Pathname(p) }
o.on('-f', '--force',
"Don't ask silly questions when overwriting files"){|f| OPTIONS.force = f }
o.on('-v', '--verbose',
"Tell me everything"){|v| OPTIONS.verbose = v }
o.on('-q', '--quiet',
"Tell me nothing, takes precendence over --verbose"){|q| OPTIONS.quiet = q }
o.on('-n', '--noop',
"Don't do anything for real, useful with --verbose"){|n| OPTIONS.noop = n }
o.on('-c', '--color',
"Use colors for diff, needs colordiff installed"){|c| OPTIONS.color = c }
o.separator(" ")
o.separator("About:")
o.on('-V', '--version', 'Version of Raku'){ puts Raku::VERSION; exit }
o.on('-h', '--help', 'Display this help'){ puts o; exit }
}
class Pathname
def glob(g)
self.class.glob(self.join(g))
end
def digest
Digest::SHA1.hexdigest(read) if exist?
end
end
class Raku
VERSION = '2009.03.27'
class ProtoPOV < Raku
def proto; @options.target.expand_path end
def target; @options.proto.expand_path end
end
class TargetPOV < Raku
end
def initialize(options)
@options = options
mkdir_p(proto)
end
def init
require 'erb'
target_rakefile = target.join('Rakefile')
proto_rakefile = proto.join('Rakefile')
cp(proto.join('Rakefile'), target.parent)
File.read(proto_rakefile)
end
def remove(*files)
end
def put(*files)
mkdir_p(target)
done_something = false
files.each do |file|
if file.exist?
done_something = true
put_file(file)
else
proto.glob("*#{file}*.rake").each do |from|
done_something = true
put_file(from)
end
end
end
log("No files match your request: %p", files) unless done_something
end
def put_file(from)
to = target.join(from.basename)
log("Put %s into %s", from, to)
cp(from, to)
end
def diff
diffbin = color? ? 'colordiff' : 'diff'
sh(diffbin, '-u', proto, target)
end
def list
proto_files = proto.glob('*.rake')
target_files = target.glob('*.rake')
hash = Hash.new{|h,k| h[k] = [] }
proto_files.each{|file| hash[file.digest] << file }
target_files.each{|file| hash[file.digest] << file }
puts "PROTO = %s | TARGET = %s" % [proto, target]
puts
proto_len = proto_files.map{|f| f.basename.to_s.size }.max
target_len = target_files.map{|f| f.basename.to_s.size }.max
hash.each do |digest, files|
args = files.map{|f| f.basename }
args << '' if args.size == 1
puts "%40s : %-#{proto_len}s | %-#{target_len}s" % [digest, *args]
end
end
def update
mkdir_p(target)
proto.glob('*.rake').each do |from|
to = target.join(from.basename)
if from.digest == to.digest
debug("Won't copy %s, file contents are identical", from.basename)
else
cp(from, to)
end
end
end
private
def mkdir_p(dir)
return if File.directory?(dir)
debug("Create directory %p", dir)
FileUtils.mkdir_p(dir)
end
def cp(from, to)
if to.exist?
unless force?
log("Will not overwrite %s with %s", to.basename, from)
return
end
end
FileUtils.cp(from, to,
:noop => noop?,
:verbose => verbose?,
:preserve => true)
rescue ArgumentError => ex
debug(ex.message) unless ex.message =~ /^same file:/
end
def sh(*cmd)
debug(cmd.join(' '))
system(*cmd)
end
def debug(*args)
log(*args) if verbose?
end
def log(format, *args)
puts(format % args.flatten) unless quiet?
end
def target; @options.target.expand_path end
def proto; @options.proto.expand_path end
def color?; @options.color end
def force?; @options.force end
def noop?; @options.noop end
def quiet?; @options.quiet end
def verbose?; @options.verbose end
end
begin
op.parse!(ARGV)
rescue OptionParser::MissingArgument => ex
puts ex
exit
end
if ACTIONS.empty?
puts op
exit 1
end
if TARGETS.first == :proto
raku = Raku::ProtoPOV.new(OPTIONS)
else
raku = Raku::TargetPOV.new(OPTIONS)
end
action, *args = ACTIONS.shift
args = (args + ARGV).map{|a| Pathname(a) }
args.delete true
raku.send(action, *args)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment