cake 0.2.6 → 0.2.7
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.
- data/bin/cake +358 -31
- data/lib/bake.jar +0 -0
- data/lib/cake.jar +0 -0
- metadata +4 -4
data/bin/cake
CHANGED
@@ -1,20 +1,28 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# Save your fork, there's cake!"
|
3
3
|
require 'ftools'
|
4
|
+
require 'find'
|
4
5
|
require 'open-uri'
|
5
6
|
require 'rexml/document'
|
7
|
+
require 'socket'
|
8
|
+
require 'timeout'
|
9
|
+
require 'readline'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'pp'
|
6
12
|
|
7
|
-
|
8
|
-
$
|
9
|
-
$
|
13
|
+
file = File.readlink(__FILE__) rescue __FILE__
|
14
|
+
$cakedir = File.dirname(File.dirname(file))
|
15
|
+
$confdir = ".cake"
|
16
|
+
$repo = "http://clojars.org/repo/cake/cake"
|
17
|
+
File.makedirs($confdir)
|
10
18
|
|
11
|
-
def
|
19
|
+
def get_cake(version, dest)
|
12
20
|
jar = version =~ /(.*)-SNAPSHOT/ ? "cake-#{$1}-#{snapshot(version)}.jar" : "cake-#{version}.jar"
|
13
21
|
dest = File.expand_path(dest)
|
14
22
|
path = "#{dest}/#{jar}"
|
15
23
|
|
16
24
|
if not File.exists?(path)
|
17
|
-
|
25
|
+
log(:deps, "fetching cake libraries. this may take a moment...")
|
18
26
|
url = "#{$repo}/#{version}/#{jar}"
|
19
27
|
File.makedirs(dest)
|
20
28
|
open(url) do |jar|
|
@@ -27,16 +35,11 @@ def have_cake(version, dest)
|
|
27
35
|
end
|
28
36
|
path
|
29
37
|
rescue OpenURI::HTTPError => e
|
30
|
-
|
31
|
-
|
38
|
+
log(:deps, "unable to find cake version #{version} on clojars.")
|
39
|
+
log(:deps, "please check http://github.com/ninjudd/cake for latest install instructions.")
|
32
40
|
exit
|
33
41
|
end
|
34
42
|
|
35
|
-
def eat_cake(*args)
|
36
|
-
opts = %{ -d32 -cp #{$classpath} -Dbakepath="#{$bakepath}" }
|
37
|
-
system %{ java #{opts} clojure.main -e "(use 'cake)(-main)" /dev/null #{args.join(' ')} }
|
38
|
-
end
|
39
|
-
|
40
43
|
def current_version
|
41
44
|
open("#{$repo}/maven-metadata.xml") do |file|
|
42
45
|
doc = REXML::Document.new file
|
@@ -60,34 +63,358 @@ def extract(jar, file)
|
|
60
63
|
"#{dest}/#{file}"
|
61
64
|
end
|
62
65
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
+
def newer?(file1, file2)
|
67
|
+
not File.exists?(file2) or test(?>, file1, file2)
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_opt!(key, *vals)
|
71
|
+
($opts[key.to_sym] ||= []).concat vals
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_opts!
|
75
|
+
ARGV.unshift('default') if ARGV.empty? or ARGV.first[0,1] == '-'
|
76
|
+
$command = ARGV.shift.to_sym
|
77
|
+
$opts = {}
|
78
|
+
ARGV.each do |opt|
|
79
|
+
case opt
|
80
|
+
when /^-(\w*)$/ then $1.chars.each {|c| add_opt!(c, "")}
|
81
|
+
when /^--?([-\w]*)=([-,\w]+)$/ then add_opt!($1, *$2.split(','))
|
82
|
+
when /^--?([-\w]*)$/ then add_opt!($1, "")
|
83
|
+
else add_opt!($command, opt)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
$opts.freeze
|
87
|
+
end
|
88
|
+
parse_opts!
|
89
|
+
|
90
|
+
def debug?
|
91
|
+
ENV['CAKE_DEBUG'] or $opts[:d] or $opts[:debug]
|
92
|
+
end
|
93
|
+
|
94
|
+
def verbose?
|
95
|
+
debug? or $opts[:v] or $opts[:verbose]
|
96
|
+
end
|
97
|
+
|
98
|
+
def restart?
|
99
|
+
$opts[:r] or $opts[:restart] or [:stop, :restart].include?($command)
|
100
|
+
end
|
101
|
+
|
102
|
+
def admin_command?
|
103
|
+
[:start, :stop, :reload, :restart].include?($command)
|
104
|
+
end
|
105
|
+
|
106
|
+
def log(command, *message)
|
107
|
+
message.each do |line|
|
108
|
+
printf("%11s %s\n", "[#{command}]", line)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
class JVM
|
113
|
+
attr_reader :type, :classpath, :port, :pid, :pidfile, :start_time
|
114
|
+
|
115
|
+
def initialize(classpath)
|
116
|
+
@type = self.class.name.downcase
|
117
|
+
@classpath = classpath
|
118
|
+
@pidfile = "#{$confdir}/#{type}.pid"
|
119
|
+
@start_time = File.exists?(pidfile) ? File.mtime(pidfile) : Time.now
|
120
|
+
|
121
|
+
@pid, @port = IO.read(pidfile).map {|l| l.to_i}
|
122
|
+
Process.kill(0, @pid) # make sure pid is valid
|
123
|
+
|
124
|
+
rescue Errno::ESRCH, Errno::ENOENT => e
|
125
|
+
reset! # no pidfile or invalid pid
|
126
|
+
end
|
127
|
+
|
128
|
+
def running?
|
129
|
+
not pid.nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
def init
|
133
|
+
reload_stale_files if running?
|
134
|
+
start
|
135
|
+
end
|
136
|
+
|
137
|
+
def reload_stale_files
|
138
|
+
stale_files = files.select {|f| stale?(f)}
|
139
|
+
|
140
|
+
if stale_files.empty?
|
141
|
+
log(:reload, "no stale #{type} files found") if verbose? and admin_command?
|
142
|
+
else
|
143
|
+
log(:reload, "the following #{type} files have changed: #{stale_files.join(', ')}") if debug?
|
144
|
+
|
145
|
+
if stale_files.any? {|f| File.extname(f) != ".clj"}
|
146
|
+
log(:reload, "non-clojure #{type} files have changed, restarting") if verbose?
|
147
|
+
stop(:reload)
|
148
|
+
else
|
149
|
+
log(:reload, "clojure #{type} files have changed, reloading") if verbose?
|
150
|
+
with_socket(0) do |socket|
|
151
|
+
stale_files = stale_files.collect {|f| %{"#{f}"} }
|
152
|
+
socket.write ":reload [#{stale_files.join(" ")}]\n"
|
153
|
+
if socket.eof?
|
154
|
+
FileUtils.touch(pidfile)
|
155
|
+
@start_time = Time.now
|
156
|
+
else
|
157
|
+
inspect(socket) if debug?
|
158
|
+
log(:reload, "unable to reload all #{type} files, restarting") if verbose?
|
159
|
+
stop(:reload)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
MIN_PORT = 2**13
|
167
|
+
MAX_PORT = 2**16
|
168
|
+
|
169
|
+
def start
|
170
|
+
return if running?
|
171
|
+
@port = rand(MAX_PORT - MIN_PORT) + MIN_PORT
|
172
|
+
log(:start, "starting #{type} jvm on port #{port}") if debug?
|
173
|
+
@pid = daemon %{ java -d32 -cp #{classpath} clojure.main -e "(use '#{type})(start-server #{port})" /dev/null }
|
174
|
+
File.open(pidfile, 'w') {|f| f.write("#{pid}\n#{port}\n") }
|
175
|
+
log(:start, "#{type} jvm started") if verbose?
|
176
|
+
rescue Errno::EADDRNOTAVAIL => e
|
177
|
+
retry
|
178
|
+
end
|
179
|
+
|
180
|
+
def stop(mode = :stop)
|
181
|
+
with_socket(0) do |socket|
|
182
|
+
action = mode == :reload ? 'quit' : 'force-quit'
|
183
|
+
log(mode, "sending #{action} to #{type} jvm on port #{port}") if debug?
|
184
|
+
socket.write(":#{action}\n")
|
185
|
+
if socket.eof?
|
186
|
+
log(mode, "#{type} jvm stopped") if verbose?
|
187
|
+
reset!
|
188
|
+
else
|
189
|
+
inspect(socket) if debug?
|
190
|
+
if mode == :stop
|
191
|
+
log(mode, "error stopping #{type} jvm, try 'cake kill' or 'cake kill -9'")
|
192
|
+
else
|
193
|
+
log(mode, "warning: classes have changed but can't restart #{type} jvm with active connections")
|
194
|
+
log(mode, " close active connections or use 'cake stop' to force quit")
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end || (log(mode, "#{type} jvm not running") if verbose?)
|
198
|
+
end
|
199
|
+
|
200
|
+
def kill
|
201
|
+
Process.kill($opts[:"9"] ? "KILL" : "TERM", pid) if pid
|
202
|
+
end
|
203
|
+
|
204
|
+
def files
|
205
|
+
files = []
|
206
|
+
classpath.split(':').uniq.each do |path|
|
207
|
+
if path =~ /(.*)\/\*$/
|
208
|
+
files.concat Dir["#{path}.jar"] << "#{$1}/." # include the directory itself so deletions will be detected
|
209
|
+
else
|
210
|
+
Find.find(path) do |f|
|
211
|
+
files << f if File.exists?(f) and not File.directory?(f)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
files
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
def inspect(socket)
|
221
|
+
while line = socket.gets
|
222
|
+
puts line
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def reset!
|
227
|
+
File.unlink(pidfile) if File.exists?(pidfile)
|
228
|
+
@pid, @port = []
|
229
|
+
@start_time = Time.now
|
230
|
+
end
|
231
|
+
|
232
|
+
def stale?(file)
|
233
|
+
File.exists?(file) and File.mtime(file) > start_time
|
234
|
+
end
|
235
|
+
|
236
|
+
def daemon(cmd)
|
237
|
+
puts cmd if debug?
|
238
|
+
pid = fork do
|
239
|
+
Process.setsid
|
240
|
+
exec(cmd)
|
241
|
+
end
|
242
|
+
Process.detach(pid)
|
243
|
+
pid
|
244
|
+
end
|
245
|
+
|
246
|
+
def with_socket(retries = 5)
|
247
|
+
return unless port
|
248
|
+
socket = TCPSocket.new("localhost", port)
|
249
|
+
result = yield(socket)
|
250
|
+
result
|
251
|
+
rescue Errno::ECONNREFUSED => e
|
252
|
+
sleep 1
|
253
|
+
retry if (retries -= 1) >= 0
|
254
|
+
exit
|
255
|
+
ensure
|
256
|
+
socket.close if socket
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class Cake < JVM
|
261
|
+
attr_accessor :bakeport
|
262
|
+
|
263
|
+
def files
|
264
|
+
super.concat ["project.clj", "build.clj", ".cake/swank"]
|
265
|
+
end
|
266
|
+
|
267
|
+
def send_command(command, *args)
|
268
|
+
with_socket do |socket|
|
269
|
+
socket.write("(#{command} [#{args.join(' ')}] #{bakeport})\n")
|
270
|
+
while(line = socket.gets)
|
271
|
+
puts line
|
272
|
+
end
|
273
|
+
command
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class Bake < JVM
|
279
|
+
MARKER = rand.to_s
|
280
|
+
PROMPT = /^(.*)#{MARKER}$/
|
281
|
+
START_REPL = <<-END
|
282
|
+
(clojure.main/repl
|
283
|
+
:init #(in-ns 'user)
|
284
|
+
:prompt #(printf "%s=> #{MARKER}\n" (ns-name *ns*)))
|
285
|
+
END
|
286
|
+
|
287
|
+
def repl
|
288
|
+
load_history
|
289
|
+
loop do
|
290
|
+
with_socket do |socket|
|
291
|
+
socket.write START_REPL
|
292
|
+
socket.gets # burn extra prompt
|
293
|
+
|
294
|
+
while prompt = read_until_prompt(socket)
|
295
|
+
line = readline(prompt)
|
296
|
+
return unless line
|
297
|
+
socket.write(line + "\n")
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
ensure
|
302
|
+
save_history
|
303
|
+
end
|
304
|
+
|
305
|
+
private
|
306
|
+
|
307
|
+
HISTORY_NUM = 500
|
308
|
+
HISTORY_FILE = ".cake/history"
|
309
|
+
|
310
|
+
def load_history
|
311
|
+
open(HISTORY_FILE) do |file|
|
312
|
+
file.each {|line| Readline::HISTORY << line.chomp}
|
313
|
+
end if File.exists?(HISTORY_FILE)
|
314
|
+
end
|
315
|
+
|
316
|
+
def save_history
|
317
|
+
open(HISTORY_FILE, 'w') do |file|
|
318
|
+
history = Readline::HISTORY.to_a
|
319
|
+
file.puts(history[-HISTORY_NUM..-1] || history)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def read_until_prompt(socket)
|
324
|
+
while line = socket.gets
|
325
|
+
return $1 if line =~ PROMPT
|
326
|
+
puts line
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def complete?(input)
|
331
|
+
return true if input.empty?
|
332
|
+
with_socket do |socket|
|
333
|
+
socket.write(":validate #{input.join("\n").strip}")
|
334
|
+
socket.close_write # send eof
|
335
|
+
socket.gets != "incomplete\n"
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
def readline(initial_prompt)
|
340
|
+
input = []
|
341
|
+
prompt = initial_prompt.clone
|
342
|
+
while line = Readline.readline(prompt)
|
343
|
+
input << line
|
344
|
+
if complete?(input)
|
345
|
+
Readline::HISTORY.push(input.join(' ').strip)
|
346
|
+
return input.join("\n").strip
|
347
|
+
end
|
348
|
+
prompt[-2] = ?*
|
349
|
+
end
|
350
|
+
rescue Interrupt => e
|
351
|
+
return nil if input.empty?
|
352
|
+
Readline::HISTORY.push(input)
|
353
|
+
retry
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
# Bootstrap cake dependencies.
|
358
|
+
lib = "#{$cakedir}/lib"
|
359
|
+
if File.exists?("#{$cakedir}/.gitignore")
|
66
360
|
if Dir["#{lib}/*.jar"].empty?
|
67
361
|
# In a new git checkout, need to fetch dependencies.
|
68
|
-
version = IO.read("#{$
|
69
|
-
|
362
|
+
version = IO.read("#{$cakedir}/project.clj").first.match(/defproject cake \"(.*)\"/)[1]
|
363
|
+
get_cake(version, lib)
|
70
364
|
end
|
71
|
-
|
72
|
-
|
365
|
+
cakepath = "#{$cakedir}/src:#{lib}/*"
|
366
|
+
bakepath = "#{$cakedir}/bake"
|
73
367
|
else
|
74
|
-
|
75
|
-
|
76
|
-
if File.exists?(
|
368
|
+
cakejar = "#{lib}/cake.jar"
|
369
|
+
bakejar = "#{lib}/bake.jar"
|
370
|
+
if File.exists?(cakejar) and File.exists?(bakejar)
|
77
371
|
# Inside a gem install.
|
78
|
-
|
79
|
-
|
372
|
+
cakepath = cakejar
|
373
|
+
bakepath = bakejar
|
80
374
|
else
|
81
375
|
# Naked script.
|
82
|
-
version
|
83
|
-
dest
|
84
|
-
|
85
|
-
|
376
|
+
version = current_version
|
377
|
+
dest = "~/.m2/repository/cake/cake/#{version}"
|
378
|
+
cakepath = get_cake(version, dest)
|
379
|
+
bakepath = extract(classpath, "bake-#{version}.jar")
|
86
380
|
end
|
87
381
|
end
|
88
382
|
|
89
|
-
|
90
|
-
|
383
|
+
pwd = Dir.getwd
|
384
|
+
srcpath = "#{pwd}/src:#{pwd}/src/clj"
|
385
|
+
|
386
|
+
cake = Cake.new("#{cakepath}:#{srcpath}:#{pwd}/lib/dev/*")
|
387
|
+
bake = Bake.new("#{bakepath}:#{srcpath}:#{pwd}/classes:#{pwd}/test:#{pwd}/lib/*:#{pwd}/lib/dev/*")
|
388
|
+
|
389
|
+
if $command == :kill
|
390
|
+
cake.kill
|
391
|
+
bake.kill
|
392
|
+
exit
|
393
|
+
elsif restart?
|
394
|
+
cake.stop
|
395
|
+
bake.stop
|
396
|
+
exit if $command == :stop
|
91
397
|
end
|
92
398
|
|
93
|
-
|
399
|
+
cake.init
|
400
|
+
if not [:deps, :clean].include?($command) and File.exists?('project.clj')
|
401
|
+
if newer?('project.clj', 'pom.xml')
|
402
|
+
deps = cake.send_command(:deps)
|
403
|
+
elsif File.exist?('.cake/swank')
|
404
|
+
deps = cake.send_command(:"swank-deps")
|
405
|
+
end
|
406
|
+
|
407
|
+
bake.init
|
408
|
+
cake.init if deps # must check if dev dependencies have changed
|
409
|
+
end
|
410
|
+
|
411
|
+
if $command == :repl
|
412
|
+
if File.exists?('project.clj')
|
413
|
+
bake.repl
|
414
|
+
else
|
415
|
+
log(:repl, "cannot start repl without project.clj")
|
416
|
+
end
|
417
|
+
elsif not [:start, :reload, :restart].include?($command)
|
418
|
+
cake.bakeport = bake.port
|
419
|
+
cake.send_command($command, ARGV)
|
420
|
+
end
|
data/lib/bake.jar
CHANGED
Binary file
|
data/lib/cake.jar
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 25
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 7
|
10
|
+
version: 0.2.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Justin Balthrop
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-06-
|
19
|
+
date: 2010-06-22 00:00:00 -07:00
|
20
20
|
default_executable: cake
|
21
21
|
dependencies: []
|
22
22
|
|