hiiro 0.1.150 → 0.1.152

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: 10f2a86eb2689dd8fa57d4f90c5dbb4cad8cdfff2607a0b382eb26a941a31775
4
- data.tar.gz: ac6de045418d116c85f336c2926bd8c959b6b52cd9d6493f30c29bcea59a90d8
3
+ metadata.gz: ca8a2bc3e8f629e23986cd1f75bdcca6fc2cd0aaabf85fbde2ae00e721077178
4
+ data.tar.gz: 1bfc80f8f3f0844bbc943c23f48258577f7d3b7cea66dd48319893e7f3289aa7
5
5
  SHA512:
6
- metadata.gz: eaf5e0269292073af2e4b2ea9015ed9ebb13376aa2756513d6a1eb14a84ea9706bf600159bbd38d72436f29ebcbdfb2b51e0994457949e3a7a921c704459e109
7
- data.tar.gz: 757f05788e7fa28a6a998a218cfaa8e672461a296e646f4919611138fc1d20054171eed3e054ae1bb5693ffb0e65f2b000be3c5f9523ad555f195fe1767f61f0
6
+ metadata.gz: 05dfbdf2fdef32ec3471b8f26efefc26f07b171b0886c6f9beb55ea7008218165cc126f762cd1ef5e391511815b42eb479aa0dcdff9cc5831b885a8c4ea15b52
7
+ data.tar.gz: b9645c6341b3cf753d209b7fcac576264788156a646042a5601d4e4f1269478fd87ab8d93024448ad2ce8eb410d01cd7cd410c26d20f0ebd71007967f6f6a028
@@ -109,13 +109,50 @@ class Hiiro
109
109
  return false
110
110
  end
111
111
 
112
+ session = tmux_info[:session] || current_tmux_session
113
+ unless session
114
+ puts "tmux is required to start a service group"
115
+ return false
116
+ end
117
+
112
118
  puts "Starting group '#{group[:name]}'..."
113
- members.each do |member|
119
+
120
+ # Create one window for the group, split panes for each service
121
+ first_member = members.first
122
+ first_name = first_member['name'] || first_member[:name]
123
+ first_svc = find_service(first_name)
124
+ first_base_dir = first_svc&.[](:base_dir) || Dir.pwd
125
+
126
+ # Create a new window for the group
127
+ window_target = create_tmux_window(session, group[:name], first_base_dir)
128
+ first_pane_id = capture_pane_id(window_target)
129
+
130
+ members.each_with_index do |member, idx|
114
131
  member_name = member['name'] || member[:name]
115
132
  use_overrides = member['use'] || member[:use] || {}
116
133
 
117
134
  prepare_env(member_name, variation_overrides: use_overrides)
118
- start(member_name, tmux_info: tmux_info, task_info: task_info, skip_env: true)
135
+
136
+ svc = find_service(member_name)
137
+ next unless svc
138
+
139
+ base_dir = svc[:base_dir] || Dir.pwd
140
+
141
+ if idx == 0
142
+ # First service uses the initial pane
143
+ pane_id = first_pane_id
144
+ else
145
+ # Subsequent services get split panes
146
+ pane_id = split_tmux_pane(window_target, base_dir)
147
+ end
148
+
149
+ member_tmux_info = tmux_info.merge(
150
+ session: session,
151
+ window: window_target,
152
+ pane: pane_id,
153
+ )
154
+
155
+ start(member_name, tmux_info: member_tmux_info, task_info: task_info, skip_env: true, skip_window_creation: true)
119
156
  end
120
157
  true
121
158
  end
@@ -129,7 +166,45 @@ class Hiiro
129
166
  load_state
130
167
  end
131
168
 
132
- def start(name, tmux_info: {}, task_info: {}, variation_overrides: {}, skip_env: false)
169
+ def reset(name)
170
+ svc = find_service(name)
171
+ unless svc
172
+ puts "Service '#{name}' not found"
173
+ return false
174
+ end
175
+
176
+ svc_name = svc[:name]
177
+ state = load_state
178
+ unless state.key?(svc_name)
179
+ puts "Service '#{svc_name}' is not in running state"
180
+ return false
181
+ end
182
+
183
+ state.delete(svc_name)
184
+ save_state(state)
185
+ puts "Reset service '#{svc_name}' (cleared from running state)"
186
+ true
187
+ end
188
+
189
+ def clean
190
+ state = load_state
191
+ return puts("No running services to clean") if state.empty?
192
+
193
+ stale = state.select { |_, info| stale_pane?(info['tmux_pane']) }
194
+ if stale.empty?
195
+ puts "All running services have live panes"
196
+ return false
197
+ end
198
+
199
+ stale.each do |svc_name, _|
200
+ state.delete(svc_name)
201
+ puts "Cleaned stale service '#{svc_name}'"
202
+ end
203
+ save_state(state)
204
+ true
205
+ end
206
+
207
+ def start(name, tmux_info: {}, task_info: {}, variation_overrides: {}, skip_env: false, skip_window_creation: false)
133
208
  svc = find_service(name)
134
209
  unless svc
135
210
  puts "Service '#{name}' not found"
@@ -168,29 +243,38 @@ class Hiiro
168
243
  return false
169
244
  end
170
245
 
246
+ start_cmds = Array(start_cmd)
171
247
  base_dir = svc[:base_dir]
172
- pane_id = tmux_info[:pane] || ENV['TMUX_PANE']
248
+ session = tmux_info[:session] || current_tmux_session
249
+
250
+ # Write start commands to an executable tempfile
251
+ script = write_start_script(svc_name, start_cmds, base_dir)
252
+
253
+ if session && !skip_window_creation
254
+ # Create a new tmux window for this service
255
+ window_target = create_tmux_window(session, svc_name, base_dir || Dir.pwd)
256
+ pane_id = capture_pane_id(window_target)
257
+ elsif session && skip_window_creation
258
+ # Pane already created by start_group
259
+ pane_id = tmux_info[:pane]
260
+ window_target = tmux_info[:window]
261
+ else
262
+ pane_id = nil
263
+ window_target = nil
264
+ end
173
265
 
174
266
  if pane_id
175
- if base_dir
176
- system('tmux', 'send-keys', '-t', pane_id, "cd #{base_dir} && #{start_cmd}", 'Enter')
177
- else
178
- system('tmux', 'send-keys', '-t', pane_id, start_cmd, 'Enter')
179
- end
267
+ system('tmux', 'send-keys', '-t', pane_id, script, 'Enter')
180
268
  else
181
- if base_dir
182
- system("cd #{base_dir} && #{start_cmd} &")
183
- else
184
- system("#{start_cmd} &")
185
- end
269
+ system("#{script} &")
186
270
  end
187
271
 
188
272
  # Record state
189
273
  state = load_state
190
274
  state[svc_name] = {
191
275
  'pid' => nil,
192
- 'tmux_session' => tmux_info[:session],
193
- 'tmux_window' => tmux_info[:window],
276
+ 'tmux_session' => session || tmux_info[:session],
277
+ 'tmux_window' => window_target || tmux_info[:window],
194
278
  'tmux_pane' => pane_id,
195
279
  'task' => task_info[:task_name],
196
280
  'tree' => task_info[:tree],
@@ -220,7 +304,7 @@ class Hiiro
220
304
  info = running_services[svc_name]
221
305
  pane_id = info['tmux_pane']
222
306
 
223
- if svc[:stop]
307
+ if svc[:stop] && !svc[:stop].to_s.strip.empty?
224
308
  stop_cmd = svc[:stop]
225
309
  if info['pid']
226
310
  stop_cmd = stop_cmd.gsub('$PID', info['pid'].to_s)
@@ -260,11 +344,16 @@ class Hiiro
260
344
  info = running_services[svc_name]
261
345
  pane_id = info['tmux_pane']
262
346
  session = info['tmux_session']
347
+ window = info['tmux_window']
263
348
 
264
349
  if session
265
350
  system('tmux', 'switch-client', '-t', session)
266
351
  end
267
352
 
353
+ if window
354
+ system('tmux', 'select-window', '-t', window)
355
+ end
356
+
268
357
  if pane_id
269
358
  system('tmux', 'select-pane', '-t', pane_id)
270
359
  end
@@ -398,8 +487,6 @@ class Hiiro
398
487
 
399
488
  tmux_info = {
400
489
  session: ENV['TMUX'] ? `tmux display-message -p '#S'`.chomp : nil,
401
- window: ENV['TMUX'] ? `tmux display-message -p '#I'`.chomp : nil,
402
- pane: ENV['TMUX_PANE'],
403
490
  }
404
491
 
405
492
  task_info = {}
@@ -433,6 +520,19 @@ class Hiiro
433
520
  sm.stop(svc_name)
434
521
  end
435
522
 
523
+ h.add_subcmd(:reset) do |svc_name=nil|
524
+ unless svc_name
525
+ puts "Usage: service reset <name>"
526
+ next
527
+ end
528
+
529
+ sm.reset(svc_name)
530
+ end
531
+
532
+ h.add_subcmd(:clean) do
533
+ sm.clean
534
+ end
535
+
436
536
  h.add_subcmd(:attach) do |svc_name=nil|
437
537
  unless svc_name
438
538
  puts "Usage: service attach <name>"
@@ -499,8 +599,7 @@ class Hiiro
499
599
  'host' => 'localhost',
500
600
  'port' => '',
501
601
  'init' => [],
502
- 'start' => '',
503
- 'stop' => '',
602
+ 'start' => [''],
504
603
  'cleanup' => [],
505
604
  }
506
605
 
@@ -606,6 +705,45 @@ class Hiiro
606
705
 
607
706
  private
608
707
 
708
+ def stale_pane?(pane_id)
709
+ return true unless pane_id
710
+ !system('tmux', 'has-session', '-t', pane_id, [:out, :err] => '/dev/null')
711
+ end
712
+
713
+ def write_start_script(svc_name, cmds, base_dir)
714
+ dir = File.join(STATE_DIR, 'scripts')
715
+ FileUtils.mkdir_p(dir)
716
+ path = File.join(dir, "#{svc_name}.sh")
717
+
718
+ lines = ["#!/usr/bin/env bash", "set -e"]
719
+ lines << "cd #{base_dir}" if base_dir
720
+ lines.concat(cmds)
721
+
722
+ File.write(path, lines.join("\n") + "\n")
723
+ File.chmod(0755, path)
724
+ path
725
+ end
726
+
727
+ def current_tmux_session
728
+ return nil unless ENV['TMUX']
729
+ `tmux display-message -p '#S'`.chomp
730
+ end
731
+
732
+ def create_tmux_window(session, name, start_dir)
733
+ system('tmux', 'new-window', '-d', '-t', session, '-n', name, '-c', start_dir)
734
+ "#{session}:#{name}"
735
+ end
736
+
737
+ def capture_pane_id(window_target)
738
+ `tmux list-panes -t #{window_target} -F '\#{pane_id}'`.chomp.split("\n").last
739
+ end
740
+
741
+ def split_tmux_pane(window_target, start_dir)
742
+ system('tmux', 'split-window', '-d', '-t', window_target, '-c', start_dir)
743
+ system('tmux', 'select-layout', '-t', window_target, 'even-vertical')
744
+ `tmux list-panes -t #{window_target} -F '\#{pane_id}'`.chomp.split("\n").last
745
+ end
746
+
609
747
  def load_config
610
748
  return {} unless File.exist?(config_file)
611
749
  YAML.safe_load_file(config_file, permitted_classes: [Symbol]) || {}
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.150"
2
+ VERSION = "0.1.152"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiiro
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.150
4
+ version: 0.1.152
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota