spring_standalone 0.1.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +418 -0
  4. data/bin/spring_sa +49 -0
  5. data/lib/spring_standalone/application.rb +367 -0
  6. data/lib/spring_standalone/application/boot.rb +19 -0
  7. data/lib/spring_standalone/application_manager.rb +141 -0
  8. data/lib/spring_standalone/binstub.rb +13 -0
  9. data/lib/spring_standalone/boot.rb +10 -0
  10. data/lib/spring_standalone/client.rb +48 -0
  11. data/lib/spring_standalone/client/binstub.rb +198 -0
  12. data/lib/spring_standalone/client/command.rb +18 -0
  13. data/lib/spring_standalone/client/help.rb +62 -0
  14. data/lib/spring_standalone/client/rails.rb +34 -0
  15. data/lib/spring_standalone/client/run.rb +232 -0
  16. data/lib/spring_standalone/client/server.rb +18 -0
  17. data/lib/spring_standalone/client/status.rb +30 -0
  18. data/lib/spring_standalone/client/stop.rb +22 -0
  19. data/lib/spring_standalone/client/version.rb +11 -0
  20. data/lib/spring_standalone/command_wrapper.rb +82 -0
  21. data/lib/spring_standalone/commands.rb +50 -0
  22. data/lib/spring_standalone/commands/rake.rb +30 -0
  23. data/lib/spring_standalone/configuration.rb +58 -0
  24. data/lib/spring_standalone/env.rb +116 -0
  25. data/lib/spring_standalone/errors.rb +36 -0
  26. data/lib/spring_standalone/failsafe_thread.rb +14 -0
  27. data/lib/spring_standalone/json.rb +626 -0
  28. data/lib/spring_standalone/process_title_updater.rb +65 -0
  29. data/lib/spring_standalone/server.rb +150 -0
  30. data/lib/spring_standalone/sid.rb +42 -0
  31. data/lib/spring_standalone/version.rb +3 -0
  32. data/lib/spring_standalone/watcher.rb +30 -0
  33. data/lib/spring_standalone/watcher/abstract.rb +117 -0
  34. data/lib/spring_standalone/watcher/polling.rb +98 -0
  35. 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,11 @@
1
+ require "spring_standalone/version"
2
+
3
+ module SpringStandalone
4
+ module Client
5
+ class Version < Command
6
+ def call
7
+ puts "SpringStandalone version #{SpringStandalone::VERSION}"
8
+ end
9
+ end
10
+ end
11
+ 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