manveru (owner)

Revisions

gist: 90392 Download_button fork
public
Description:
Raku is a tiny rake-task manager
Public Clone URL: git://gist.github.com/90392.git
Embed All Files: show embed
raku #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/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)