bake.clj 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/bake.clj.gemspec +14 -0
  2. data/bin/bake +600 -0
  3. data/lib/bake.jar +0 -0
  4. data/lib/cake.jar +0 -0
  5. metadata +71 -0
data/bake.clj.gemspec ADDED
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bake.clj'
3
+ s.rubyforge_project = 'bake.clj'
4
+ s.version = ENV['BAKE_VERSION']
5
+ s.authors = ['Justin Balthrop', 'Lance Bradley']
6
+ s.date = Time.now
7
+ s.default_executable = 'bake'
8
+ s.summary = 'Build tools got you down? Get baked!'
9
+ s.description = 'Add equal parts clojure, ruby, love, and tenderness. Bake at 350 for 1 minute. Delicious.'
10
+ s.email = 'code@justinbalthrop.com'
11
+ s.executables = ['bake']
12
+ s.files = ['bake.clj.gemspec', 'bin/bake', 'lib/bake.jar', 'lib/cake.jar']
13
+ s.homepage = 'http://github.com/ninjudd/bake'
14
+ end
data/bin/bake ADDED
@@ -0,0 +1,600 @@
1
+ #!/usr/bin/env ruby
2
+ # Save your fork, there's bake!"
3
+ require 'ftools'
4
+ require 'find'
5
+ require 'open-uri'
6
+ require 'rexml/document'
7
+ require 'socket'
8
+ require 'timeout'
9
+ require 'fileutils'
10
+
11
+ begin
12
+ require 'readline'
13
+ rescue LoadError => e
14
+ module Readline
15
+ HISTORY = []
16
+ attr_accessor :basic_word_break_characters, :completion_proc
17
+ def readline(prompt)
18
+ $stdout.print prompt
19
+ $stdout.flush
20
+ $stdin.gets
21
+ end
22
+ extend Readline
23
+ end
24
+ end
25
+
26
+ def project_dir(dir)
27
+ while dir != "/"
28
+ return dir if [".bake", "project.clj", "build.clj"].any? {|file| File.exists?("#{dir}/#{file}")}
29
+ dir = File.dirname(dir)
30
+ end
31
+ File.expand_path("~")
32
+ end
33
+
34
+ PATH_SEP = ':'
35
+ file = File.readlink(__FILE__) rescue __FILE__
36
+ $cakedir = project_dir(Dir.getwd)
37
+ $bakedir = File.dirname(File.dirname(file))
38
+ $repo = "http://clojars.org/repo/bake/bake"
39
+ $confdir = ".bake"
40
+ Dir.chdir($cakedir)
41
+ File.makedirs($confdir)
42
+
43
+ def get_bake(version, dest = nil)
44
+ jar = version =~ /(.*)-SNAPSHOT/ ? "bake-#{$1}-#{snapshot(version)}.jar" : "bake-#{version}.jar"
45
+ repo = File.expand_path("~/.m2/repository/bake/bake/#{version}")
46
+ path = "#{repo}/#{jar}"
47
+
48
+ if not File.exists?(path)
49
+ log(:deps, "fetching bake libraries. this may take a moment...")
50
+ url = "#{$repo}/#{version}/#{jar}"
51
+ File.makedirs(repo)
52
+ open(url) do |jarfile|
53
+ open(path, "wb") do |file|
54
+ while (buf = jarfile.read(8192))
55
+ file.write buf
56
+ end
57
+ end
58
+ end
59
+ end
60
+ return path unless dest
61
+
62
+ dest = File.expand_path(dest)
63
+ File.makedirs(dest)
64
+ File.copy(path, dest)
65
+ "#{dest}/#{jar}"
66
+ rescue OpenURI::HTTPError => e
67
+ log(:deps, "unable to find bake version #{version} on clojars.")
68
+ log(:deps, "please check http://github.com/ninjudd/bake for latest install instructions.")
69
+ exit
70
+ end
71
+
72
+ def current_version
73
+ open("#{$repo}/maven-metadata.xml") do |file|
74
+ doc = REXML::Document.new file
75
+ doc.elements['metadata'].elements['versioning'].elements['versions'].elements.to_a('version').last.get_text.to_s
76
+ end
77
+ end
78
+
79
+ def snapshot(version)
80
+ open("#{$repo}/#{version}/maven-metadata.xml") do |file|
81
+ doc = REXML::Document.new file
82
+ snapshot = doc.elements['metadata'].elements['versioning'].elements['snapshot'].elements
83
+ timestamp = snapshot['timestamp'].get_text
84
+ build_num = snapshot['buildNumber'].get_text
85
+ "#{timestamp}-#{build_num}"
86
+ end
87
+ end
88
+
89
+ def extract(jar, file, dest = File.dirname(jar))
90
+ if not File.exists?("#{dest}/#{file}")
91
+ log(:deps, "extracting #{file} from #{jar}") if verbose?
92
+ ret = system %{ jar xf #{jar} #{file} }
93
+ raise "cannot find jar command" unless ret
94
+ File.makedirs(dest)
95
+ File.move(file, dest)
96
+ end
97
+ "#{dest}/#{file}"
98
+ end
99
+
100
+ def newer?(file1, file2)
101
+ return false unless File.exists?(file1)
102
+ not File.exists?(file2) or test(?>, file1, file2)
103
+ end
104
+
105
+ def add_opt!(key, *vals)
106
+ ($opts[key.to_sym] ||= []).concat vals
107
+ end
108
+
109
+ def parse_opts!
110
+ ARGV.unshift('default') if ARGV.empty? or ARGV.first[0,1] == '-'
111
+ $command = ARGV.shift.to_sym
112
+ $opts = {}
113
+ ARGV.each do |opt|
114
+ case opt
115
+ when /^-(\w*)$/ then $1.split('').each {|c| add_opt!(c, '')}
116
+ when /^--?([-\w]*)=([-,\w]+)$/ then add_opt!($1, *$2.split(','))
117
+ when /^--?([-\w]*)$/ then add_opt!($1, "")
118
+ else add_opt!($command, opt)
119
+ end
120
+ end
121
+ $opts.freeze
122
+ end
123
+ parse_opts!
124
+
125
+ def debug?
126
+ ENV['BAKE_DEBUG'] or $opts[:d] or $opts[:debug]
127
+ end
128
+
129
+ def verbose?
130
+ debug? or $opts[:v] or $opts[:verbose]
131
+ end
132
+
133
+ def config_updated?
134
+ newer?(".bake/config", ".bake/bake.pid") or (File.exists?(".bake/cake.pid") and newer?(".bake/config", ".bake/cake.pid"))
135
+ end
136
+
137
+ def restart?
138
+ $opts[:r] or $opts[:restart] or [:stop, :restart].include?($command)
139
+ end
140
+
141
+ def admin_command?
142
+ [:start, :stop, :reload, :restart].include?($command)
143
+ end
144
+
145
+ def log(command, *message)
146
+ message.each do |line|
147
+ printf("%11s %s\n", "[#{command}]", line)
148
+ end
149
+ end
150
+
151
+ class Config < Hash
152
+ def initialize(path)
153
+ File.open(path, 'r') do |file|
154
+ file.each do |line|
155
+ next if ['#', '!'].include?(line[0,1])
156
+ key, value = line.split('=', 2)
157
+ next unless key and value
158
+ self[key.strip] = value.strip
159
+ end
160
+ end if File.exists?(path)
161
+ end
162
+
163
+ def [](*keys)
164
+ if keys.first.kind_of?(Symbol)
165
+ key = keys.join('.') + '.'
166
+ clone.delete_if {|k,v| not k.index(key) == 0}
167
+ else
168
+ super
169
+ end
170
+ end
171
+ end
172
+
173
+ def config
174
+ @config ||= Config.new(".bake/config")
175
+ end
176
+
177
+ class JVM
178
+ attr_reader :type, :classpath, :libpath, :port, :pid, :pidfile, :load_time
179
+
180
+ def initialize(classpath, libpath)
181
+ @type = self.class.name.downcase
182
+ @classpath = make_path(classpath)
183
+ @libpath = make_path(libpath)
184
+ @pidfile = "#{$confdir}/#{type}.pid"
185
+ @load_time = File.exists?(pidfile) ? File.mtime(pidfile) : Time.now
186
+ refresh
187
+ rescue Errno::ENOENT, Errno::ESRCH, Errno::ECONNREFUSED => e
188
+ log(:start, "defunct #{type} jvm") if debug? and e.kind_of?(Errno::ECONNREFUSED)
189
+ reset! # no pidfile or invalid pid or connection refused
190
+ end
191
+
192
+ def running?
193
+ not pid.nil?
194
+ end
195
+
196
+ def enabled?
197
+ true
198
+ end
199
+
200
+ def init
201
+ stale = reload_stale_files if enabled? and running?
202
+ start
203
+ stale
204
+ end
205
+
206
+ def refresh
207
+ @pid, @port = IO.read(pidfile).map {|l| l.to_i}
208
+ Process.kill(0, @pid) # make sure pid is valid
209
+ TCPSocket.new("localhost", @port) if @port # make sure jvm is running on port
210
+ end
211
+
212
+ def reload
213
+ refresh
214
+ init
215
+ end
216
+
217
+ def reload_stale_files
218
+ stale_files = files.select {|f| stale?(f)}
219
+
220
+ if stale_files.empty?
221
+ log(:reload, "no stale #{type} files found") if verbose? and admin_command?
222
+ false
223
+ else
224
+ log(:reload, "the following #{type} files have changed: #{stale_files.join(', ')}") if debug?
225
+
226
+ if stale_files.any? {|f| File.extname(f) != ".clj"}
227
+ log(:reload, "non-clojure #{type} files have changed, restarting") if verbose?
228
+ stop(:reload)
229
+ else
230
+ log(:reload, "clojure #{type} files have changed, reloading") if verbose?
231
+ with_socket(0) do |socket|
232
+ stale_files = stale_files.collect {|f| %{"#{f}"} }
233
+ socket.write ":reload [#{stale_files.join(" ")}]\n"
234
+ if socket.eof?
235
+ FileUtils.touch(pidfile)
236
+ @load_time = Time.now
237
+ else
238
+ inspect(socket) if debug?
239
+ log(:reload, "unable to reload all #{type} files, restarting") if verbose?
240
+ stop(:reload)
241
+ end
242
+ end
243
+ end
244
+ true
245
+ end
246
+ end
247
+
248
+ def java_opts
249
+ opts = "-cp #{classpath} -Djava.library.path=#{libpath}"
250
+ opts << " -Djava.home=#{ENV['JAVA_HOME']} -Djava.ext.dirs=#{ENV['JAVA_HOME']}/lib" if ENV['JAVA_HOME']
251
+ opts
252
+ end
253
+
254
+ MIN_PORT = 2**13
255
+ MAX_PORT = 2**16
256
+
257
+ def start
258
+ return unless enabled?
259
+ if running?
260
+ log(:start, "#{type} jvm already running") if $command == :start
261
+ return
262
+ else
263
+ log(:start, "starting #{type} jvm") if verbose? or $command == :start
264
+ @port = rand(MAX_PORT - MIN_PORT) + MIN_PORT
265
+ @pid = daemon %{ java -Dbake.project=#{$cakedir} #{java_opts} clojure.main -e "(use '#{type})(start-server #{port})" /dev/null }
266
+ File.open(pidfile, 'w') {|f| f.write("#{pid}\n#{port}\n") }
267
+ end
268
+ rescue Errno::EADDRNOTAVAIL => e
269
+ retry
270
+ end
271
+
272
+ def stop(mode = :stop)
273
+ with_socket(0) do |socket|
274
+ action = mode == :reload ? 'quit' : 'force-quit'
275
+ log(mode, "sending #{action} to #{type} jvm on port #{port}") if debug?
276
+ socket.write(":#{action}\n")
277
+ if socket.eof?
278
+ log(mode, "#{type} jvm stopped") if restart?
279
+ reset!
280
+ else
281
+ inspect(socket) if debug?
282
+ if mode == :stop
283
+ log(mode, "error stopping #{type} jvm, try 'bake kill' or 'bake kill -9'")
284
+ else
285
+ log(mode, "warning: classes have changed but can't restart #{type} jvm with active connections")
286
+ log(mode, " close active connections or use 'bake stop' to force quit")
287
+ end
288
+ end
289
+ end || (log(mode, "#{type} jvm not running") if $command == :stop)
290
+ end
291
+
292
+ def kill
293
+ Process.kill($opts[:"9"] ? "KILL" : "TERM", pid) if pid
294
+ end
295
+
296
+ def files
297
+ files = ["project.clj"]
298
+ classpath.split(PATH_SEP).uniq.each do |path|
299
+ if path =~ /(.*)\/\*$/
300
+ files.concat Dir["#{path}.jar"] << "#{$1}/." # include the directory itself so deletions will be detected
301
+ else
302
+ Find.find(path) do |f|
303
+ Find.prune if f == "#{$cakedir}/src/jvm"
304
+ files << f if File.exists?(f) and not File.directory?(f)
305
+ end
306
+ end
307
+ end
308
+ files
309
+ end
310
+
311
+ def ping
312
+ return unless enabled?
313
+ with_socket(10) do |socket|
314
+ socket.write ":ping\n"
315
+ log($command, "#{type} jvm not running") unless socket.gets == "pong\n"
316
+ end
317
+ end
318
+
319
+ REPL_PROMPT = "REPL_PROMPT__#{rand}"
320
+ def repl
321
+ load_history
322
+ loop do
323
+ with_socket do |socket|
324
+ socket.write %{:repl "#{REPL_PROMPT}"}
325
+ while @ns = read_until_prompt(socket)
326
+ line = readline
327
+ return unless line
328
+ socket.write(line + "\n")
329
+ end
330
+ end
331
+ end
332
+ ensure
333
+ save_history
334
+ end
335
+
336
+ private
337
+
338
+ def make_path(paths)
339
+ paths.flatten.compact.collect do |path|
340
+ path[0,1] == '/' ? path : "#{$cakedir}/#{path}"
341
+ end.join(PATH_SEP)
342
+ end
343
+
344
+ def inspect(socket)
345
+ while line = socket.gets
346
+ puts line
347
+ end
348
+ end
349
+
350
+ def reset!
351
+ File.unlink(pidfile) if File.exists?(pidfile)
352
+ @pid, @port = []
353
+ @load_time = Time.now
354
+ end
355
+
356
+ def stale?(file)
357
+ File.exists?(file) and File.mtime(file) > load_time
358
+ end
359
+
360
+ def daemon(cmd)
361
+ puts cmd if debug?
362
+ pid = fork do
363
+ Process.setsid
364
+ exec(cmd)
365
+ end
366
+ Process.detach(pid)
367
+ pid
368
+ end
369
+
370
+ def with_socket(retries = 10)
371
+ return unless port
372
+ socket = TCPSocket.new("localhost", port)
373
+ result = yield(socket)
374
+ result
375
+ rescue Errno::ECONNREFUSED => e
376
+ sleep 1
377
+ retry if (retries -= 1) >= 0
378
+ exit
379
+ ensure
380
+ socket.close if socket
381
+ end
382
+
383
+ HISTORY_NUM = 500
384
+ HISTORY_FILE = ".bake/history"
385
+ def load_history
386
+ open(HISTORY_FILE) do |file|
387
+ file.each {|line| Readline::HISTORY << line.chomp}
388
+ end if File.exists?(HISTORY_FILE)
389
+ end
390
+
391
+ def save_history
392
+ open(HISTORY_FILE, 'w') do |file|
393
+ history = Readline::HISTORY.to_a
394
+ file.puts(history[-HISTORY_NUM..-1] || history)
395
+ end
396
+ end
397
+
398
+ def read_until_prompt(socket)
399
+ while line = socket.gets
400
+ return $1 if line =~ /^#{REPL_PROMPT}(.*)$/
401
+ puts line
402
+ end
403
+ end
404
+
405
+ def complete?(input)
406
+ return true if input.empty?
407
+ with_socket do |socket|
408
+ socket.write(":validate #{input.join("\n").strip}")
409
+ socket.close_write # send eof
410
+ socket.gets != "incomplete\n"
411
+ end
412
+ end
413
+
414
+ Readline.basic_word_break_characters = " \t\n\"'`~@;#&{}()[]"
415
+ def readline
416
+ input = []
417
+ prompt = "#{@ns}=> "
418
+ Readline.completion_proc = method(:completions)
419
+ while line = Readline.readline(prompt)
420
+ input << line
421
+ if complete?(input)
422
+ Readline::HISTORY.push(input.join(' ').strip)
423
+ return input.join("\n").strip
424
+ end
425
+ prompt[-2] = ?*
426
+ end
427
+ rescue Interrupt => e
428
+ return nil if input.empty?
429
+ Readline::HISTORY.push(input)
430
+ retry
431
+ end
432
+
433
+ def completions(prefix)
434
+ return [] if prefix.empty?
435
+ with_socket do |socket|
436
+ socket.write(":completions [\"#{prefix}\" #{@ns}]\n")
437
+ completions = []
438
+ while line = socket.gets
439
+ completions << line.chomp
440
+ end
441
+ completions
442
+ end
443
+ end
444
+ end
445
+
446
+ class Bake < JVM
447
+ attr_accessor :cakeport
448
+
449
+ READLINE = "READLINE__#{rand}"
450
+ def send_command(command, args = [])
451
+ with_socket do |socket|
452
+ args = args.collect{|arg| '"' + arg.gsub('"', '\"').gsub("\n", "\\n") + '"'}
453
+ cmd = %{(#{command} [#{args.join(' ')}] #{cakeport}) "#{READLINE}"}
454
+ log(command, "sending: " + cmd) if debug?
455
+ socket.write(cmd)
456
+ while (line = socket.gets)
457
+ if line =~ /^#{READLINE}(.*)$/
458
+ socket.write(prompt($1))
459
+ elsif line =~ /^@#{READLINE}(.*)$/
460
+ socket.write(prompt($1, :echo => false))
461
+ else
462
+ puts line
463
+ end
464
+ end
465
+ end
466
+ end
467
+
468
+ def files
469
+ super.concat ["build.clj", ".bake/swank"]
470
+ end
471
+
472
+ def java_opts
473
+ [ENV['BAKE_JAVA_OPTS'], config['bake.java_opts'], super].compact.join(' ')
474
+ end
475
+
476
+ private
477
+
478
+ def prompt(prompt, opts = {})
479
+ if opts[:echo] == false
480
+ echo_off = system("stty -echo 2&> /dev/null")
481
+ prompt << " (WARNING, input will be visible on console!)" unless echo_off
482
+ end
483
+ input = Readline.readline(prompt + ": ") || ''
484
+ input + "\n"
485
+ ensure
486
+ if echo_off
487
+ system("stty echo 2&> /dev/null")
488
+ puts
489
+ end
490
+ end
491
+ end
492
+
493
+ class Cake < JVM
494
+ def java_opts
495
+ [ENV['JAVA_OPTS'], config['project.java_opts'], super].compact.join(' ')
496
+ end
497
+
498
+ def enabled?
499
+ Dir["lib/*.jar"].any?
500
+ end
501
+ end
502
+
503
+ # Bootstrap bake dependencies.
504
+ lib = "#{$bakedir}/lib"
505
+ if File.exists?("#{$bakedir}/.gitignore")
506
+ if Dir["#{lib}/*.jar"].empty? or Dir["#{lib}/dev/*.jar"].empty?
507
+ # In a new git checkout, need to fetch dependencies.
508
+ version = IO.read("#{$bakedir}/project.clj").split("\n").first.match(/defproject bake \"(.*)\"/)[1]
509
+ bakejar = get_bake(version, lib)
510
+ extract(bakejar, "cake-#{version}.jar", "#{lib}/dev")
511
+ end
512
+
513
+ bakepath = ["#{$bakedir}/src", "#{lib}/*:#{lib}/dev/*"].join(PATH_SEP)
514
+ cakepath = ["#{$bakedir}/cake", "#{lib}/dev/*"].join(PATH_SEP)
515
+ else
516
+ bakejar = "#{lib}/bake.jar"
517
+ cakejar = "#{lib}/cake.jar"
518
+ if File.exists?(bakejar) and File.exists?(cakejar)
519
+ # Inside a gem install.
520
+ bakepath = bakejar
521
+ cakepath = cakejar
522
+ else
523
+ # Naked script.
524
+ version = current_version
525
+ bakepath = get_bake(version)
526
+ cakepath = extract(bakepath, "cake-#{version}.jar")
527
+ end
528
+ end
529
+
530
+ bake = Bake.new(
531
+ [bakepath, "src", "src/clj", config['bake.claspath'], "lib/dev/*"],
532
+ [config['bake.library.path'], "lib/dev/native"]
533
+ )
534
+ cake = Cake.new(
535
+ [cakepath, "src", "src/clj", "classes", "test", config['project.classpath'], "lib/*", "lib/dev/*"],
536
+ [config['project.library.path'], "lib/native", "lib/dev/native"]
537
+ )
538
+
539
+ if $command == :kill
540
+ if $opts[:all]
541
+ `jps -v | grep bake.project`.split("\n").each do |line|
542
+ pid = line.split(' ').first.to_i
543
+ Process.kill($opts[:"9"] ? "KILL" : "TERM", pid)
544
+ end
545
+ else
546
+ bake.kill
547
+ cake.kill
548
+ end
549
+ exit
550
+ elsif $command == :ps
551
+ puts `jps -v | grep bake.project`.sort.reverse
552
+ exit
553
+ elsif restart? or config_updated?
554
+ bake.stop
555
+ cake.stop
556
+ exit if $command == :stop
557
+ end
558
+
559
+ bake.init
560
+ if not [:deps, :clean].include?($command) and File.exists?('project.clj')
561
+ if newer?('project.clj', 'pom.xml')
562
+ bake.send_command(:deps)
563
+ bake.init
564
+ elsif File.exist?('.bake/swank')
565
+ bake.send_command(:"swank-deps")
566
+ bake.init
567
+ end
568
+
569
+ cake.init
570
+ end
571
+
572
+ if $command == :repl
573
+ if File.exists?('project.clj') and not $opts[:bake]
574
+ cake.repl
575
+ else
576
+ bake.repl
577
+ end
578
+ elsif [:start, :reload, :restart].include?($command)
579
+ if $opts[:l] or $opts[:log]
580
+ system("tail -f .bake/cake.log")
581
+ else
582
+ bake.ping
583
+ cake.ping
584
+ end
585
+ else
586
+ bake.cakeport = cake.port
587
+ if $command == :test and $opts[:auto]
588
+ interval = $opts[:auto].last.to_i
589
+ interval = config['test.auto.interval'].to_i if config['test.auto.interval'] || 1 if interval == 0
590
+ run_tests = true
591
+ while true
592
+ bake.send_command($command, ARGV) if run_tests
593
+ run_tests = cake.reload
594
+ bake.reload
595
+ sleep(interval)
596
+ end
597
+ else
598
+ bake.send_command($command, ARGV)
599
+ end
600
+ end
data/lib/bake.jar ADDED
Binary file
data/lib/cake.jar ADDED
Binary file
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bake.clj
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 1
10
+ version: 0.3.1
11
+ platform: ruby
12
+ authors:
13
+ - Justin Balthrop
14
+ - Lance Bradley
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-07-23 00:00:00 -07:00
20
+ default_executable: bake
21
+ dependencies: []
22
+
23
+ description: Add equal parts clojure, ruby, love, and tenderness. Bake at 350 for 1 minute. Delicious.
24
+ email: code@justinbalthrop.com
25
+ executables:
26
+ - bake
27
+ extensions: []
28
+
29
+ extra_rdoc_files: []
30
+
31
+ files:
32
+ - bake.clj.gemspec
33
+ - bin/bake
34
+ - lib/bake.jar
35
+ - lib/cake.jar
36
+ has_rdoc: true
37
+ homepage: http://github.com/ninjudd/bake
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ hash: 3
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project: bake.clj
66
+ rubygems_version: 1.3.7
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Build tools got you down? Get baked!
70
+ test_files: []
71
+