zeus 0.15.10 → 0.15.12

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f28b5877e1a9f2d864f994db8ec997e2bfd2e88
4
- data.tar.gz: 7e71058d4c5171c6992f5074e5f1df204392019f
3
+ metadata.gz: d0b6652301511b13e06a1b60dbb808cc5e2161a2
4
+ data.tar.gz: 4898481f7b4acec5828dfa25a2351d31b5f166b0
5
5
  SHA512:
6
- metadata.gz: 4c369f05160ce2dbbb0b631af280f73bc19bdfa524109e03d33c9ef0216f33b0c47e1289d248e7d7b462c275d7960da72acfee86f2dd2c05f47682278cc0a4da
7
- data.tar.gz: 266f75f0595297687016d2af1d7d7319f62f83a45a8ed815c56c73a2385bd40e46b75478c5f3221dc358a752283b1e0455abb4fe00bbbaefcc64d567db136c73
6
+ metadata.gz: 187015a45fdb160f364da8c1ee05de7577642e79d114ca0982f5409cc582cb02bb764a0b0074750d72fa492dd52782ad1b77580691963c1fb83900d13d703345
7
+ data.tar.gz: c837a56c542b72057a3dbc324bf42dbc4f8cd75080f6b211e01f7e83053d3f9f15470eedfc40310d313e2399a3a53f8382d28c9ac38a95ab21c86602b3c90729
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zeus (0.15.10)
4
+ zeus (0.15.12)
5
5
  method_source (>= 0.6.7)
6
6
 
7
7
  GEM
@@ -10,24 +10,24 @@ GEM
10
10
  coderay (1.1.1)
11
11
  diff-lcs (1.2.5)
12
12
  method_source (0.8.2)
13
- pry (0.10.3)
13
+ pry (0.10.4)
14
14
  coderay (~> 1.1.0)
15
15
  method_source (~> 0.8.1)
16
16
  slop (~> 3.4)
17
- rake (11.1.2)
18
- rspec (3.4.0)
19
- rspec-core (~> 3.4.0)
20
- rspec-expectations (~> 3.4.0)
21
- rspec-mocks (~> 3.4.0)
22
- rspec-core (3.4.4)
23
- rspec-support (~> 3.4.0)
24
- rspec-expectations (3.4.0)
17
+ rake (12.0.0)
18
+ rspec (3.5.0)
19
+ rspec-core (~> 3.5.0)
20
+ rspec-expectations (~> 3.5.0)
21
+ rspec-mocks (~> 3.5.0)
22
+ rspec-core (3.5.4)
23
+ rspec-support (~> 3.5.0)
24
+ rspec-expectations (3.5.0)
25
25
  diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.4.0)
27
- rspec-mocks (3.4.1)
26
+ rspec-support (~> 3.5.0)
27
+ rspec-mocks (3.5.0)
28
28
  diff-lcs (>= 1.2.0, < 2.0)
29
- rspec-support (~> 3.4.0)
30
- rspec-support (3.4.1)
29
+ rspec-support (~> 3.5.0)
30
+ rspec-support (3.5.0)
31
31
  slop (3.6.0)
32
32
 
33
33
  PLATFORMS
@@ -41,4 +41,4 @@ DEPENDENCIES
41
41
  zeus!
42
42
 
43
43
  BUNDLED WITH
44
- 1.12.3
44
+ 1.13.7
Binary file
Binary file
Binary file
@@ -9,6 +9,7 @@ require 'zeus/rails'
9
9
 
10
10
  class CucumberPlan < Zeus::Rails
11
11
  def cucumber_environment
12
+ ::Rails.env = ENV['RAILS_ENV'] = 'test'
12
13
  require 'cucumber/rspec/disable_option_parser'
13
14
  require 'cucumber/cli/main'
14
15
  @cucumber_runtime = Cucumber::Runtime.new
@@ -69,7 +69,9 @@ module Zeus
69
69
  local.send_io(feature_pipe_r)
70
70
  feature_pipe_r.close
71
71
 
72
- run_action(local, identifier, feature_pipe_w)
72
+ Zeus::LoadTracking.set_feature_pipe(feature_pipe_w)
73
+
74
+ run_action(local, identifier)
73
75
 
74
76
  # We are now 'connected'. From this point, we may receive requests to fork.
75
77
  children = Set.new
@@ -97,10 +99,16 @@ module Zeus
97
99
  elsif code == "S"
98
100
  # Child, supposed to start another step:
99
101
  @parent_pid = forked_from
102
+
103
+ Zeus::LoadTracking.clear_feature_pipe
104
+
100
105
  throw(:boot_step, ident.to_sym)
101
106
  else
102
107
  # Child, supposed to run a command:
103
108
  @parent_pid = forked_from
109
+
110
+ Zeus::LoadTracking.clear_feature_pipe
111
+
104
112
  return [ident.to_sym, local]
105
113
  end
106
114
  end
@@ -176,12 +184,6 @@ module Zeus
176
184
  }
177
185
  end
178
186
 
179
- def notify_features(pipe, features)
180
- features.each do |t|
181
- pipe.puts t
182
- end
183
- end
184
-
185
187
  def report_error_to_master(local, error)
186
188
  str = "R:"
187
189
  str << "#{error.backtrace[0]}: #{error.message} (#{error.class})\n"
@@ -192,28 +194,18 @@ module Zeus
192
194
  local.write str
193
195
  end
194
196
 
195
- def run_action(socket, identifier, feature_pipe_w)
197
+ def run_action(socket, identifier)
196
198
  # Now we run the action and report its success/fail status to the master.
197
- features, err = Zeus::LoadTracking.features_loaded_by do
198
- plan.after_fork unless identifier == :boot
199
- plan.send(identifier)
200
- end
201
-
202
- if err
203
- # If we received an error, report features to the master syncronously.
204
- # We need to do this before reporting the error to the master
205
- # otherwise it will kill us before we can report features.
206
- begin
207
- notify_features(feature_pipe_w, features)
208
- feature_pipe_w.close
209
- ensure
210
- report_error_to_master(socket, err)
199
+ begin
200
+ Zeus::LoadTracking.track_features_loaded_by do
201
+ plan.after_fork unless identifier == :boot
202
+ plan.send(identifier)
211
203
  end
212
- else
213
- # If we booted successfully, report features in a new thread
214
- # so we can immediately begin listening for commands.
204
+
215
205
  socket.write "R:OK\0"
216
- Thread.new { notify_features(feature_pipe_w, features) }
206
+ rescue => err
207
+ report_error_to_master(socket, err)
208
+ raise
217
209
  end
218
210
  end
219
211
  end
@@ -1,8 +1,15 @@
1
1
  module Zeus
2
2
  class LoadTracking
3
3
  class << self
4
- def features_loaded_by(&block)
5
- old_features = all_features
4
+ def add_feature(file)
5
+ full_path = File.expand_path(file)
6
+ return unless File.exist?(full_path) && @feature_pipe
7
+ notify_features([full_path])
8
+ end
9
+
10
+ # Internal: This should only be called by Zeus code
11
+ def track_features_loaded_by
12
+ old_features = $LOADED_FEATURES.dup
6
13
 
7
14
  # Catch exceptions so we can determine the features
8
15
  # that were being loaded at the time of the exception.
@@ -14,48 +21,47 @@ module Zeus
14
21
  # the error is not in the backtrace, only the error message.
15
22
  match = /\A([^:]+):\d+: syntax error/.match(err.message)
16
23
  err_features << match[1] if match
17
- rescue Exception => err
18
- # Just capture this to add to the err_features list
19
- end
24
+ raise
25
+ rescue ScriptError => err
26
+ raise
27
+ rescue => err
28
+ raise
29
+ ensure
30
+ if err && err.backtrace
31
+ err_features += err.backtrace.map { |b| b.split(':').first }
32
+ .select { |f| f.start_with?('/') }
33
+ .take_while { |f| f != __FILE__ }
34
+ end
20
35
 
21
- if err && err.backtrace
22
- err_features += err.backtrace.map { |b| b.split(':').first }
23
- .select { |f| f.start_with?('/') }
24
- .take_while { |f| f != __FILE__ }
36
+ notify_features(Set.new($LOADED_FEATURES) + err_features - old_features)
25
37
  end
26
-
27
- new_features = all_features + err_features - old_features
28
- new_features.uniq!
29
-
30
- [new_features, err]
31
38
  end
32
39
 
33
- # Check the load path first to see if the file getting loaded is already
34
- # loaded. Otherwise, add the file to the $untracked_features array which
35
- # then gets added to $LOADED_FEATURES array.
36
- def add_feature(file)
37
- full_path = File.expand_path(file)
38
-
39
- if find_in_load_path(full_path) || File.exist?(full_path)
40
- add_extra_feature(full_path)
41
- end
40
+ # Internal: This should only be called by Zeus code
41
+ def set_feature_pipe(feature_pipe)
42
+ @feature_mutex = Mutex.new
43
+ @feature_pipe = feature_pipe
42
44
  end
43
45
 
44
- # $LOADED_FEATURES global variable is used internally by Rubygems
45
- def all_features
46
- untracked = defined?($untracked_features) ? $untracked_features : []
47
- $LOADED_FEATURES + untracked
46
+ # Internal: This should only be called by Zeus code
47
+ def clear_feature_pipe
48
+ @feature_pipe.close
49
+ @feature_pipe = nil
50
+ @feature_mutex = nil
48
51
  end
49
52
 
50
53
  private
51
54
 
52
- def add_extra_feature(path)
53
- $untracked_features ||= []
54
- $untracked_features << path
55
- end
55
+ def notify_features(features)
56
+ unless @feature_pipe
57
+ raise "Attempted to report features to Zeus when not running as part of a Zeus process"
58
+ end
56
59
 
57
- def find_in_load_path(file_path)
58
- $LOAD_PATH.detect { |path| path == file_path }
60
+ @feature_mutex.synchronize do
61
+ features.each do |t|
62
+ @feature_pipe.puts(t)
63
+ end
64
+ end
59
65
  end
60
66
  end
61
67
  end
@@ -1,3 +1,3 @@
1
1
  module Zeus
2
- VERSION = "0.15.10"
2
+ VERSION = "0.15.12"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "ZEUS" "1" "January 2016" "" ""
4
+ .TH "ZEUS" "1" "January 2017" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBzeus\fR \- boot rails in under a second
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "ZEUS\-INIT" "1" "January 2016" "" ""
4
+ .TH "ZEUS\-INIT" "1" "January 2017" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBzeus\-init\fR \- Generate a template zeus\.json
@@ -14,4 +14,4 @@ DESCRIPTION
14
14
 
15
15
 
16
16
 
17
- January 2016 ZEUS-INIT(1)
17
+ January 2017 ZEUS-INIT(1)
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "ZEUS\-START" "1" "January 2016" "" ""
4
+ .TH "ZEUS\-START" "1" "January 2017" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBzeus\-start\fR \- Start a zeus server
@@ -15,4 +15,4 @@ DESCRIPTION
15
15
 
16
16
 
17
17
 
18
- January 2016 ZEUS-START(1)
18
+ January 2017 ZEUS-START(1)
@@ -75,4 +75,4 @@ BUILTIN COMMANDS
75
75
 
76
76
 
77
77
 
78
- January 2016 ZEUS(1)
78
+ January 2017 ZEUS(1)
@@ -0,0 +1,2 @@
1
+ # This is a single ruby file that doesn't do anything for testing Zeus
2
+ # load tracking during boot.
@@ -0,0 +1,2 @@
1
+ # This is a single ruby file that doesn't do anything for testing Zeus
2
+ # load tracking after boot.
@@ -6,55 +6,53 @@ describe "Zeus::LoadTracking" do
6
6
 
7
7
  class MyError < StandardError; end
8
8
 
9
- describe '.add_feature' do
10
- context 'already in load path' do
11
- before do
12
- # add the dir path of the tempfile to LOAD_PATH
13
- $LOAD_PATH << test_dirname
14
- end
15
-
16
- after { $LOAD_PATH.delete test_dirname }
17
-
18
- it 'adds full filepath to $untracked_features' do
19
- Zeus::LoadTracking.add_feature(test_filename)
9
+ def expect_to_load(expect_features, expect_err=NilClass)
10
+ buf = StringIO.new
11
+ Zeus::LoadTracking.set_feature_pipe(buf)
20
12
 
21
- expect($untracked_features).to include(__dir__ + "/load_tracking_spec.rb")
13
+ begin
14
+ Zeus::LoadTracking.track_features_loaded_by do
15
+ yield
22
16
  end
17
+ rescue ScriptError => err
18
+ rescue => err
23
19
  end
24
20
 
25
- context 'not in load path' do
26
- it 'adds full filepath to $untracked_features' do
27
- Zeus::LoadTracking.add_feature(test_filename)
21
+ expect(err).to be_instance_of(expect_err)
22
+ expect(buf.string.strip.split("\n").sort).to eq(expect_features.sort)
23
+ end
28
24
 
29
- expect($untracked_features).to include(__dir__ + "/load_tracking_spec.rb")
30
- end
31
- end
25
+ def expand_asset_path(path)
26
+ File.join(__dir__, 'assets', path)
27
+ end
32
28
 
33
- context '.features_loaded_by' do
34
- it 'returns list of new files loaded when block executes' do
35
- new_files, = Zeus::LoadTracking.features_loaded_by do
36
- $untracked_features << "an_untracked_feature.rb"
37
- end
29
+ describe '.add_feature' do
30
+ it 'tracks full filepath' do
31
+ relative_path = Pathname.new(test_filename).relative_path_from(Pathname.new(Dir.pwd)).to_s
38
32
 
39
- expect(new_files).to eq(["an_untracked_feature.rb"])
33
+ expect_to_load([test_filename]) do
34
+ Zeus::LoadTracking.add_feature(relative_path)
40
35
  end
41
36
  end
42
- end
43
37
 
44
- describe '.features_loaded_by' do
45
- def expect_to_load(expect_features, expect_err=NilClass)
46
- new_files, err = Zeus::LoadTracking.features_loaded_by do
47
- yield
48
- end
38
+ it 'tracks loads' do
39
+ target = expand_asset_path('load.rb')
40
+
41
+ # The first `load` in Travis also pulls enc/trans/single_byte.so from the
42
+ # Ruby VM for some reason. Loading twice is harmless since this file is empty.
43
+ load(target)
49
44
 
50
- expect(new_files.sort).to eq(expect_features.sort)
51
- expect(err).to be_instance_of(expect_err)
45
+ expect_to_load([target]) do
46
+ load(target)
47
+ end
52
48
  end
53
49
 
54
- def expand_asset_path(path)
55
- File.join(__dir__, 'assets', path)
50
+ it 'does not error outside a tracking block without Zeus configured' do
51
+ Zeus::LoadTracking.add_feature(test_filename)
56
52
  end
53
+ end
57
54
 
55
+ describe '.track_features_loaded_by' do
58
56
  context 'loading valid code' do
59
57
  it 'tracks successful require_relative' do
60
58
  expect_to_load([expand_asset_path('require_relative.rb')]) do
@@ -67,35 +65,29 @@ describe "Zeus::LoadTracking" do
67
65
  require expand_asset_path('require')
68
66
  end
69
67
  end
70
-
71
- it 'tracks loads' do
72
- expect_to_load([expand_asset_path('load.rb')]) do
73
- load expand_asset_path('load.rb')
74
- end
75
- end
76
68
  end
77
69
 
78
70
  context 'loading invalid code' do
79
71
  it 'tracks requires that raise a SyntaxError' do
80
- expect_to_load([expand_asset_path('invalid_syntax.rb')], SyntaxError) do
72
+ files = [expand_asset_path('invalid_syntax.rb')]
73
+ # SyntaxError does not have a backtrace in 2.3+ (https://bugs.ruby-lang.org/issues/12811)
74
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
75
+ files << test_filename
76
+ end
77
+
78
+ expect_to_load(files, SyntaxError) do
81
79
  require expand_asset_path('invalid_syntax')
82
80
  end
83
81
  end
84
82
 
85
83
  it 'tracks requires that raise a RuntimeError' do
86
- expect_to_load([expand_asset_path('runtime_error.rb')], RuntimeError) do
84
+ expect_to_load([test_filename, expand_asset_path('runtime_error.rb')], RuntimeError) do
87
85
  require expand_asset_path('runtime_error')
88
86
  end
89
87
  end
90
88
 
91
- it 'tracks requires that exit' do
92
- expect_to_load([expand_asset_path('exit.rb')], SystemExit) do
93
- require expand_asset_path('exit')
94
- end
95
- end
96
-
97
89
  it 'tracks requires that throw in a method call' do
98
- expect_to_load([expand_asset_path('raise.rb')], MyError) do
90
+ expect_to_load([test_filename, expand_asset_path('raise.rb')], MyError) do
99
91
  require expand_asset_path('raise')
100
92
  raise_it(MyError)
101
93
  end
@@ -0,0 +1,85 @@
1
+ require 'zeus'
2
+
3
+ describe Zeus do
4
+ class MyTestPlan < Zeus::Plan
5
+ def self.mutex
6
+ @mutex ||= Mutex.new
7
+ end
8
+
9
+ def self.boot
10
+ require_relative 'assets/boot'
11
+ Thread.new do
12
+ mutex.synchronize do
13
+ Zeus::LoadTracking.add_feature(File.join(__dir__, 'assets', 'boot_delayed.rb'))
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Zeus.plan = MyTestPlan
20
+
21
+ before do
22
+ MyTestPlan.mutex.lock
23
+ end
24
+
25
+ after do
26
+ MyTestPlan.mutex.unlock if MyTestPlan.mutex.locked?
27
+ end
28
+
29
+ context 'booting' do
30
+ before do
31
+ # Don't reopen STDOUT
32
+ Zeus.dummy_tty = true
33
+ end
34
+
35
+ it 'boots and tracks features' do
36
+ master_r, master_w = UNIXSocket.pair(Socket::SOCK_STREAM)
37
+ ENV['ZEUS_MASTER_FD'] = master_w.to_i.to_s
38
+
39
+ thr = Thread.new do
40
+ begin
41
+ Zeus.go
42
+ rescue Interrupt
43
+ return
44
+ rescue => e
45
+ STDERR.puts "Zeus terminated with exception: #{e.message}"
46
+ STDERR.puts e.backtrace.map {|line| " #{line}"}
47
+ end
48
+ end
49
+
50
+ begin
51
+ # Receive the control IO and start message
52
+ ctrl_io = master_r.recv_io(UNIXSocket)
53
+ begin
54
+ # We use recv instead of readline on the UNIXSocket to avoid
55
+ # converting it to a buffered reader. That seems to interact
56
+ # badly with passing file descriptors around on Linux.
57
+ proc_msg = "P:#{Process.pid}:0:boot\0"
58
+ expect(ctrl_io.recv(proc_msg.length)).to eq(proc_msg)
59
+
60
+ feature_io = ctrl_io.recv_io
61
+
62
+ ready_msg = "R:OK\0"
63
+ expect(ctrl_io.recv(ready_msg.length)).to eq(ready_msg)
64
+ begin
65
+ # We should receive the synchronously required feature immediately
66
+ expect(feature_io.readline).to eq(File.join(__dir__, 'assets', 'boot.rb') + "\n")
67
+
68
+ # We should receive the delayed feature after unlocking its mutex
69
+ MyTestPlan.mutex.unlock
70
+ expect(feature_io.readline).to eq(File.join(__dir__, 'assets', 'boot_delayed.rb') + "\n")
71
+ ensure
72
+ feature_io.close
73
+ end
74
+ ensure
75
+ ctrl_io.close
76
+ end
77
+ ensure
78
+ thr.raise(Interrupt.new)
79
+ end
80
+ end
81
+
82
+ it 'tracks features after booting has completed' do
83
+ end
84
+ end
85
+ end
@@ -16,7 +16,7 @@ Gem::Specification.new do |gem|
16
16
  gem.email = ["burke@libbey.me"]
17
17
  gem.description = %q{Boot any rails app in under a second}
18
18
  gem.summary = %q{Zeus is an intelligent preloader for ruby applications. It allows normal development tasks to be run in a fraction of a second.}
19
- gem.homepage = "http://zeus.is"
19
+ gem.homepage = "https://github.com/burke/zeus"
20
20
 
21
21
  gem.files = files
22
22
  gem.extensions = []
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zeus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.10
4
+ version: 0.15.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Burke Libbey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-26 00:00:00.000000000 Z
11
+ date: 2017-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: method_source
@@ -75,7 +75,8 @@ files:
75
75
  - man/build/zeus-start
76
76
  - man/build/zeus-start.txt
77
77
  - man/build/zeus.txt
78
- - spec/assets/exit.rb
78
+ - spec/assets/boot.rb
79
+ - spec/assets/boot_delayed.rb
79
80
  - spec/assets/invalid_syntax.rb
80
81
  - spec/assets/load.rb
81
82
  - spec/assets/raise.rb
@@ -87,8 +88,9 @@ files:
87
88
  - spec/load_tracking_spec.rb
88
89
  - spec/m_spec.rb
89
90
  - spec/rails_spec.rb
91
+ - spec/zeus_spec.rb
90
92
  - zeus.gemspec
91
- homepage: http://zeus.is
93
+ homepage: https://github.com/burke/zeus
92
94
  licenses:
93
95
  - MIT
94
96
  metadata: {}
@@ -108,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
108
110
  version: '0'
109
111
  requirements: []
110
112
  rubyforge_project:
111
- rubygems_version: 2.4.5.1
113
+ rubygems_version: 2.4.8
112
114
  signing_key:
113
115
  specification_version: 4
114
116
  summary: Zeus is an intelligent preloader for ruby applications. It allows normal
@@ -1 +0,0 @@
1
- exit(1)