stable-cli-rails 0.6.6 → 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 +119 -45
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c4c6a2df62447b539c1212d98c64f9cb33744454933fac73b9c86a763c951ac
4
- data.tar.gz: 9a2f9cd59e224a67013a32351ec2bea6fda1097e01abd509594192b9648cbfa5
3
+ metadata.gz: 55e25d45106e712c1d3e9d23754150d9519e34b38d4464652c4c0a21539a0597
4
+ data.tar.gz: a2bb082ffeb11bf916903f7a15cc0da89a5136c33d53b3139038d7d294591f2d
5
5
  SHA512:
6
- metadata.gz: 2fc9bcdc91837698b3127d656bf9837e358acb42704f71d6047d7bcbae0fdc3b14e442a7896eb34a9ca83f64cc3d3ea33295b46a478e1a62fd277f22c627d10c
7
- data.tar.gz: 37a0545468ad7e1f2ca46e8e5039df4af1ecd71cee8b6d1eaaef9b6ad279969dd4bcc00abb050356113aae458229855c37ebccc8f81e1985aa09a1d9a79c8b10
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]
@@ -75,9 +86,23 @@ module Stable
75
86
  puts "Starting Rails server for #{name} on port #{port}..."
76
87
  log_file = File.join(app_path, 'log', 'stable.log')
77
88
  FileUtils.mkdir_p(File.dirname(log_file))
78
- pid = spawn("bash -lc 'rvm #{ruby}@#{name} do cd #{app_path} && bundle exec rails s -p #{port} >> #{log_file} 2>&1'")
89
+
90
+ abort "Port #{port} is already in use. Choose another port." if app_running?({ port: port })
91
+
92
+ pid = spawn(
93
+ 'bash',
94
+ '-lc',
95
+ "cd #{app_path} && #{ruby_cmd} bundle exec rails s -p #{port} -b 127.0.0.1",
96
+ out: log_file,
97
+ err: log_file
98
+ )
79
99
  Process.detach(pid)
80
100
 
101
+ app[:started_at] = Time.now.to_i
102
+ Registry.save(apps)
103
+
104
+ sleep 1.5
105
+
81
106
  wait_for_port(port)
82
107
  puts "✔ #{name} running at https://#{domain}"
83
108
  end
@@ -102,6 +127,8 @@ module Stable
102
127
  return
103
128
  end
104
129
 
130
+ puts "Detected gemset: #{File.read('.ruby-gemset').strip}" if File.exist?('.ruby-gemset')
131
+
105
132
  apps = Registry.apps
106
133
  name = File.basename(folder)
107
134
  domain = "#{name}.test"
@@ -145,51 +172,54 @@ module Stable
145
172
  desc 'start NAME', 'Start a Rails app with its correct Ruby version'
146
173
  def start(name)
147
174
  app = Registry.apps.find { |a| a[:name] == name }
148
- unless app
149
- puts "No app found with name #{name}"
150
- return
151
- end
175
+ return puts("No app found with name #{name}") unless app
152
176
 
153
177
  port = app[:port] || next_free_port
154
178
  ruby = app[:ruby]
179
+ path = app[:path]
155
180
 
156
- 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
157
185
 
158
- log_file = File.join(app[:path], 'log', 'stable.log')
159
- FileUtils.mkdir_p(File.dirname(log_file))
186
+ gemset = gemset_for(app)
160
187
 
161
- ruby_exec =
162
- if ruby
163
- if rvm_available?
164
- ensure_rvm_ruby!(ruby)
165
- "rvm #{ruby}@#{name} do"
166
- elsif rbenv_available?
167
- ensure_rbenv_ruby!(ruby)
168
- "RBENV_VERSION=#{ruby}"
169
- else
170
- puts 'No Ruby version manager found (rvm or rbenv)'
171
- return
172
- 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"
173
194
  end
174
195
 
175
- cmd = <<~CMD
176
- cd #{app[:path]} &&
177
- #{ruby_exec} bundle exec rails s -p #{port}
178
- CMD
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))
179
200
 
180
201
  pid = spawn(
181
202
  'bash',
182
203
  '-lc',
183
- cmd,
204
+ <<~CMD,
205
+ cd "#{path}"
206
+ #{rvm_cmd} bundle exec rails s \
207
+ -p #{port} \
208
+ -b 127.0.0.1
209
+ CMD
184
210
  out: log_file,
185
211
  err: log_file
186
212
  )
187
213
 
188
214
  Process.detach(pid)
189
215
 
216
+ wait_for_port(port, timeout: 30)
217
+
218
+ app[:started_at] = Time.now.to_i
219
+ Registry.save(Registry.apps)
220
+
190
221
  generate_cert(app[:domain])
191
222
  update_caddyfile(app[:domain], port)
192
- wait_for_port(port)
193
223
  caddy_reload
194
224
 
195
225
  puts "#{name} started on https://#{app[:domain]}"
@@ -249,8 +279,11 @@ module Stable
249
279
  puts "mkcert: #{system('which mkcert > /dev/null') ? 'yes' : 'no'}"
250
280
 
251
281
  Registry.apps.each do |app|
252
- status = port_in_use?(app[:port]) ? 'running' : 'stopped'
253
- 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}"
254
287
  end
255
288
  end
256
289
 
@@ -476,16 +509,17 @@ module Stable
476
509
  end
477
510
  end
478
511
 
479
- def wait_for_port(port, timeout: 5)
512
+ def wait_for_port(port, timeout: 10)
480
513
  require 'socket'
481
- start_time = Time.now
514
+ start = Time.now
515
+
482
516
  loop do
483
517
  TCPSocket.new('127.0.0.1', port).close
484
- break
518
+ return
485
519
  rescue Errno::ECONNREFUSED
486
- 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
487
521
 
488
- sleep 0.1
522
+ sleep 0.5
489
523
  end
490
524
  end
491
525
 
@@ -545,5 +579,45 @@ module Stable
545
579
  def ensure_rbenv_ruby!(version)
546
580
  system("rbenv versions | grep -q #{version} || rbenv install #{version}")
547
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
548
622
  end
549
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.6
4
+ version: 0.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danny Simfukwe