spring 1.0.0 → 1.1.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +2 -0
- data/CHANGELOG.md +27 -0
- data/README.md +114 -45
- data/bin/spring +1 -0
- data/lib/spring/application/boot.rb +16 -0
- data/lib/spring/application.rb +122 -60
- data/lib/spring/application_manager.rb +51 -40
- data/lib/spring/binstub.rb +13 -0
- data/lib/spring/boot.rb +8 -0
- data/lib/spring/client/binstub.rb +150 -39
- data/lib/spring/client/help.rb +4 -12
- data/lib/spring/client/rails.rb +1 -3
- data/lib/spring/client/version.rb +11 -0
- data/lib/spring/client.rb +8 -5
- data/lib/spring/command_wrapper.rb +86 -0
- data/lib/spring/commands/rails.rb +1 -2
- data/lib/spring/commands/rake.rb +0 -4
- data/lib/spring/commands.rb +3 -2
- data/lib/spring/configuration.rb +11 -2
- data/lib/spring/env.rb +10 -9
- data/lib/spring/server.rb +8 -36
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher/abstract.rb +7 -8
- data/spring.gemspec +1 -1
- data/test/acceptance/app_test.rb +178 -355
- data/test/acceptance/helper.rb +329 -0
- data/test/unit/client/version_test.rb +14 -0
- data/test/unit/watcher_test.rb +12 -8
- metadata +13 -3
|
@@ -1,20 +1,16 @@
|
|
|
1
|
-
require "socket"
|
|
2
|
-
require "thread"
|
|
3
|
-
require "spring/application"
|
|
4
|
-
|
|
5
1
|
module Spring
|
|
6
2
|
class ApplicationManager
|
|
7
|
-
attr_reader :pid, :child, :app_env, :spring_env, :
|
|
3
|
+
attr_reader :pid, :child, :app_env, :spring_env, :status
|
|
8
4
|
|
|
9
|
-
def initialize(
|
|
10
|
-
@server = server
|
|
5
|
+
def initialize(app_env)
|
|
11
6
|
@app_env = app_env
|
|
12
7
|
@spring_env = Env.new
|
|
13
8
|
@mutex = Mutex.new
|
|
9
|
+
@state = :running
|
|
14
10
|
end
|
|
15
11
|
|
|
16
12
|
def log(message)
|
|
17
|
-
|
|
13
|
+
spring_env.log "[application_manager:#{app_env}] #{message}"
|
|
18
14
|
end
|
|
19
15
|
|
|
20
16
|
# We're not using @mutex.synchronize to avoid the weird "<internal:prelude>:10"
|
|
@@ -28,10 +24,10 @@ module Spring
|
|
|
28
24
|
|
|
29
25
|
def start
|
|
30
26
|
start_child
|
|
31
|
-
start_wait_thread
|
|
32
27
|
end
|
|
33
28
|
|
|
34
29
|
def restart
|
|
30
|
+
return if @state == :stopping
|
|
35
31
|
start_child(true)
|
|
36
32
|
end
|
|
37
33
|
|
|
@@ -63,13 +59,15 @@ module Spring
|
|
|
63
59
|
def run(client)
|
|
64
60
|
with_child do
|
|
65
61
|
child.send_io client
|
|
66
|
-
child.gets
|
|
62
|
+
child.gets or raise Errno::EPIPE
|
|
67
63
|
end
|
|
68
64
|
|
|
69
|
-
pid = child.gets
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
pid = child.gets.to_i
|
|
66
|
+
|
|
67
|
+
unless pid.zero?
|
|
68
|
+
log "got worker pid #{pid}"
|
|
69
|
+
pid
|
|
70
|
+
end
|
|
73
71
|
rescue Errno::ECONNRESET, Errno::EPIPE => e
|
|
74
72
|
log "#{e} while reading from child; returning no pid"
|
|
75
73
|
nil
|
|
@@ -78,45 +76,58 @@ module Spring
|
|
|
78
76
|
end
|
|
79
77
|
|
|
80
78
|
def stop
|
|
81
|
-
|
|
79
|
+
@state = :stopping
|
|
80
|
+
|
|
81
|
+
if pid
|
|
82
|
+
Process.kill('TERM', pid)
|
|
83
|
+
Process.wait(pid)
|
|
84
|
+
end
|
|
82
85
|
end
|
|
83
86
|
|
|
84
87
|
private
|
|
85
88
|
|
|
86
89
|
def start_child(preload = false)
|
|
87
|
-
server.application_starting
|
|
88
|
-
|
|
89
90
|
@child, child_socket = UNIXSocket.pair
|
|
90
|
-
@pid = fork {
|
|
91
|
-
(ObjectSpace.each_object(IO).to_a - [STDOUT, STDERR, STDIN, child_socket])
|
|
92
|
-
.reject(&:closed?)
|
|
93
|
-
.each(&:close)
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
92
|
+
Bundler.with_clean_env do
|
|
93
|
+
@pid = Process.spawn(
|
|
94
|
+
{
|
|
95
|
+
"RAILS_ENV" => app_env,
|
|
96
|
+
"RACK_ENV" => app_env,
|
|
97
|
+
"SPRING_ORIGINAL_ENV" => JSON.dump(Spring::ORIGINAL_ENV),
|
|
98
|
+
"SPRING_PRELOAD" => preload ? "1" : "0"
|
|
99
|
+
},
|
|
100
|
+
"ruby",
|
|
101
|
+
"-I", File.expand_path("../..", __FILE__),
|
|
102
|
+
"-e", "require 'spring/application/boot'",
|
|
103
|
+
3 => child_socket
|
|
104
|
+
)
|
|
105
|
+
end
|
|
100
106
|
|
|
101
|
-
|
|
102
|
-
app.preload if preload
|
|
103
|
-
app.run
|
|
104
|
-
}
|
|
107
|
+
start_wait_thread(pid, child) if child.gets
|
|
105
108
|
child_socket.close
|
|
106
109
|
end
|
|
107
110
|
|
|
108
|
-
def start_wait_thread
|
|
109
|
-
|
|
110
|
-
Thread.current.abort_on_exception = true
|
|
111
|
+
def start_wait_thread(pid, child)
|
|
112
|
+
Process.detach(pid)
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
Thread.new {
|
|
115
|
+
# The recv can raise an ECONNRESET, killing the thread, but that's ok
|
|
116
|
+
# as if it does we're no longer interested in the child
|
|
117
|
+
loop do
|
|
118
|
+
IO.select([child])
|
|
119
|
+
break if child.recv(1, Socket::MSG_PEEK).empty?
|
|
120
|
+
sleep 0.01
|
|
119
121
|
end
|
|
122
|
+
|
|
123
|
+
log "child #{pid} shutdown"
|
|
124
|
+
|
|
125
|
+
synchronize {
|
|
126
|
+
if @pid == pid
|
|
127
|
+
@pid = nil
|
|
128
|
+
restart
|
|
129
|
+
end
|
|
130
|
+
}
|
|
120
131
|
}
|
|
121
132
|
end
|
|
122
133
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
command = File.basename($0)
|
|
2
|
+
bin_path = File.expand_path("../../../bin/spring", __FILE__)
|
|
3
|
+
|
|
4
|
+
if command == "spring"
|
|
5
|
+
load bin_path
|
|
6
|
+
else
|
|
7
|
+
disable = ENV["DISABLE_SPRING"]
|
|
8
|
+
|
|
9
|
+
if Process.respond_to?(:fork) && (disable.nil? || disable.empty? || disable == "0")
|
|
10
|
+
ARGV.unshift(command)
|
|
11
|
+
load bin_path
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/spring/boot.rb
ADDED
|
@@ -1,46 +1,164 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
|
|
1
3
|
module Spring
|
|
2
4
|
module Client
|
|
3
5
|
class Binstub < Command
|
|
4
|
-
|
|
6
|
+
SHEBANG = /\#\!.*\n/
|
|
7
|
+
|
|
8
|
+
# If loading the bin/spring file works, it'll run spring which will
|
|
9
|
+
# eventually call Kernel.exit. This means that in the client process
|
|
10
|
+
# we will never execute the lines after this block. But if the spring
|
|
11
|
+
# client is not invoked for whatever reason, then the Kernel.exit won't
|
|
12
|
+
# happen, and so we'll fall back to the lines after this block, which
|
|
13
|
+
# should cause the "unsprung" version of the command to run.
|
|
14
|
+
LOADER = <<CODE
|
|
15
|
+
begin
|
|
16
|
+
load File.expand_path("../spring", __FILE__)
|
|
17
|
+
rescue LoadError
|
|
18
|
+
end
|
|
19
|
+
CODE
|
|
20
|
+
|
|
21
|
+
# The defined? check ensures these lines don't execute when we load the
|
|
22
|
+
# binstub from the application process. Which means that in the application
|
|
23
|
+
# process we'll execute the lines which come after the LOADER block, which
|
|
24
|
+
# is what we want.
|
|
25
|
+
#
|
|
26
|
+
# Parsing the lockfile in this way is pretty nasty but reliable enough
|
|
27
|
+
# The regex ensures that the match must be between a GEM line and an empty
|
|
28
|
+
# line, so it won't go on to the next section.
|
|
29
|
+
SPRING = <<'CODE'
|
|
30
|
+
#!/usr/bin/env ruby
|
|
31
|
+
|
|
32
|
+
# This file loads spring without using Bundler, in order to be fast
|
|
33
|
+
# It gets overwritten when you run the `spring binstub` command
|
|
34
|
+
|
|
35
|
+
unless defined?(Spring)
|
|
36
|
+
require "rubygems"
|
|
37
|
+
require "bundler"
|
|
38
|
+
|
|
39
|
+
if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ spring \((.*?)\)$.*?^$/m)
|
|
40
|
+
ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR)
|
|
41
|
+
ENV["GEM_HOME"] = ""
|
|
42
|
+
Gem.paths = ENV
|
|
43
|
+
|
|
44
|
+
gem "spring", match[1]
|
|
45
|
+
require "spring/binstub"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
CODE
|
|
49
|
+
|
|
50
|
+
OLD_BINSTUB = %{if !Process.respond_to?(:fork) || Gem::Specification.find_all_by_name("spring").empty?}
|
|
51
|
+
|
|
52
|
+
class Item
|
|
53
|
+
attr_reader :command, :existing
|
|
54
|
+
|
|
55
|
+
def initialize(command)
|
|
56
|
+
@command = command
|
|
57
|
+
|
|
58
|
+
if command.binstub.exist?
|
|
59
|
+
@existing = command.binstub.read
|
|
60
|
+
elsif command.name == "rails"
|
|
61
|
+
scriptfile = Spring.application_root_path.join("script/rails")
|
|
62
|
+
@existing = scriptfile.read if scriptfile.exist?
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def status(text, stream = $stdout)
|
|
67
|
+
stream.puts "* #{command.binstub_name}: #{text}"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def add
|
|
71
|
+
if existing
|
|
72
|
+
if existing.include?(OLD_BINSTUB)
|
|
73
|
+
fallback = existing.match(/#{Regexp.escape OLD_BINSTUB}\n(.*)else/m)[1]
|
|
74
|
+
fallback.gsub!(/^ /, "")
|
|
75
|
+
fallback = nil if fallback.include?("exec")
|
|
76
|
+
generate(fallback)
|
|
77
|
+
status "upgraded"
|
|
78
|
+
elsif existing =~ /load .*spring/
|
|
79
|
+
status "spring already present"
|
|
80
|
+
else
|
|
81
|
+
head, shebang, tail = existing.partition(SHEBANG)
|
|
82
|
+
|
|
83
|
+
if shebang.include?("ruby")
|
|
84
|
+
unless command.binstub.exist?
|
|
85
|
+
FileUtils.touch command.binstub
|
|
86
|
+
command.binstub.chmod 0755
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
File.write(command.binstub, "#{head}#{shebang}#{LOADER}#{tail}")
|
|
90
|
+
status "spring inserted"
|
|
91
|
+
else
|
|
92
|
+
status "doesn't appear to be ruby, so cannot use spring", $stderr
|
|
93
|
+
exit 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
else
|
|
97
|
+
generate
|
|
98
|
+
status "generated with spring"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def generate(fallback = nil)
|
|
103
|
+
unless fallback
|
|
104
|
+
fallback = "require 'bundler/setup'\n" \
|
|
105
|
+
"load Gem.bin_path('#{command.gem_name}', '#{command.exec_name}')\n"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
File.write(command.binstub, "#!/usr/bin/env ruby\n#{LOADER}#{fallback}")
|
|
109
|
+
command.binstub.chmod 0755
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def remove
|
|
113
|
+
if existing
|
|
114
|
+
File.write(command.binstub, existing.sub(LOADER, ""))
|
|
115
|
+
status "spring removed"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
attr_reader :bindir, :items
|
|
5
121
|
|
|
6
122
|
def self.description
|
|
7
123
|
"Generate spring based binstubs. Use --all to generate a binstub for all known commands."
|
|
8
124
|
end
|
|
9
125
|
|
|
126
|
+
def self.rails_command
|
|
127
|
+
@rails_command ||= CommandWrapper.new("rails")
|
|
128
|
+
end
|
|
129
|
+
|
|
10
130
|
def self.call(args)
|
|
11
131
|
require "spring/commands"
|
|
12
132
|
super
|
|
13
133
|
end
|
|
14
134
|
|
|
15
|
-
class RailsCommand
|
|
16
|
-
def fallback
|
|
17
|
-
<<CODE
|
|
18
|
-
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
|
19
|
-
require_relative '../config/boot'
|
|
20
|
-
require 'rails/commands'
|
|
21
|
-
CODE
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
135
|
def initialize(args)
|
|
26
136
|
super
|
|
27
137
|
|
|
28
|
-
@bindir
|
|
29
|
-
@
|
|
138
|
+
@bindir = env.root.join("bin")
|
|
139
|
+
@all = false
|
|
140
|
+
@mode = :add
|
|
141
|
+
@items = args.drop(1)
|
|
142
|
+
.map { |name| find_commands name }
|
|
143
|
+
.inject(Set.new, :|)
|
|
144
|
+
.map { |command| Item.new(command) }
|
|
30
145
|
end
|
|
31
146
|
|
|
32
147
|
def find_commands(name)
|
|
33
148
|
case name
|
|
34
149
|
when "--all"
|
|
35
|
-
|
|
150
|
+
@all = true
|
|
151
|
+
commands = Spring.commands.dup
|
|
36
152
|
commands.delete_if { |name, _| name.start_with?("rails_") }
|
|
37
|
-
commands
|
|
38
|
-
|
|
153
|
+
commands.values + [self.class.rails_command]
|
|
154
|
+
when "--remove"
|
|
155
|
+
@mode = :remove
|
|
156
|
+
[]
|
|
39
157
|
when "rails"
|
|
40
|
-
|
|
158
|
+
[self.class.rails_command]
|
|
41
159
|
else
|
|
42
160
|
if command = Spring.commands[name]
|
|
43
|
-
|
|
161
|
+
[command]
|
|
44
162
|
else
|
|
45
163
|
$stderr.puts "The '#{name}' command is not known to spring."
|
|
46
164
|
exit 1
|
|
@@ -49,32 +167,25 @@ CODE
|
|
|
49
167
|
end
|
|
50
168
|
|
|
51
169
|
def call
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def generate_binstub(name, command)
|
|
57
|
-
File.write(bindir.join(name), <<CODE)
|
|
58
|
-
#!/usr/bin/env ruby
|
|
170
|
+
case @mode
|
|
171
|
+
when :add
|
|
172
|
+
bindir.mkdir unless bindir.exist?
|
|
59
173
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
else
|
|
63
|
-
ARGV.unshift "#{name}"
|
|
64
|
-
load Gem.bin_path("spring", "spring")
|
|
65
|
-
end
|
|
66
|
-
CODE
|
|
67
|
-
|
|
68
|
-
bindir.join(name).chmod 0755
|
|
69
|
-
end
|
|
174
|
+
File.write(spring_binstub, SPRING)
|
|
175
|
+
spring_binstub.chmod 0755
|
|
70
176
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
177
|
+
items.each(&:add)
|
|
178
|
+
when :remove
|
|
179
|
+
spring_binstub.delete if @all
|
|
180
|
+
items.each(&:remove)
|
|
74
181
|
else
|
|
75
|
-
|
|
182
|
+
raise ArgumentError
|
|
76
183
|
end
|
|
77
184
|
end
|
|
185
|
+
|
|
186
|
+
def spring_binstub
|
|
187
|
+
bindir.join("spring")
|
|
188
|
+
end
|
|
78
189
|
end
|
|
79
190
|
end
|
|
80
191
|
end
|
data/lib/spring/client/help.rb
CHANGED
|
@@ -20,6 +20,8 @@ module Spring
|
|
|
20
20
|
@spring_commands = spring_commands || Spring::Client::COMMANDS.dup
|
|
21
21
|
@application_commands = application_commands || Spring.commands.dup
|
|
22
22
|
|
|
23
|
+
@spring_commands.delete_if { |k, v| k.start_with?("-") }
|
|
24
|
+
|
|
23
25
|
@application_commands["rails"] = @spring_commands.delete("rails")
|
|
24
26
|
end
|
|
25
27
|
|
|
@@ -46,19 +48,9 @@ module Spring
|
|
|
46
48
|
spring_commands.merge application_commands
|
|
47
49
|
end
|
|
48
50
|
|
|
49
|
-
def description_for_command(command)
|
|
50
|
-
if command.respond_to?(:description)
|
|
51
|
-
command.description
|
|
52
|
-
elsif command.respond_to?(:exec_name)
|
|
53
|
-
"Runs the #{command.exec_name} command"
|
|
54
|
-
else
|
|
55
|
-
"No description given."
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
51
|
def display(name, command)
|
|
60
|
-
if description
|
|
61
|
-
" #{name.ljust(max_name_width)} #{description}"
|
|
52
|
+
if command.description
|
|
53
|
+
" #{name.ljust(max_name_width)} #{command.description}"
|
|
62
54
|
end
|
|
63
55
|
end
|
|
64
56
|
|
data/lib/spring/client/rails.rb
CHANGED
|
@@ -24,9 +24,7 @@ module Spring
|
|
|
24
24
|
else
|
|
25
25
|
require "spring/configuration"
|
|
26
26
|
ARGV.shift
|
|
27
|
-
|
|
28
|
-
require Spring.application_root_path.join("config/boot")
|
|
29
|
-
require "rails/commands"
|
|
27
|
+
load Dir.glob(Spring.application_root_path.join("{bin,script}/rails")).first
|
|
30
28
|
end
|
|
31
29
|
end
|
|
32
30
|
end
|
data/lib/spring/client.rb
CHANGED
|
@@ -8,15 +8,18 @@ require "spring/client/binstub"
|
|
|
8
8
|
require "spring/client/stop"
|
|
9
9
|
require "spring/client/status"
|
|
10
10
|
require "spring/client/rails"
|
|
11
|
+
require "spring/client/version"
|
|
11
12
|
|
|
12
13
|
module Spring
|
|
13
14
|
module Client
|
|
14
15
|
COMMANDS = {
|
|
15
|
-
"help"
|
|
16
|
-
"binstub"
|
|
17
|
-
"stop"
|
|
18
|
-
"status"
|
|
19
|
-
"rails"
|
|
16
|
+
"help" => Client::Help,
|
|
17
|
+
"binstub" => Client::Binstub,
|
|
18
|
+
"stop" => Client::Stop,
|
|
19
|
+
"status" => Client::Status,
|
|
20
|
+
"rails" => Client::Rails,
|
|
21
|
+
"-v" => Client::Version,
|
|
22
|
+
"--version" => Client::Version
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
def self.run(args)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require "spring/configuration"
|
|
2
|
+
|
|
3
|
+
module Spring
|
|
4
|
+
class CommandWrapper
|
|
5
|
+
attr_reader :name, :command
|
|
6
|
+
|
|
7
|
+
def initialize(name, command = nil)
|
|
8
|
+
@name = name
|
|
9
|
+
@command = command
|
|
10
|
+
@setup = false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def description
|
|
14
|
+
if command.respond_to?(:description)
|
|
15
|
+
command.description
|
|
16
|
+
else
|
|
17
|
+
"Runs the #{name} command"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def setup?
|
|
22
|
+
@setup
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def setup
|
|
26
|
+
if !setup? && command.respond_to?(:setup)
|
|
27
|
+
command.setup
|
|
28
|
+
@setup = true
|
|
29
|
+
return true
|
|
30
|
+
else
|
|
31
|
+
@setup = true
|
|
32
|
+
return false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def call
|
|
37
|
+
if command.respond_to?(:call)
|
|
38
|
+
command.call
|
|
39
|
+
else
|
|
40
|
+
load exec
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def process_title
|
|
45
|
+
["spring", name, *ARGV].join(" ")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def gem_name
|
|
49
|
+
if command.respond_to?(:gem_name)
|
|
50
|
+
command.gem_name
|
|
51
|
+
else
|
|
52
|
+
exec_name
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def exec_name
|
|
57
|
+
if command.respond_to?(:exec_name)
|
|
58
|
+
command.exec_name
|
|
59
|
+
else
|
|
60
|
+
name
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def binstub
|
|
65
|
+
Spring.application_root_path.join(binstub_name)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def binstub_name
|
|
69
|
+
"bin/#{name}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def exec
|
|
73
|
+
if binstub.exist?
|
|
74
|
+
binstub.to_s
|
|
75
|
+
else
|
|
76
|
+
Gem.bin_path(gem_name, exec_name)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def env(args)
|
|
81
|
+
if command.respond_to?(:env)
|
|
82
|
+
command.env(args)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
data/lib/spring/commands/rake.rb
CHANGED
data/lib/spring/commands.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "spring/watcher"
|
|
2
|
+
require "spring/command_wrapper"
|
|
2
3
|
|
|
3
4
|
module Spring
|
|
4
5
|
@commands = {}
|
|
@@ -7,8 +8,8 @@ module Spring
|
|
|
7
8
|
attr_reader :commands
|
|
8
9
|
end
|
|
9
10
|
|
|
10
|
-
def self.register_command(name,
|
|
11
|
-
commands[name] =
|
|
11
|
+
def self.register_command(name, command = nil)
|
|
12
|
+
commands[name] = CommandWrapper.new(name, command)
|
|
12
13
|
end
|
|
13
14
|
|
|
14
15
|
def self.command?(name)
|
data/lib/spring/configuration.rb
CHANGED
|
@@ -22,15 +22,24 @@ module Spring
|
|
|
22
22
|
|
|
23
23
|
def application_root_path
|
|
24
24
|
@application_root_path ||= begin
|
|
25
|
-
|
|
25
|
+
if application_root
|
|
26
|
+
path = Pathname.new(File.expand_path(application_root))
|
|
27
|
+
else
|
|
28
|
+
path = project_root_path
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
raise MissingApplication.new(path) unless path.join("config/application.rb").exist?
|
|
27
32
|
path
|
|
28
33
|
end
|
|
29
34
|
end
|
|
30
35
|
|
|
36
|
+
def project_root_path
|
|
37
|
+
@project_root_path ||= find_project_root(Pathname.new(File.expand_path(Dir.pwd)))
|
|
38
|
+
end
|
|
39
|
+
|
|
31
40
|
private
|
|
32
41
|
|
|
33
|
-
def find_project_root(current_dir
|
|
42
|
+
def find_project_root(current_dir)
|
|
34
43
|
if current_dir.join(gemfile).exist?
|
|
35
44
|
current_dir
|
|
36
45
|
elsif current_dir.root?
|
data/lib/spring/env.rb
CHANGED
|
@@ -14,14 +14,19 @@ module Spring
|
|
|
14
14
|
attr_reader :log_file
|
|
15
15
|
|
|
16
16
|
def initialize(root = nil)
|
|
17
|
-
@root
|
|
18
|
-
@
|
|
17
|
+
@root = root
|
|
18
|
+
@project_root = root
|
|
19
|
+
@log_file = File.open(ENV["SPRING_LOG"] || "/dev/null", "a")
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def root
|
|
22
23
|
@root ||= Spring.application_root_path
|
|
23
24
|
end
|
|
24
25
|
|
|
26
|
+
def project_root
|
|
27
|
+
@project_root ||= Spring.project_root_path
|
|
28
|
+
end
|
|
29
|
+
|
|
25
30
|
def version
|
|
26
31
|
Spring::VERSION
|
|
27
32
|
end
|
|
@@ -33,7 +38,7 @@ module Spring
|
|
|
33
38
|
end
|
|
34
39
|
|
|
35
40
|
def application_id
|
|
36
|
-
Digest::MD5.hexdigest(
|
|
41
|
+
Digest::MD5.hexdigest(project_root.to_s)
|
|
37
42
|
end
|
|
38
43
|
|
|
39
44
|
def socket_path
|
|
@@ -60,7 +65,7 @@ module Spring
|
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
def server_running?
|
|
63
|
-
pidfile = pidfile_path.open('r')
|
|
68
|
+
pidfile = pidfile_path.open('r+')
|
|
64
69
|
!pidfile.flock(File::LOCK_EX | File::LOCK_NB)
|
|
65
70
|
rescue Errno::ENOENT
|
|
66
71
|
false
|
|
@@ -71,12 +76,8 @@ module Spring
|
|
|
71
76
|
end
|
|
72
77
|
end
|
|
73
78
|
|
|
74
|
-
def bundle_mtime
|
|
75
|
-
[Bundler.default_lockfile, Bundler.default_gemfile].select(&:exist?).map(&:mtime).max
|
|
76
|
-
end
|
|
77
|
-
|
|
78
79
|
def log(message)
|
|
79
|
-
log_file.puts "[#{Time.now}] #{message}"
|
|
80
|
+
log_file.puts "[#{Time.now}] [#{Process.pid}] #{message}"
|
|
80
81
|
log_file.flush
|
|
81
82
|
end
|
|
82
83
|
end
|