spring_standalone 0.1.13
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 +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +418 -0
- data/bin/spring_sa +49 -0
- data/lib/spring_standalone/application.rb +367 -0
- data/lib/spring_standalone/application/boot.rb +19 -0
- data/lib/spring_standalone/application_manager.rb +141 -0
- data/lib/spring_standalone/binstub.rb +13 -0
- data/lib/spring_standalone/boot.rb +10 -0
- data/lib/spring_standalone/client.rb +48 -0
- data/lib/spring_standalone/client/binstub.rb +198 -0
- data/lib/spring_standalone/client/command.rb +18 -0
- data/lib/spring_standalone/client/help.rb +62 -0
- data/lib/spring_standalone/client/rails.rb +34 -0
- data/lib/spring_standalone/client/run.rb +232 -0
- data/lib/spring_standalone/client/server.rb +18 -0
- data/lib/spring_standalone/client/status.rb +30 -0
- data/lib/spring_standalone/client/stop.rb +22 -0
- data/lib/spring_standalone/client/version.rb +11 -0
- data/lib/spring_standalone/command_wrapper.rb +82 -0
- data/lib/spring_standalone/commands.rb +50 -0
- data/lib/spring_standalone/commands/rake.rb +30 -0
- data/lib/spring_standalone/configuration.rb +58 -0
- data/lib/spring_standalone/env.rb +116 -0
- data/lib/spring_standalone/errors.rb +36 -0
- data/lib/spring_standalone/failsafe_thread.rb +14 -0
- data/lib/spring_standalone/json.rb +626 -0
- data/lib/spring_standalone/process_title_updater.rb +65 -0
- data/lib/spring_standalone/server.rb +150 -0
- data/lib/spring_standalone/sid.rb +42 -0
- data/lib/spring_standalone/version.rb +3 -0
- data/lib/spring_standalone/watcher.rb +30 -0
- data/lib/spring_standalone/watcher/abstract.rb +117 -0
- data/lib/spring_standalone/watcher/polling.rb +98 -0
- metadata +106 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module SpringStandalone
|
2
|
+
module Client
|
3
|
+
class Server < Command
|
4
|
+
def self.description
|
5
|
+
"Explicitly start a SpringStandalone server in the foreground"
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
require "spring_standalone/server"
|
10
|
+
SpringStandalone::Server.boot(foreground: foreground?)
|
11
|
+
end
|
12
|
+
|
13
|
+
def foreground?
|
14
|
+
!args.include?("--background")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SpringStandalone
|
2
|
+
module Client
|
3
|
+
class Status < Command
|
4
|
+
def self.description
|
5
|
+
"Show current status."
|
6
|
+
end
|
7
|
+
|
8
|
+
def call
|
9
|
+
if env.server_running?
|
10
|
+
puts "SpringStandalone is running:"
|
11
|
+
puts
|
12
|
+
print_process env.pid
|
13
|
+
application_pids.each { |pid| print_process pid }
|
14
|
+
else
|
15
|
+
puts "SpringStandalone is not running."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def print_process(pid)
|
20
|
+
puts `ps -p #{pid} -o pid= -o command=`
|
21
|
+
end
|
22
|
+
|
23
|
+
def application_pids
|
24
|
+
candidates = `ps -ax -o ppid= -o pid=`.lines
|
25
|
+
candidates.select { |l| l =~ /^(\s+)?#{env.pid} / }
|
26
|
+
.map { |l| l.split(" ").last }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spring_standalone/version"
|
2
|
+
|
3
|
+
module SpringStandalone
|
4
|
+
module Client
|
5
|
+
class Stop < Command
|
6
|
+
def self.description
|
7
|
+
"Stop all SpringStandalone processes for this project."
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
case env.stop
|
12
|
+
when :stopped
|
13
|
+
puts "SpringStandalone stopped."
|
14
|
+
when :killed
|
15
|
+
$stderr.puts "SpringStandalone did not stop; killing forcibly."
|
16
|
+
when :not_running
|
17
|
+
puts "SpringStandalone is not running"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spring_standalone/configuration"
|
2
|
+
|
3
|
+
module SpringStandalone
|
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 gem_name
|
45
|
+
if command.respond_to?(:gem_name)
|
46
|
+
command.gem_name
|
47
|
+
else
|
48
|
+
exec_name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def exec_name
|
53
|
+
if command.respond_to?(:exec_name)
|
54
|
+
command.exec_name
|
55
|
+
else
|
56
|
+
name
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def binstub
|
61
|
+
SpringStandalone.application_root_path.join(binstub_name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def binstub_name
|
65
|
+
"bin/#{name}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def exec
|
69
|
+
if binstub.exist?
|
70
|
+
binstub.to_s
|
71
|
+
else
|
72
|
+
Gem.bin_path(gem_name, exec_name)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def env(args)
|
77
|
+
if command.respond_to?(:env)
|
78
|
+
command.env(args)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "spring_standalone/watcher"
|
2
|
+
require "spring_standalone/command_wrapper"
|
3
|
+
|
4
|
+
module SpringStandalone
|
5
|
+
@commands = {}
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :commands
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.register_command(name, command = nil)
|
12
|
+
commands[name] = CommandWrapper.new(name, command)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.command?(name)
|
16
|
+
commands.include? name
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.command(name)
|
20
|
+
commands.fetch name
|
21
|
+
end
|
22
|
+
|
23
|
+
# require "spring_standalone/commands/rails"
|
24
|
+
require "spring_standalone/commands/rake"
|
25
|
+
|
26
|
+
# Load custom commands, if any.
|
27
|
+
# needs to be at the end to allow modification of existing commands.
|
28
|
+
config = File.expand_path("~/.spring_standalone.rb")
|
29
|
+
require config if File.exist?(config)
|
30
|
+
|
31
|
+
# If the config/spring.rb contains requires for commands from other gems,
|
32
|
+
# then we need to be under bundler.
|
33
|
+
require "bundler/setup"
|
34
|
+
|
35
|
+
# Auto-require any SpringStandalone extensions which are in the Gemfile
|
36
|
+
Gem::Specification.map(&:name).grep(/^spring_standalone-/).each do |command|
|
37
|
+
begin
|
38
|
+
require command
|
39
|
+
rescue LoadError => error
|
40
|
+
if error.message.include?(command)
|
41
|
+
require command.gsub("-", "/")
|
42
|
+
else
|
43
|
+
raise
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
config = File.expand_path("./config/spring_standalone.rb")
|
49
|
+
require config if File.exist?(config)
|
50
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module SpringStandalone
|
2
|
+
module Commands
|
3
|
+
class Rake
|
4
|
+
class << self
|
5
|
+
attr_accessor :environment_matchers
|
6
|
+
end
|
7
|
+
|
8
|
+
self.environment_matchers = {
|
9
|
+
:default => "test",
|
10
|
+
/^test($|:)/ => "test"
|
11
|
+
}
|
12
|
+
|
13
|
+
def env(args)
|
14
|
+
# This is an adaption of the matching that Rake itself does.
|
15
|
+
# See: https://github.com/jimweirich/rake/blob/3754a7639b3f42c2347857a0878beb3523542aee/lib/rake/application.rb#L691-L692
|
16
|
+
if env = args.grep(/^(APP|RACK)_ENV=(.*)$/m).last
|
17
|
+
return env.split("=").last
|
18
|
+
end
|
19
|
+
|
20
|
+
self.class.environment_matchers.each do |matcher, environment|
|
21
|
+
return environment if matcher === (args.first || :default)
|
22
|
+
end
|
23
|
+
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
SpringStandalone.register_command "rake", Rake.new
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spring_standalone/errors"
|
2
|
+
|
3
|
+
module SpringStandalone
|
4
|
+
class << self
|
5
|
+
attr_accessor :application_root, :quiet
|
6
|
+
|
7
|
+
def gemfile
|
8
|
+
if /\s1.9.[0-9]/ === Bundler.ruby_scope.gsub(/[\/\s]+/,'')
|
9
|
+
ENV["BUNDLE_GEMFILE"] || "Gemfile"
|
10
|
+
else
|
11
|
+
Bundler.default_gemfile
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def after_fork_callbacks
|
16
|
+
@after_fork_callbacks ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_fork(&block)
|
20
|
+
after_fork_callbacks << block
|
21
|
+
end
|
22
|
+
|
23
|
+
def verify_environment
|
24
|
+
application_root_path
|
25
|
+
end
|
26
|
+
|
27
|
+
def application_root_path
|
28
|
+
@application_root_path ||= begin
|
29
|
+
if application_root
|
30
|
+
path = Pathname.new(File.expand_path(application_root))
|
31
|
+
else
|
32
|
+
path = project_root_path
|
33
|
+
end
|
34
|
+
|
35
|
+
# raise MissingApplication.new(path) unless path.join("config/application.rb").exist?
|
36
|
+
path
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def project_root_path
|
41
|
+
@project_root_path ||= find_project_root(Pathname.new(File.expand_path(Dir.pwd)))
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def find_project_root(current_dir)
|
47
|
+
if current_dir.join(gemfile).exist?
|
48
|
+
current_dir
|
49
|
+
elsif current_dir.root?
|
50
|
+
raise UnknownProject.new(Dir.pwd)
|
51
|
+
else
|
52
|
+
find_project_root(current_dir.parent)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
self.quiet = false
|
58
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "digest/md5"
|
3
|
+
|
4
|
+
require "spring_standalone/version"
|
5
|
+
require "spring_standalone/sid"
|
6
|
+
require "spring_standalone/configuration"
|
7
|
+
|
8
|
+
module SpringStandalone
|
9
|
+
IGNORE_SIGNALS = %w(INT QUIT)
|
10
|
+
STOP_TIMEOUT = 2 # seconds
|
11
|
+
|
12
|
+
class Env
|
13
|
+
attr_reader :log_file
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@root = options[:root]
|
17
|
+
@project_root = options[:root]
|
18
|
+
@log_file = options[:log_file] || File.open(ENV["SPRING_LOG"] || File::NULL, "a")
|
19
|
+
end
|
20
|
+
|
21
|
+
def root
|
22
|
+
@root ||= SpringStandalone.application_root_path
|
23
|
+
end
|
24
|
+
|
25
|
+
def project_root
|
26
|
+
@project_root ||= SpringStandalone.project_root_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def version
|
30
|
+
SpringStandalone::VERSION
|
31
|
+
end
|
32
|
+
|
33
|
+
def tmp_path
|
34
|
+
require "tmpdir"
|
35
|
+
path = Pathname.new(
|
36
|
+
ENV["SPRING_TMP_PATH"] ||
|
37
|
+
File.join(ENV['XDG_RUNTIME_DIR'] || Dir.tmpdir, "spring-#{Process.uid}")
|
38
|
+
)
|
39
|
+
require "fileutils"
|
40
|
+
FileUtils.mkdir_p(path) unless path.exist?
|
41
|
+
path
|
42
|
+
end
|
43
|
+
|
44
|
+
def application_id
|
45
|
+
ENV["SPRING_APPLICATION_ID"] || Digest::MD5.hexdigest(RUBY_VERSION + project_root.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
def socket_path
|
49
|
+
Pathname.new(ENV["SPRING_SOCKET"] || tmp_path.join(application_id))
|
50
|
+
end
|
51
|
+
|
52
|
+
def socket_name
|
53
|
+
socket_path.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def pidfile_path
|
57
|
+
Pathname.new(ENV["SPRING_PIDFILE"] || socket_path.dirname.join("#{socket_path.basename(".*")}.pid"))
|
58
|
+
end
|
59
|
+
|
60
|
+
def pid
|
61
|
+
pidfile_path.exist? ? pidfile_path.read.to_i : nil
|
62
|
+
rescue Errno::ENOENT
|
63
|
+
# This can happen if the pidfile is removed after we check it
|
64
|
+
# exists
|
65
|
+
end
|
66
|
+
|
67
|
+
def app_name
|
68
|
+
root.basename
|
69
|
+
end
|
70
|
+
|
71
|
+
def server_running?
|
72
|
+
pidfile = pidfile_path.open('r+')
|
73
|
+
!pidfile.flock(File::LOCK_EX | File::LOCK_NB)
|
74
|
+
rescue Errno::ENOENT
|
75
|
+
false
|
76
|
+
ensure
|
77
|
+
if pidfile
|
78
|
+
pidfile.flock(File::LOCK_UN)
|
79
|
+
pidfile.close
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def log(message)
|
84
|
+
log_file.puts "[#{Time.now}] [#{Process.pid}] #{message}"
|
85
|
+
log_file.flush
|
86
|
+
end
|
87
|
+
|
88
|
+
def stop
|
89
|
+
if server_running?
|
90
|
+
timeout = Time.now + STOP_TIMEOUT
|
91
|
+
kill 'TERM'
|
92
|
+
sleep 0.1 until !server_running? || Time.now >= timeout
|
93
|
+
|
94
|
+
if server_running?
|
95
|
+
kill 'KILL'
|
96
|
+
:killed
|
97
|
+
else
|
98
|
+
:stopped
|
99
|
+
end
|
100
|
+
else
|
101
|
+
:not_running
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def kill(sig)
|
106
|
+
pid = self.pid
|
107
|
+
Process.kill(sig, pid) if pid
|
108
|
+
rescue Errno::ESRCH
|
109
|
+
# already dead
|
110
|
+
end
|
111
|
+
|
112
|
+
def server_command
|
113
|
+
ENV["SPRING_SERVER_COMMAND"] || "#{File.expand_path("../../../bin/spring_sa", __FILE__)} server --background"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module SpringStandalone
|
2
|
+
class ClientError < StandardError; end
|
3
|
+
|
4
|
+
class UnknownProject < StandardError
|
5
|
+
attr_reader :current_dir
|
6
|
+
|
7
|
+
def initialize(current_dir)
|
8
|
+
@current_dir = current_dir
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
"SpringStandalone was unable to locate the root of your project. There was no Gemfile " \
|
13
|
+
"present in the current directory (#{current_dir}) or any of the parent " \
|
14
|
+
"directories."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# class MissingApplication < ClientError
|
19
|
+
# attr_reader :project_root
|
20
|
+
#
|
21
|
+
# def initialize(project_root)
|
22
|
+
# @project_root = project_root
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# def message
|
26
|
+
# "SpringStandalone was unable to find your config/application.rb file. " \
|
27
|
+
# "Your project root was detected at #{project_root}, so SpringStandalone " \
|
28
|
+
# "looked for #{project_root}/config/application.rb but it doesn't exist. You can " \
|
29
|
+
# "configure the root of your application by setting SpringStandalone.application_root in " \
|
30
|
+
# "config/spring.rb."
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
|
34
|
+
class CommandNotFound < ClientError
|
35
|
+
end
|
36
|
+
end
|