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.
- checksums.yaml +4 -4
- data/lib/stable/cli.rb +119 -45
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55e25d45106e712c1d3e9d23754150d9519e34b38d4464652c4c0a21539a0597
|
|
4
|
+
data.tar.gz: a2bb082ffeb11bf916903f7a15cc0da89a5136c33d53b3139038d7d294591f2d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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(
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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 '
|
|
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
|
-
|
|
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
|
-
|
|
181
|
+
if app_running?(app)
|
|
182
|
+
puts "#{name} is already running on https://#{app[:domain]} (port #{port})"
|
|
183
|
+
return
|
|
184
|
+
end
|
|
157
185
|
|
|
158
|
-
|
|
159
|
-
FileUtils.mkdir_p(File.dirname(log_file))
|
|
186
|
+
gemset = gemset_for(app)
|
|
160
187
|
|
|
161
|
-
|
|
162
|
-
if ruby
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
-
|
|
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
|
-
|
|
253
|
-
|
|
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:
|
|
512
|
+
def wait_for_port(port, timeout: 10)
|
|
480
513
|
require 'socket'
|
|
481
|
-
|
|
514
|
+
start = Time.now
|
|
515
|
+
|
|
482
516
|
loop do
|
|
483
517
|
TCPSocket.new('127.0.0.1', port).close
|
|
484
|
-
|
|
518
|
+
return
|
|
485
519
|
rescue Errno::ECONNREFUSED
|
|
486
|
-
raise "
|
|
520
|
+
raise "Rails never bound port #{port}. Check log/stable.log" if Time.now - start > timeout
|
|
487
521
|
|
|
488
|
-
sleep 0.
|
|
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
|