rosh 0.9.3 → 0.9.5

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
  SHA256:
3
- metadata.gz: 4a029ca2deda02d278e112ba05e40a56dce955ffa8476091d0406ae098788bd1
4
- data.tar.gz: 701dfa757f7371589b997e21914dfecf6af4fe5b21b8519804ff4f2e7ae36b71
3
+ metadata.gz: 9a9b04489aa21bdb87dd7a21a2696d33c0f1b29c45767593bca5bdc0b383b2a4
4
+ data.tar.gz: a43d640d729094bb85640cfece07ebe2f1b82bb007723d528b628fb5a495a23a
5
5
  SHA512:
6
- metadata.gz: 98e03da0dbba0d8737e39729553952ada5016b5cb7e2fe73a1b5184be1cafcfdf7d76b38a373731dca8a08bca68e014ed4b0d38fed7182eca1d9567249a31da4
7
- data.tar.gz: 8889757e1b4d933624a33d78727d2044fb36e16d58048e9e255355d8b2de8236697ceabb08eba52f63d90abb9c6f429555ffe5dc436596a3c9263399662bcdb8
6
+ metadata.gz: 35972089d8384a358f3e79795fbf774be00e38b811872f690491057ccb17134488d3a19d21cdd2bc5854acab669033273689f2d99bc1fedbdb324d1eff31982c
7
+ data.tar.gz: 8a422f7936c8482d12b168ed6a5aab6dddda8691e98b327c206a676976f770ad3a02d4a0d19888eeb86188b0dea4431b370ed2e6989559758d99adaf2c696932
data/Makefile ADDED
@@ -0,0 +1,6 @@
1
+ start:
2
+ codex --search --dangerously-bypass-approvals-and-sandbox
3
+ continue:
4
+ codex resume --search --dangerously-bypass-approvals-and-sandbox --last
5
+ resume:
6
+ codex resume --search --dangerously-bypass-approvals-and-sandbox
data/README.md CHANGED
@@ -26,6 +26,7 @@ Or install it yourself as:
26
26
  Default: "^t"
27
27
  -I interval Reconnection interval.
28
28
  -S Use GNU screen instead of tmux
29
+ -L socket-name Specify tmux socket name (tmux -L socket-name)
29
30
 
30
31
  If ~/.ssh/config contains LocalForward or RemoteForward for the host, the same
31
32
  forwarding options are passed to `ssh` automatically.
data/lib/rosh/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Rosh
2
- VERSION = '0.9.3'
2
+ VERSION = '0.9.5'
3
3
  end
data/lib/rosh.rb CHANGED
@@ -11,6 +11,7 @@ class Rosh
11
11
  @ssh_opts = []
12
12
  alive_interval = 5
13
13
  @escape = '^t'
14
+ @tmux_socket_name = nil
14
15
  OptionParser.new("test").tap do |opt|
15
16
  opt.banner = 'Usage: rosh [options] hostname [session-name]'
16
17
  opt.on('-a alive-interval'){|v| alive_interval = v.to_i}
@@ -18,6 +19,7 @@ class Rosh
18
19
  opt.on('-I interval'){|v| @interval = v.to_f}
19
20
  opt.on('-V'){|v| @verbose = true}
20
21
  opt.on('-S'){|v| @screen = true}
22
+ opt.on('-L socket-name'){|v| @tmux_socket_name = v}
21
23
  end.parse! args
22
24
  @host, @name = *args, :default
23
25
  abort 'hostname is required' if @host == :default
@@ -62,8 +64,9 @@ class Rosh
62
64
  ["ssh", *@ssh_opts, resolv,
63
65
  '-t', "'screen -rx #{@name}'", '2>/dev/null']*' '
64
66
  else
67
+ remote_cmd = single_quote(tmux_attach_command)
65
68
  ["ssh", *@ssh_opts, resolv,
66
- '-t', "'tmux attach -t #{@name}'", '2>/dev/null']*' '
69
+ '-t', remote_cmd, '2>/dev/null']*' '
67
70
  end
68
71
  if @verbose
69
72
  puts "connecting to #{@host}..."
@@ -227,23 +230,25 @@ private
227
230
 
228
231
  def sh_has_session?
229
232
  # tmux has-session -t <session_name>
230
- cmd = [
231
- "ssh",
232
- *@ssh_opts,
233
- resolv,
234
- "'tmux has-session -t #{@name} 2>/dev/null'"
235
- ]*' '
236
- puts cmd if @verbose
237
- system cmd
233
+ ssh_tmux("#{tmux_prefix} has-session -t #{tmux_session_name} 2>/dev/null")
238
234
  end
239
235
 
240
236
  def sh_new_session?
241
237
  # tmux new-session -s <session_name> -d
238
+ create_with_override = "#{tmux_prefix} new-session -s #{tmux_session_name} -d \\; set-option -t #{tmux_session_name} destroy-unattached off"
239
+ return true if ssh_tmux(create_with_override)
240
+
241
+ puts "retrying tmux new-session without destroy-unattached override" if @verbose
242
+ ssh_tmux("#{tmux_prefix} new-session -s #{tmux_session_name} -d")
243
+ end
244
+
245
+ def ssh_tmux(command)
246
+ remote_command = single_quote(command.to_s)
242
247
  cmd = [
243
248
  "ssh",
244
249
  *@ssh_opts,
245
250
  resolv,
246
- "'tmux new-session -s #{@name} -d'"
251
+ remote_command
247
252
  ]*' '
248
253
  puts cmd if @verbose
249
254
  system cmd
@@ -292,4 +297,27 @@ private
292
297
  rescue Exception
293
298
  @host
294
299
  end
300
+
301
+ def tmux_attach_command
302
+ "#{tmux_prefix} attach -t #{tmux_session_name}"
303
+ end
304
+
305
+ def tmux_prefix
306
+ return 'tmux' unless @tmux_socket_name
307
+ "tmux -L #{format_remote_arg(@tmux_socket_name)}"
308
+ end
309
+
310
+ def tmux_session_name
311
+ format_remote_arg(@name)
312
+ end
313
+
314
+ def format_remote_arg(value)
315
+ str = value.to_s
316
+ return str if str.match?(%r{\A[[:alnum:]@%+=:,./_-]+\z})
317
+ %("#{str.gsub(/(["\\$`])/, '\\\\\1')}")
318
+ end
319
+
320
+ def single_quote(str)
321
+ "'" + str.to_s.gsub("'", %q('\'') ) + "'"
322
+ end
295
323
  end
data/rosh.gemspec CHANGED
@@ -21,5 +21,6 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_dependency "net-ssh"
23
23
  spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "minitest"
24
25
  spec.add_development_dependency "rake"
25
26
  end
@@ -24,14 +24,24 @@ class RoshForwardingTest < Minitest::Test
24
24
  end
25
25
 
26
26
  def test_ssh_opts_include_local_forwarding_from_ssh_config
27
- rosh = Rosh.new('grav')
27
+ klass = Class.new(Rosh) do
28
+ def local_forward_available?(_spec)
29
+ true
30
+ end
31
+ end
32
+ rosh = klass.new('grav')
28
33
  ssh_opts = rosh.instance_variable_get(:@ssh_opts)
29
34
 
30
35
  assert_includes ssh_opts, '-L 127.0.0.1:3131:localhost:3131'
31
36
  end
32
37
 
33
38
  def test_ssh_opts_include_remote_forwarding_from_ssh_config
34
- rosh = Rosh.new('grav')
39
+ klass = Class.new(Rosh) do
40
+ def local_forward_available?(_spec)
41
+ true
42
+ end
43
+ end
44
+ rosh = klass.new('grav')
35
45
  ssh_opts = rosh.instance_variable_get(:@ssh_opts)
36
46
 
37
47
  assert_includes ssh_opts, '-R 8082:localhost:8082'
@@ -84,4 +94,50 @@ class RoshForwardingTest < Minitest::Test
84
94
  out_again, _ = capture_io { rosh.send(:report_oom_if_needed, 'ssh grav') }
85
95
  assert_equal '', out_again
86
96
  end
97
+
98
+ def test_tmux_new_session_disables_destroy_unattached
99
+ rosh = Rosh.new('grav', 'grav')
100
+ commands = []
101
+ rosh.stub(:system, ->(cmd) { commands << cmd; true }) do
102
+ assert rosh.send(:sh_new_session?)
103
+ end
104
+
105
+ assert_equal 1, commands.size
106
+ assert_includes commands.first, 'set-option -t grav destroy-unattached off'
107
+ end
108
+
109
+ def test_tmux_new_session_fallback_without_override
110
+ rosh = Rosh.new('grav', 'grav')
111
+ commands = []
112
+ results = [false, true].each
113
+
114
+ rosh.stub(:system, ->(cmd) { commands << cmd; results.next rescue true }) do
115
+ assert rosh.send(:sh_new_session?)
116
+ end
117
+
118
+ assert_includes commands.first, 'set-option -t grav destroy-unattached off'
119
+ refute_includes commands.last, 'set-option -t grav destroy-unattached off'
120
+ end
121
+
122
+ def test_tmux_commands_include_socket_name_when_specified
123
+ socket_name = 'work'
124
+ rosh = Rosh.new('-L', socket_name, 'grav')
125
+ rosh.instance_variable_set(:@name, 'grav')
126
+
127
+ assert_includes rosh.send(:tmux_attach_command), "-L #{socket_name}"
128
+
129
+ commands = []
130
+ rosh.stub(:system, ->(cmd) { commands << cmd; true }) do
131
+ rosh.send(:sh_has_session?)
132
+ end
133
+
134
+ assert_includes commands.first, "-L #{socket_name}"
135
+ end
136
+
137
+ def test_tmux_default_socket_used_when_not_specified
138
+ rosh = Rosh.new('grav')
139
+ command = rosh.send(:tmux_attach_command)
140
+
141
+ refute_includes command, '-L'
142
+ end
87
143
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rosh
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Genki Takiuchi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-27 00:00:00.000000000 Z
11
+ date: 2025-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: net-ssh
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -65,6 +79,7 @@ files:
65
79
  - ".gitignore"
66
80
  - Gemfile
67
81
  - LICENSE.txt
82
+ - Makefile
68
83
  - README.md
69
84
  - Rakefile
70
85
  - bin/rosh