hiiro 0.1.152 → 0.1.154

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: ca8a2bc3e8f629e23986cd1f75bdcca6fc2cd0aaabf85fbde2ae00e721077178
4
- data.tar.gz: 1bfc80f8f3f0844bbc943c23f48258577f7d3b7cea66dd48319893e7f3289aa7
3
+ metadata.gz: a2fdf896084fbec37ad190f81188a0e470aaf30c491acb77df209e3b6d3da6cf
4
+ data.tar.gz: 3310a848c676685907bec54adba6b2eb76be56a811cf73f1dd56fb4a3953ddd7
5
5
  SHA512:
6
- metadata.gz: 05dfbdf2fdef32ec3471b8f26efefc26f07b171b0886c6f9beb55ea7008218165cc126f762cd1ef5e391511815b42eb479aa0dcdff9cc5831b885a8c4ea15b52
7
- data.tar.gz: b9645c6341b3cf753d209b7fcac576264788156a646042a5601d4e4f1269478fd87ab8d93024448ad2ce8eb410d01cd7cd410c26d20f0ebd71007967f6f6a028
6
+ metadata.gz: 85fe854d98a6ffa72e9df07b3816bd8a0e20ca044667afabefd8cd5918264804b8d92f85c464301aaf3275be71ba410399ab27499473ffb3b4b163e872040bff
7
+ data.tar.gz: 0ea45cfd61f388f051c50eca1fc6a7f1f46039cd56f6129dc03b12e5a93ad952298225d18ea0cb078aabea04f78fcf4e27ae6662d54abeb45bdaa9ffd0dba590
data/README.md CHANGED
@@ -241,3 +241,118 @@ bundle exec rake test
241
241
  ## License
242
242
 
243
243
  MIT
244
+
245
+
246
+ # COMPLEX SERVICES
247
+
248
+ ```sh
249
+
250
+ ❯ in this setup...can you configure a couple complex services that use variations, etc. i need examples of how to configure it. and then can you show me how to run it for different variations
251
+
252
+ ⏺ Here's an example ~/.config/hiiro/services.yml:
253
+
254
+ # Individual services
255
+ api-rails:
256
+ base_dir: ~/work/api
257
+ host: localhost
258
+ port: 3000
259
+ init:
260
+ - bundle install
261
+ start:
262
+ - bin/rails s -p 3000
263
+ cleanup: []
264
+ env_file: .env.development
265
+ base_env: api-rails.env
266
+ env_vars:
267
+ DATABASE_URL:
268
+ variations:
269
+ local: postgres://localhost:5432/api_dev
270
+ docker: postgres://db:5432/api_dev
271
+ REDIS_URL:
272
+ variations:
273
+ local: redis://localhost:6379
274
+ docker: redis://redis:6379
275
+
276
+ graphql:
277
+ base_dir: ~/work/graphql
278
+ host: localhost
279
+ port: 4000
280
+ init:
281
+ - npm install
282
+ start:
283
+ - npm run dev
284
+ env_file: .env.local
285
+ base_env: graphql.env
286
+ env_vars:
287
+ API_URL:
288
+ variations:
289
+ local: http://localhost:3000
290
+ staging: https://api.staging.example.com
291
+ AUTH_PROVIDER:
292
+ variations:
293
+ local: http://localhost:8080/auth
294
+ staging: https://auth.staging.example.com
295
+
296
+ frontend:
297
+ base_dir: ~/work/frontend
298
+ host: localhost
299
+ port: 8080
300
+ start:
301
+ - npm run dev
302
+ env_file: .env.local
303
+ base_env: frontend.env
304
+ env_vars:
305
+ GRAPHQL_URL:
306
+ variations:
307
+ local: http://localhost:4000/graphql
308
+ staging: https://graphql.staging.example.com/graphql
309
+
310
+ # Service groups
311
+ full-stack:
312
+ services:
313
+ - name: api-rails
314
+ use:
315
+ DATABASE_URL: local
316
+ REDIS_URL: local
317
+ - name: graphql
318
+ use:
319
+ API_URL: local
320
+ AUTH_PROVIDER: local
321
+ - name: frontend
322
+ use:
323
+ GRAPHQL_URL: local
324
+
325
+ staging-fe:
326
+ services:
327
+ - name: graphql
328
+ use:
329
+ API_URL: staging
330
+ AUTH_PROVIDER: staging
331
+ - name: frontend
332
+ use:
333
+ GRAPHQL_URL: local
334
+
335
+ Usage:
336
+
337
+ # Start a single service (defaults to "local" variations)
338
+ h service start api-rails
339
+
340
+ # Start with specific variations
341
+ h service start api-rails --use DATABASE_URL=docker --use REDIS_URL=docker
342
+
343
+ # Start the full local stack (one window, 3 split panes)
344
+ h service start full-stack
345
+
346
+ # Start frontend pointing at staging backends
347
+ h service start staging-fe
348
+
349
+ # No args — fuzzy select from all services + groups
350
+ h service start
351
+
352
+ The key ideas:
353
+ - local is the default variation — if you don't pass --use, each env var gets its local value
354
+ - Groups let you pre-bake variation combos — full-stack vs staging-fe are just different use: presets for the same services
355
+ - Base env templates live in ~/.config/hiiro/env_templates/ (e.g., api-rails.env) — they get copied to base_dir/env_file first, then variations are injected on top
356
+
357
+
358
+ ```
@@ -50,50 +50,15 @@ class Hiiro
50
50
  svc = find_service(svc_name)
51
51
  return unless svc
52
52
 
53
- env_vars = svc[:env_vars]
54
- return unless env_vars || svc[:base_env]
55
-
56
53
  base_dir = svc[:base_dir]
57
- env_file = svc[:env_file]
58
- base_env = svc[:base_env]
59
-
60
- # Copy base env template if configured
61
- if base_env && env_file && base_dir
62
- src = File.join(ENV_TEMPLATES_DIR, base_env)
63
- dest = File.join(base_dir, env_file)
64
- if File.exist?(src)
65
- FileUtils.mkdir_p(File.dirname(dest))
66
- FileUtils.cp(src, dest)
67
- end
68
- end
69
-
70
- # Inject variation values into env file
71
- return unless env_vars && env_file && base_dir
54
+ return unless base_dir
72
55
 
73
- dest = File.join(base_dir, env_file)
74
- lines = File.exist?(dest) ? File.readlines(dest) : []
75
-
76
- env_vars.each do |var_name, var_config|
77
- next unless var_config.is_a?(Hash) && var_config['variations']
78
-
79
- variation = (variation_overrides[var_name] || variation_overrides[var_name.to_sym] || 'local').to_s
80
- value = var_config['variations'][variation]
81
- next unless value
56
+ env_file_configs = build_env_file_configs(svc)
57
+ return if env_file_configs.empty?
82
58
 
83
- # Replace existing line or append
84
- replaced = false
85
- lines.map! do |line|
86
- if line.match?(/\A#{Regexp.escape(var_name)}=/)
87
- replaced = true
88
- "#{var_name}=#{value}\n"
89
- else
90
- line
91
- end
92
- end
93
- lines << "#{var_name}=#{value}\n" unless replaced
59
+ env_file_configs.each do |efc|
60
+ prepare_single_env(base_dir, efc, variation_overrides)
94
61
  end
95
-
96
- File.write(dest, lines.join)
97
62
  end
98
63
 
99
64
  def start_group(name, tmux_info: {}, task_info: {})
@@ -131,8 +96,6 @@ class Hiiro
131
96
  member_name = member['name'] || member[:name]
132
97
  use_overrides = member['use'] || member[:use] || {}
133
98
 
134
- prepare_env(member_name, variation_overrides: use_overrides)
135
-
136
99
  svc = find_service(member_name)
137
100
  next unless svc
138
101
 
@@ -152,7 +115,7 @@ class Hiiro
152
115
  pane: pane_id,
153
116
  )
154
117
 
155
- start(member_name, tmux_info: member_tmux_info, task_info: task_info, skip_env: true, skip_window_creation: true)
118
+ start(member_name, tmux_info: member_tmux_info, task_info: task_info, variation_overrides: use_overrides, skip_window_creation: true)
156
119
  end
157
120
  true
158
121
  end
@@ -219,11 +182,6 @@ class Hiiro
219
182
  return false
220
183
  end
221
184
 
222
- # Prepare env file unless already handled by start_group
223
- unless skip_env
224
- prepare_env(svc_name, variation_overrides: variation_overrides)
225
- end
226
-
227
185
  # Run init commands
228
186
  if svc[:init]
229
187
  svc[:init].each do |cmd|
@@ -236,6 +194,11 @@ class Hiiro
236
194
  end
237
195
  end
238
196
 
197
+ # Prepare env files after init (e.g., init may install deps that generate .env templates)
198
+ unless skip_env
199
+ prepare_env(svc_name, variation_overrides: variation_overrides)
200
+ end
201
+
239
202
  # Start the service
240
203
  start_cmd = svc[:start]
241
204
  unless start_cmd
@@ -248,7 +211,7 @@ class Hiiro
248
211
  session = tmux_info[:session] || current_tmux_session
249
212
 
250
213
  # Write start commands to an executable tempfile
251
- script = write_start_script(svc_name, start_cmds, base_dir)
214
+ script = write_start_script(svc_name, start_cmds)
252
215
 
253
216
  if session && !skip_window_creation
254
217
  # Create a new tmux window for this service
@@ -265,6 +228,8 @@ class Hiiro
265
228
 
266
229
  if pane_id
267
230
  system('tmux', 'send-keys', '-t', pane_id, script, 'Enter')
231
+ elsif base_dir
232
+ system("cd #{base_dir} && #{script} &")
268
233
  else
269
234
  system("#{script} &")
270
235
  end
@@ -469,8 +434,13 @@ class Hiiro
469
434
 
470
435
  h.add_subcmd(:start) do |svc_name=nil, *extra_args|
471
436
  unless svc_name
472
- puts "Usage: service start <name> [--use VAR=variation ...]"
473
- next
437
+ all = sm.services.keys
438
+ if all.empty?
439
+ puts "No services configured"
440
+ next
441
+ end
442
+ svc_name = h.fuzzyfind(all)
443
+ next unless svc_name
474
444
  end
475
445
 
476
446
  # Parse --use flags from extra_args
@@ -513,8 +483,13 @@ class Hiiro
513
483
 
514
484
  h.add_subcmd(:stop) do |svc_name=nil|
515
485
  unless svc_name
516
- puts "Usage: service stop <name>"
517
- next
486
+ running = sm.running_services.keys
487
+ if running.empty?
488
+ puts "No running services"
489
+ next
490
+ end
491
+ svc_name = h.fuzzyfind(running)
492
+ next unless svc_name
518
493
  end
519
494
 
520
495
  sm.stop(svc_name)
@@ -522,8 +497,13 @@ class Hiiro
522
497
 
523
498
  h.add_subcmd(:reset) do |svc_name=nil|
524
499
  unless svc_name
525
- puts "Usage: service reset <name>"
526
- next
500
+ running = sm.running_services.keys
501
+ if running.empty?
502
+ puts "No running services"
503
+ next
504
+ end
505
+ svc_name = h.fuzzyfind(running)
506
+ next unless svc_name
527
507
  end
528
508
 
529
509
  sm.reset(svc_name)
@@ -535,8 +515,13 @@ class Hiiro
535
515
 
536
516
  h.add_subcmd(:attach) do |svc_name=nil|
537
517
  unless svc_name
538
- puts "Usage: service attach <name>"
539
- next
518
+ running = sm.running_services.keys
519
+ if running.empty?
520
+ puts "No running services"
521
+ next
522
+ end
523
+ svc_name = h.fuzzyfind(running)
524
+ next unless svc_name
540
525
  end
541
526
 
542
527
  sm.attach(svc_name)
@@ -586,8 +571,13 @@ class Hiiro
586
571
 
587
572
  h.add_subcmd(:status) do |svc_name=nil|
588
573
  unless svc_name
589
- puts "Usage: service status <name>"
590
- next
574
+ running = sm.running_services.keys
575
+ if running.empty?
576
+ puts "No running services"
577
+ next
578
+ end
579
+ svc_name = h.fuzzyfind(running)
580
+ next unless svc_name
591
581
  end
592
582
 
593
583
  sm.status(svc_name)
@@ -601,6 +591,9 @@ class Hiiro
601
591
  'init' => [],
602
592
  'start' => [''],
603
593
  'cleanup' => [],
594
+ 'env_files' => [
595
+ { 'env_file' => '.env', 'base_env' => '', 'env_vars' => {} },
596
+ ],
604
597
  }
605
598
 
606
599
  require 'tempfile'
@@ -675,29 +668,30 @@ class Hiiro
675
668
  next
676
669
  end
677
670
 
678
- env_vars = svc[:env_vars]
679
- unless env_vars
680
- puts "No env_vars configured for '#{svc[:name]}'"
671
+ configs = sm.send(:build_env_file_configs, svc)
672
+ if configs.empty?
673
+ puts "No env files configured for '#{svc[:name]}'"
681
674
  next
682
675
  end
683
676
 
684
- puts "Env vars for '#{svc[:name]}':"
685
- puts
686
- env_vars.each do |var_name, var_config|
687
- next unless var_config.is_a?(Hash) && var_config['variations']
677
+ puts "Env files for '#{svc[:name]}':"
678
+ configs.each do |efc|
679
+ puts
680
+ puts " #{efc[:env_file] || '(no dest)'}"
681
+ puts " template: #{efc[:base_env]}" if efc[:base_env]
688
682
 
689
- puts " #{var_name}:"
690
- var_config['variations'].each do |variation, value|
691
- puts " #{variation}: #{value}"
692
- end
693
- end
683
+ env_vars = efc[:env_vars]
684
+ next unless env_vars
694
685
 
695
- if svc[:base_env]
696
- puts
697
- puts "Base env template: #{svc[:base_env]}"
698
- end
699
- if svc[:env_file]
700
- puts "Env file: #{svc[:env_file]}"
686
+ env_vars.each do |var_name, var_config|
687
+ variations = var_config.is_a?(Hash) && (var_config['variations'] || var_config[:variations])
688
+ next unless variations
689
+
690
+ puts " #{var_name}:"
691
+ variations.each do |variation, value|
692
+ puts " #{variation}: #{value}"
693
+ end
694
+ end
701
695
  end
702
696
  end
703
697
  end
@@ -705,18 +699,74 @@ class Hiiro
705
699
 
706
700
  private
707
701
 
702
+ # Normalize env file config into an array of hashes,
703
+ # supporting both old single-env format and new env_files array
704
+ def build_env_file_configs(svc)
705
+ if svc[:env_files]
706
+ Array(svc[:env_files]).map { |ef| symbolize_keys(ef.is_a?(Hash) ? ef : {}) }
707
+ elsif svc[:env_file] || svc[:base_env] || svc[:env_vars]
708
+ [{ env_file: svc[:env_file], base_env: svc[:base_env], env_vars: svc[:env_vars] }]
709
+ else
710
+ []
711
+ end
712
+ end
713
+
714
+ def prepare_single_env(base_dir, efc, variation_overrides)
715
+ env_file = efc[:env_file]
716
+ base_env = efc[:base_env]
717
+ env_vars = efc[:env_vars]
718
+
719
+ # Copy base env template if configured
720
+ if base_env && env_file
721
+ src = File.join(ENV_TEMPLATES_DIR, base_env)
722
+ dest = File.join(base_dir, env_file)
723
+ if File.exist?(src)
724
+ FileUtils.mkdir_p(File.dirname(dest))
725
+ FileUtils.cp(src, dest)
726
+ end
727
+ end
728
+
729
+ # Inject variation values into env file
730
+ return unless env_vars && env_file
731
+
732
+ dest = File.join(base_dir, env_file)
733
+ lines = File.exist?(dest) ? File.readlines(dest) : []
734
+
735
+ env_vars.each do |var_name, var_config|
736
+ var_config = symbolize_keys(var_config) if var_config.is_a?(Hash)
737
+ variations = var_config.is_a?(Hash) && (var_config[:variations] || var_config['variations'])
738
+ next unless variations
739
+
740
+ variation = (variation_overrides[var_name] || variation_overrides[var_name.to_sym] || 'local').to_s
741
+ value = variations[variation]
742
+ next unless value
743
+
744
+ replaced = false
745
+ lines.map! do |line|
746
+ if line.match?(/\A#{Regexp.escape(var_name.to_s)}=/)
747
+ replaced = true
748
+ "#{var_name}=#{value}\n"
749
+ else
750
+ line
751
+ end
752
+ end
753
+ lines << "#{var_name}=#{value}\n" unless replaced
754
+ end
755
+
756
+ File.write(dest, lines.join)
757
+ end
758
+
708
759
  def stale_pane?(pane_id)
709
760
  return true unless pane_id
710
761
  !system('tmux', 'has-session', '-t', pane_id, [:out, :err] => '/dev/null')
711
762
  end
712
763
 
713
- def write_start_script(svc_name, cmds, base_dir)
764
+ def write_start_script(svc_name, cmds)
714
765
  dir = File.join(STATE_DIR, 'scripts')
715
766
  FileUtils.mkdir_p(dir)
716
767
  path = File.join(dir, "#{svc_name}.sh")
717
768
 
718
769
  lines = ["#!/usr/bin/env bash", "set -e"]
719
- lines << "cd #{base_dir}" if base_dir
720
770
  lines.concat(cmds)
721
771
 
722
772
  File.write(path, lines.join("\n") + "\n")
data/lib/hiiro/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class Hiiro
2
- VERSION = "0.1.152"
2
+ VERSION = "0.1.154"
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.152
4
+ version: 0.1.154
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Toyota