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.
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