stable-cli-rails 0.6.7 → 0.6.8

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/stable/cli.rb +111 -42
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d85bcf8eb4e71a8dc2c0bdb7e77fd053f844c81160f5c8cdc4d6fa42194b1275
4
- data.tar.gz: 0465bfad22e484c444f3c0564e54e135d7f2c83e93996af0085e9f3aa8cf1f6a
3
+ metadata.gz: 55e25d45106e712c1d3e9d23754150d9519e34b38d4464652c4c0a21539a0597
4
+ data.tar.gz: a2bb082ffeb11bf916903f7a15cc0da89a5136c33d53b3139038d7d294591f2d
5
5
  SHA512:
6
- metadata.gz: 7dfdd1728588725ffdc0fda92cb367fb53323f5e6683c2c78c2b10a9ce06fef8ca5df494a11868c260f3be12d88021f0d922e88add43b97fd91a32e56432c342
7
- data.tar.gz: e8e9f9cf95140ec1090130c059ebfca7087a2377136bc306a304918d0e35b1e25a3dd4c448cd99cce5a8e0eec22766298586d16ce463f2b28c6de678f1ed8d92
6
+ metadata.gz: 954bb6bd50281fe5a47ed03e2cead5a2c614f7786d17cdc4831c50ab798e0a6fac59dc1b98b76f3d35524be574396813444bbf3d4f60099e7e81b44846658ef4
7
+ data.tar.gz: 275d760d16ce88fb018f3aad059330fd05c63911aa19352b67780bd8d8680d64918583ece7e48e2eb452329c468fff3eaac5a7fdee92341425ff792421646c0b
data/lib/stable/cli.rb CHANGED
@@ -14,6 +14,7 @@ module Stable
14
14
  super
15
15
  Stable::Bootstrap.run!
16
16
  ensure_dependencies!
17
+ dedupe_registry!
17
18
  end
18
19
 
19
20
  def self.exit_on_failure?
@@ -29,24 +30,40 @@ module Stable
29
30
  port ||= next_free_port
30
31
  app_path = File.expand_path(name)
31
32
 
33
+ # --- Add app to registry ---
34
+ domain = "#{name}.test"
35
+ apps = Registry.apps
36
+
37
+ app = {
38
+ name: name,
39
+ path: app_path,
40
+ domain: domain,
41
+ port: port,
42
+ ruby: ruby,
43
+ started_at: nil
44
+ }
45
+
46
+ apps.reject! { |a| a[:name] == name }
47
+ apps << app
48
+
32
49
  abort "Folder already exists: #{app_path}" if File.exist?(app_path)
33
50
 
34
51
  # --- Ensure RVM and Ruby ---
35
52
  ensure_rvm!
36
53
  puts "Using Ruby #{ruby} with RVM gemset #{name}..."
37
- system("bash -lc 'rvm #{ruby}@#{name} --create do true'") or abort('Failed to create RVM gemset')
38
-
54
+ system("bash -lc 'rvm #{ruby}@#{name} --create do true'") or abort("Failed to create RVM gemset #{name}")
55
+ ruby_cmd = rvm_exec(app, ruby)
39
56
  # --- Install Rails in gemset if needed ---
40
57
  rails_version = rails || 'latest'
41
- rails_check = system("bash -lc 'rvm #{ruby}@#{name} do gem list -i rails#{rails ? " -v #{rails}" : ''}'")
58
+ rails_check = system("bash -lc '#{ruby_cmd} gem list -i rails#{rails ? " -v #{rails}" : ''}'")
42
59
  unless rails_check
43
60
  puts "Installing Rails #{rails_version} in gemset..."
44
- system("bash -lc 'rvm #{ruby}@#{name} do gem install rails #{rails ? "-v #{rails}" : ''}'") or abort('Failed to install Rails')
61
+ system("bash -lc '#{ruby_cmd} gem install rails #{rails ? "-v #{rails}" : ''}'") or abort('Failed to install Rails')
45
62
  end
46
63
 
47
64
  # --- Create Rails app ---
48
65
  puts "Creating Rails app #{name} (Ruby #{ruby})..."
49
- system("bash -lc 'rvm #{ruby}@#{name} do rails new #{app_path}'") or abort('Rails app creation failed')
66
+ system("bash -lc '#{ruby_cmd} rails new #{app_path}'") or abort('Rails app creation failed')
50
67
 
51
68
  # --- Add .ruby-version and .ruby-gemset ---
52
69
  Dir.chdir(app_path) do
@@ -55,15 +72,9 @@ module Stable
55
72
 
56
73
  # --- Install gems inside gemset ---
57
74
  puts 'Running bundle install...'
58
- system("bash -lc 'rvm #{ruby}@#{name} do bundle install --jobs=4 --retry=3'") or abort('bundle install failed')
75
+ system("bash -lc '#{ruby_cmd} bundle install --jobs=4 --retry=3'") or abort('bundle install failed')
59
76
  end
60
77
 
61
- # --- Add app to registry ---
62
- domain = "#{name}.test"
63
- apps = Registry.apps
64
- apps << { name: name, path: app_path, domain: domain, port: port, ruby: ruby }
65
- Registry.save(apps)
66
-
67
78
  # --- Host entry & certificate ---
68
79
  add_host_entry(domain)
69
80
  generate_cert(domain) unless options[:skip_ssl]
@@ -76,15 +87,20 @@ module Stable
76
87
  log_file = File.join(app_path, 'log', 'stable.log')
77
88
  FileUtils.mkdir_p(File.dirname(log_file))
78
89
 
90
+ abort "Port #{port} is already in use. Choose another port." if app_running?({ port: port })
91
+
79
92
  pid = spawn(
80
93
  'bash',
81
94
  '-lc',
82
- "cd #{app_path} && rvm #{ruby}@#{name} do bundle exec rails s -p #{port} -b 127.0.0.1",
95
+ "cd #{app_path} && #{ruby_cmd} bundle exec rails s -p #{port} -b 127.0.0.1",
83
96
  out: log_file,
84
97
  err: log_file
85
98
  )
86
99
  Process.detach(pid)
87
100
 
101
+ app[:started_at] = Time.now.to_i
102
+ Registry.save(apps)
103
+
88
104
  sleep 1.5
89
105
 
90
106
  wait_for_port(port)
@@ -111,6 +127,8 @@ module Stable
111
127
  return
112
128
  end
113
129
 
130
+ puts "Detected gemset: #{File.read('.ruby-gemset').strip}" if File.exist?('.ruby-gemset')
131
+
114
132
  apps = Registry.apps
115
133
  name = File.basename(folder)
116
134
  domain = "#{name}.test"
@@ -154,47 +172,54 @@ module Stable
154
172
  desc 'start NAME', 'Start a Rails app with its correct Ruby version'
155
173
  def start(name)
156
174
  app = Registry.apps.find { |a| a[:name] == name }
157
- unless app
158
- puts "No app found with name #{name}"
159
- return
160
- end
175
+ return puts("No app found with name #{name}") unless app
161
176
 
162
177
  port = app[:port] || next_free_port
163
178
  ruby = app[:ruby]
179
+ path = app[:path]
164
180
 
165
- puts "Starting #{name} on port #{port}#{ruby ? " (Ruby #{ruby})" : ''}..."
181
+ if app_running?(app)
182
+ puts "#{name} is already running on https://#{app[:domain]} (port #{port})"
183
+ return
184
+ end
166
185
 
167
- log_file = File.join(app[:path], 'log', 'stable.log')
168
- FileUtils.mkdir_p(File.dirname(log_file))
186
+ gemset = gemset_for(app)
169
187
 
170
- ruby_exec =
171
- if ruby
172
- if rvm_available?
173
- ensure_rvm_ruby!(ruby)
174
- "rvm #{ruby}@#{name} do"
175
- elsif rbenv_available?
176
- ensure_rbenv_ruby!(ruby)
177
- "RBENV_VERSION=#{ruby}"
178
- else
179
- puts 'No Ruby version manager found (rvm or rbenv)'
180
- return
181
- end
188
+ rvm_cmd =
189
+ if ruby && gemset
190
+ system("bash -lc 'rvm #{ruby}@#{gemset} --create do true'")
191
+ "rvm #{ruby}@#{gemset} do"
192
+ elsif ruby
193
+ "rvm #{ruby} do"
182
194
  end
183
195
 
196
+ puts "Starting #{name} on port #{port}..."
197
+
198
+ log_file = File.join(path, 'log', 'stable.log')
199
+ FileUtils.mkdir_p(File.dirname(log_file))
200
+
184
201
  pid = spawn(
185
202
  'bash',
186
203
  '-lc',
187
- "cd #{app[:path]} && rvm #{ruby}@#{name} do bundle exec rails s -p #{port} -b 127.0.0.1",
204
+ <<~CMD,
205
+ cd "#{path}"
206
+ #{rvm_cmd} bundle exec rails s \
207
+ -p #{port} \
208
+ -b 127.0.0.1
209
+ CMD
188
210
  out: log_file,
189
211
  err: log_file
190
212
  )
213
+
191
214
  Process.detach(pid)
192
215
 
193
- sleep 1.5
216
+ wait_for_port(port, timeout: 30)
217
+
218
+ app[:started_at] = Time.now.to_i
219
+ Registry.save(Registry.apps)
194
220
 
195
221
  generate_cert(app[:domain])
196
222
  update_caddyfile(app[:domain], port)
197
- wait_for_port(port)
198
223
  caddy_reload
199
224
 
200
225
  puts "#{name} started on https://#{app[:domain]}"
@@ -254,8 +279,11 @@ module Stable
254
279
  puts "mkcert: #{system('which mkcert > /dev/null') ? 'yes' : 'no'}"
255
280
 
256
281
  Registry.apps.each do |app|
257
- status = port_in_use?(app[:port]) ? 'running' : 'stopped'
258
- puts "#{app[:name]} → Ruby #{app[:ruby] || 'default'} (#{status})"
282
+ state = boot_state(app)
283
+ ruby = app[:ruby] || 'default'
284
+ port = app[:port]
285
+
286
+ puts "#{app[:name]} → Ruby #{ruby} | port #{port} | #{state}"
259
287
  end
260
288
  end
261
289
 
@@ -481,16 +509,17 @@ module Stable
481
509
  end
482
510
  end
483
511
 
484
- def wait_for_port(port, timeout: 30)
512
+ def wait_for_port(port, timeout: 10)
485
513
  require 'socket'
486
- start_time = Time.now
514
+ start = Time.now
515
+
487
516
  loop do
488
517
  TCPSocket.new('127.0.0.1', port).close
489
- break
518
+ return
490
519
  rescue Errno::ECONNREFUSED
491
- raise "Timeout waiting for port #{port}" if Time.now - start_time > timeout
520
+ raise "Rails never bound port #{port}. Check log/stable.log" if Time.now - start > timeout
492
521
 
493
- sleep 0.1
522
+ sleep 0.5
494
523
  end
495
524
  end
496
525
 
@@ -550,5 +579,45 @@ module Stable
550
579
  def ensure_rbenv_ruby!(version)
551
580
  system("rbenv versions | grep -q #{version} || rbenv install #{version}")
552
581
  end
582
+
583
+ def app_running?(app)
584
+ return false unless app && app[:port]
585
+
586
+ system("lsof -i tcp:#{app[:port]} -sTCP:LISTEN > /dev/null 2>&1")
587
+ end
588
+
589
+ def boot_state(app)
590
+ return 'stopped' unless app_running?(app)
591
+
592
+ if app[:started_at]
593
+ elapsed = Time.now.to_i - app[:started_at]
594
+ return "booting (#{elapsed}s)" if elapsed < 10
595
+ end
596
+
597
+ 'running'
598
+ end
599
+
600
+ def dedupe_registry!
601
+ apps = Registry.apps
602
+ apps.uniq! { |a| a[:name] }
603
+ Registry.save(apps)
604
+ end
605
+
606
+ def gemset_for(app)
607
+ gemset_file = File.join(app[:path], '.ruby-gemset')
608
+ return File.read(gemset_file).strip if File.exist?(gemset_file)
609
+
610
+ nil
611
+ end
612
+
613
+ def rvm_exec(app, ruby)
614
+ gemset = gemset_for(app)
615
+
616
+ if gemset
617
+ "rvm #{ruby}@#{gemset} do"
618
+ else
619
+ "rvm #{ruby} do"
620
+ end
621
+ end
553
622
  end
554
623
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stable-cli-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.7
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Simfukwe