pry-timetravel 0.0.2 → 0.0.3

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: 5d28f753687e1f5f96c87e7ce51949dc68d8fab6
4
- data.tar.gz: be676c5cc7e8ff236314b31e6161aef76ce017a4
3
+ metadata.gz: 036cd80689a69996c2e965251b5eea0d8ad65958
4
+ data.tar.gz: 4469ac880bb66bcea64873f4cc423f06c2603a76
5
5
  SHA512:
6
- metadata.gz: c42224c2d9c89770cf5f22c861b37fa254a71713d11c46696fbc6d912027f21454a0ea98688f13f690a69e7fc7a5e12b8a1c63e2b2d61603c7c192bbebfb0c01
7
- data.tar.gz: 27bfcc69e86ff9838820f350c5fb617e24d6d1c456e702b670c8c25d7156b9afdb5be0c728b9416f8645696759c4482930e3f0f9e309344635fc9638b2636fed
6
+ metadata.gz: 948b4b85a37039e6829ff9a511ce3cf9c40f3c28d10b0f62e3d9726089c7e2280a9350553f903e15cbce77a36efc5334a1cd917a6c0cb23c0e35fd835204c727
7
+ data.tar.gz: c045d71745d255a7e3c37978cc212a666cde0e40adb625deded075b8323283fc12c070b7377e7b8dcbb3267ba50c05cc97e43f24740d8e6c1c95d62b92e62a75
data/README.md CHANGED
@@ -26,6 +26,27 @@ There are a few more details, but that is the important bit.
26
26
 
27
27
  WARNING: Time travel may cause zombies.
28
28
 
29
+ ## KNOWN ISSUES
30
+
31
+ ### Redis fork detection
32
+
33
+ Redis checks to see if you forked and yells at you about needing to reconnect.
34
+ Reasonably so, as it is a crazy idea to use the same connection in forked
35
+ children! But we are doing crazy things. In 3.1.0 the gem will auto-reconnect,
36
+ or you can pass inherit_socket to the connection to stop that. Or you can do
37
+ this to bypass safety measures:
38
+
39
+ class Redis
40
+ class Client
41
+ def ensure_connected
42
+ yield
43
+ end
44
+ end
45
+ end
46
+
47
+ Maybe this will be a default hack that gets activated on your first snapshot at
48
+ some point in the near future.
49
+
29
50
  ## Meta
30
51
 
31
52
  Released under the MIT license, see LICENSE.MIT for details. License is
@@ -1,7 +1,8 @@
1
1
  require 'rubygems'
2
2
  require 'pry'
3
+ require 'json'
3
4
 
4
- require File.expand_path('../pry-timetravel/commands', __FILE__)
5
+ require_relative 'pry-timetravel/commands'
5
6
 
6
7
  class PryTimetravel
7
8
  class << self
@@ -23,92 +24,142 @@ class PryTimetravel
23
24
  end
24
25
 
25
26
  def enter_suspended_animation
27
+ dlog("Installing SIGCONT trap")
26
28
  old_sigcont_handler = Signal.trap('CONT') do
27
29
  dlog("Got a SIGCONT")
28
30
  end
29
31
 
32
+ dlog("Installing SIGEXIT trap")
30
33
  old_sigexit_handler = Signal.trap('EXIT') do
31
34
  dlog("got EXIT")
32
- Kernel.exit!
35
+ Kernel.exit! true
33
36
  end
34
37
 
35
38
  dlog("Stopping myself")
36
39
  Process.kill 'SIGSTOP', $$
37
40
  dlog("Back from SIGSTOP!")
38
41
 
42
+ @snap_tree = JSON.parse(File.read("/tmp/timetravel_#{$root_parent}.json"))
43
+
39
44
  dlog("Returning to old SIGCONT")
40
- Signal.trap('CONT', old_sigcont_handler)
45
+ Signal.trap('CONT', old_sigcont_handler || "DEFAULT")
46
+
41
47
  dlog("Returning to old SIGEXIT")
42
- Signal.trap('EXIT', old_sigexit_handler)
48
+ Signal.trap('EXIT', old_sigexit_handler || "DEFAULT")
43
49
  end
44
50
 
45
- def snapshot
51
+ def start_root_parent
52
+ $root_parent = $$
53
+ child_pid = fork
54
+ if child_pid
55
+ Signal.trap('INT') do
56
+ dlog("root-parent got INT, ignoring")
57
+ end
58
+ Signal.trap('USR1') do
59
+ dlog("root-parent got USR1, exiting")
60
+ FileUtils.rm("/tmp/timetravel_#{$root_parent}.json")
61
+ Kernel.exit! true
62
+ end
63
+ dlog "Root parent waiting on #{child_pid}"
64
+ # sleep
65
+ # Process.waitall
66
+ Process.waitpid child_pid
67
+ # Process.waitpid 0
68
+ dlog "Root parent exiting after wait"
69
+ FileUtils.rm("/tmp/timetravel_#{$root_parent}.json")
70
+ Kernel.exit! true
71
+ end
72
+ end
73
+
74
+ def snapshot(target, parent = -> {}, child = -> {})
46
75
 
47
76
  # We need a root-parent to keep the shell happy
48
77
  if ! $root_parent
49
- $root_parent = $$
50
- child_pid = fork
51
- if child_pid
52
- Signal.trap('INT') do
53
- dlog("root-parent got INT")
54
- end
55
- Signal.trap('USR1') do
56
- dlog("root-parent got USR1")
57
- Kernel.exit!
58
- end
59
- dlog "Root parent waiting on #{child_pid}"
60
- Process.waitpid child_pid
61
- dlog "Root parent exiting!"
62
- Kernel.exit!
63
- end
78
+ start_root_parent
64
79
  end
65
80
 
66
- $timetravel_root ||= $$
81
+ @timetravel_root ||= $$
82
+ @snap_tree ||= {
83
+ $$.to_s => {
84
+ "file" => target.eval('__FILE__'),
85
+ "line" => target.eval('__LINE__'),
86
+ }
87
+ }
67
88
 
68
89
  parent_pid = $$
69
90
  child_pid = fork
91
+
70
92
  if child_pid
71
- dlog("I am parent #{parent_pid}: I have a child pid #{child_pid}")
72
93
 
73
- # Method 3: Child suspends themselves, parent adds them to list
74
- @previous_pid ||= []
75
- @previous_pid.push child_pid
94
+ dlog("I am parent #{parent_pid}: I have a child pid #{child_pid}")
95
+ enter_suspended_animation
76
96
 
77
- # Perform operation
78
- yield
97
+ # Perform child operation
98
+ child.()
79
99
 
80
100
  else
101
+
81
102
  child_pid = $$
82
103
  dlog("I am child #{child_pid}: I have a parent pid #{parent_pid}")
83
- enter_suspended_animation
104
+
105
+ @snap_tree[child_pid.to_s] = {
106
+ "previous" => parent_pid,
107
+ "file" => target.eval('__FILE__'),
108
+ "line" => target.eval('__LINE__'),
109
+ }
110
+
111
+ # Perform parent operation
112
+ parent.()
113
+
84
114
  end
85
115
  end
86
116
 
87
- def snapshot_list
88
- @previous_pid && @previous_pid.join(" ")
117
+ def snapshot_list(target, indent = "", node = @timetravel_root.to_s)
118
+ # @snap_tree && @snap_tree.keys.join(" ")
119
+ return unless node && node != ""
120
+
121
+ # This shouldn't be here
122
+ @snap_tree[$$.to_s]["file"] = target.eval('__FILE__')
123
+ @snap_tree[$$.to_s]["line"] = target.eval('__LINE__')
124
+
125
+ out = "#{indent}#{node} #{@snap_tree[node]["file"]} #{@snap_tree[node]["line"]} #{ node == $$.to_s ? '***' : ''}\n"
126
+ @snap_tree.keys.select { |n|
127
+ @snap_tree[n]["previous"] == node.to_i
128
+ }.each do |n|
129
+ out += snapshot_list(target, indent + " ", n)
130
+ end
131
+ out
89
132
  end
90
133
 
91
- def restore_snapshot(target_pid = nil, count = nil)
92
- dlog("Thinking about time travel...");
134
+ def restore_snapshot(target, target_pid = nil, count = 1)
135
+ dlog("Thinking about time travel... $$");
93
136
 
94
- if target_pid.nil? && @previous_pid && ! @previous_pid.empty?
95
- count = 1 if count == 0
96
- target_pid = @previous_pid[-count]
137
+ if target_pid.nil? && @snap_tree && ! @snap_tree[$$.to_s].nil?
138
+ count = 1 if count < 1
139
+ target_pid = @snap_tree[$$.to_s]["previous"]
140
+ @snap_tree[$$.to_s]["file"] = target.eval('__FILE__')
141
+ @snap_tree[$$.to_s]["line"] = target.eval('__LINE__')
97
142
  else
98
143
  target_pid = target_pid
99
144
  end
100
145
 
101
146
  if target_pid
102
147
  dlog("ME #{$$}: I found a target pid #{target_pid}! TIME TRAVEL TIME")
148
+
149
+ File.open("/tmp/timetravel_#{$root_parent}.json", 'w') do |f|
150
+ f.puts @snap_tree.to_json
151
+ end
152
+
103
153
  Process.kill 'SIGCONT', target_pid
104
154
  enter_suspended_animation
105
155
  else
106
156
  dlog("I was unable to time travel. Maybe it is a myth.");
157
+ puts "No previous snapshot found."
107
158
  end
108
159
  end
109
160
 
110
161
  def restore_root_snapshot
111
- restore_snapshot($timetravel_root) if $timetravel_root
162
+ restore_snapshot(@timetravel_root) if @timetravel_root
112
163
  end
113
164
 
114
165
  end
@@ -20,11 +20,14 @@ Pry::Commands.create_command "snap", "Create a snapshot that you can later retur
20
20
  end
21
21
  def process
22
22
  if opts.l?
23
- output.puts PryTimetravel.snapshot_list
23
+ output.puts PryTimetravel.snapshot_list(target)
24
24
  else
25
- PryTimetravel.snapshot do
26
- run(args.join(" ")) unless args.empty?
27
- end
25
+ PryTimetravel.snapshot(
26
+ target,
27
+ -> { run(args.join(" ")) unless args.empty? },
28
+ -> { run('whereami') }
29
+ )
30
+ # run('whereami')
28
31
  end
29
32
  end
30
33
  end
@@ -47,10 +50,10 @@ Pry::Commands.create_command "back", "Go back to the most recent snapshot" do
47
50
  end
48
51
  def process
49
52
  if opts.h?
50
- PryTimetravel.restore_root_snapshot
53
+ PryTimetravel.restore_root_snapshot(target)
51
54
  else
52
- count = args.first.to_i
53
- PryTimetravel.restore_snapshot(opts[:p], count)
55
+ target_pid = args.first ? args.first.to_i : opts[:p]
56
+ PryTimetravel.restore_snapshot(target, target_pid)
54
57
  end
55
58
  end
56
59
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'pry-timetravel'
3
- s.version = '0.0.2'
3
+ s.version = '0.0.3'
4
4
  s.summary = 'Timetravel'
5
5
  s.description = 'Allows you to timetravel!'
6
6
  s.homepage = 'https://github.com/awwaiid/pry-timetravel'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-timetravel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brock Wilcox
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-20 00:00:00.000000000 Z
11
+ date: 2014-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry