zeus 0.15.10 → 0.15.12

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