mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-06-10 11:16:14 +08:00
182 lines
4.9 KiB
Ruby
Executable file
Vendored
182 lines
4.9 KiB
Ruby
Executable file
Vendored
#!/usr/bin/env ruby
|
|
# frozen_string_literal: true
|
|
|
|
require "pathname"
|
|
require "open3"
|
|
|
|
RAILS_ROOT = File.expand_path("../../", Pathname.new(__FILE__).realpath)
|
|
PORT = ENV["UNICORN_PORT"] ||= "3000"
|
|
HOSTNAME = ENV["DISCOURSE_HOSTNAME"] ||= "127.0.0.1"
|
|
CUSTOM_ARGS = %w[--try --test --build --server --unicorn -u --forward-host]
|
|
PROXY =
|
|
if ARGV.include?("--try")
|
|
"https://try.discourse.org"
|
|
else
|
|
"http://#{HOSTNAME}:#{PORT}"
|
|
end
|
|
|
|
def process_running?(pid)
|
|
!!Process.kill(0, pid)
|
|
rescue Errno::ESRCH
|
|
false
|
|
end
|
|
|
|
def kill_tree(root_pid, signal)
|
|
return unless root_pid
|
|
children = `pgrep -P #{root_pid} 2>/dev/null`.to_s.split.map(&:to_i)
|
|
children.each { |c| kill_tree(c, signal) }
|
|
Process.kill(signal, root_pid)
|
|
rescue Errno::ESRCH, Errno::EPERM
|
|
# already gone
|
|
end
|
|
|
|
command =
|
|
if ARGV.include?("--test")
|
|
"test"
|
|
elsif ARGV.include?("--build")
|
|
"build"
|
|
else
|
|
"server"
|
|
end
|
|
|
|
class String
|
|
def cyan
|
|
"\e[36m#{self}\e[0m"
|
|
end
|
|
|
|
def red
|
|
"\033[31m#{self}\e[0m"
|
|
end
|
|
end
|
|
|
|
if ARGV.include?("-h") || ARGV.include?("--help")
|
|
puts "ember-cli OPTIONS"
|
|
puts "#{"--try".cyan} To proxy try.discourse.org"
|
|
puts "#{"--test".cyan} To run the test suite"
|
|
puts "#{"--server, -u".cyan} To run a server as well"
|
|
puts "The rest of the arguments are passed to ember server per:", ""
|
|
exec "pnpm ember #{command} --help"
|
|
end
|
|
|
|
args = ["--dir=frontend/discourse", "ember", command] + (ARGV - CUSTOM_ARGS)
|
|
|
|
if !args.include?("test") && !args.include?("build") && !args.include?("--proxy")
|
|
args << "--proxy"
|
|
args << PROXY
|
|
end
|
|
|
|
node_modules_outdated =
|
|
begin
|
|
File.read("node_modules/.pnpm/lock.yaml") != File.read("pnpm-lock.yaml")
|
|
rescue Errno::ENOENT
|
|
true
|
|
end
|
|
|
|
if node_modules_outdated
|
|
puts "[bin/ember-cli] Detected outdated or missing node_modules. Running pnpm install..."
|
|
|
|
if !system "pnpm", "--dir=#{RAILS_ROOT}", "install"
|
|
if !system("command -v pnpm >/dev/null;")
|
|
abort "pnpm is not installed. run `npm install -g pnpm`"
|
|
end
|
|
exit 1
|
|
end
|
|
end
|
|
|
|
pnpm_env = {
|
|
"TERM" => "dumb", # simple output from ember-cli, so we can parse/forward it more easily
|
|
}
|
|
pnpm_env["FORWARD_HOST"] = "true" if ARGV.include?("--forward-host")
|
|
|
|
if ARGV.include?("-u") || ARGV.include?("--server") || ARGV.include?("--unicorn")
|
|
server_env = { "DISCOURSE_PORT" => ENV["DISCOURSE_PORT"] || "4200" }
|
|
|
|
if command == "server" && ENV["CODESPACE_NAME"]
|
|
server_env.merge!(
|
|
{
|
|
"DISCOURSE_PORT" => "443",
|
|
"DISCOURSE_FORCE_HTTPS" => "1",
|
|
"DISCOURSE_FORCE_HOSTNAME" =>
|
|
"#{ENV["CODESPACE_NAME"]}-4200.#{ENV["GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN"]}",
|
|
},
|
|
)
|
|
end
|
|
|
|
# Own process group so terminal Ctrl+C only hits bin/ember-cli.
|
|
# The INT trap below is the only signaller.
|
|
server_pid = spawn(server_env, "#{__dir__}/pitchfork", pgroup: true)
|
|
ember_cli_pid = nil
|
|
sigint_received = false
|
|
|
|
Thread.new do
|
|
Open3.popen2e(pnpm_env, "pnpm", *args.to_a.flatten) do |i, oe, t|
|
|
ember_cli_pid = t.pid
|
|
puts "Ember CLI running on PID: #{ember_cli_pid}"
|
|
oe.each do |line|
|
|
if line.include?("\e[32m200\e") || line.include?("\e[36m304\e[0m") ||
|
|
line.include?("POST /message-bus")
|
|
# skip 200s and 304s and message bus
|
|
else
|
|
puts "[ember-cli] #{line}"
|
|
end
|
|
end
|
|
end
|
|
# On Ctrl+C the INT trap already TERMs the server. Only do it here if
|
|
# ember-cli exited on its own.
|
|
if !sigint_received && process_running?(server_pid)
|
|
puts "[bin/ember-cli] ember-cli process stopped. Terminating server."
|
|
Process.kill("TERM", server_pid)
|
|
end
|
|
end
|
|
|
|
int_count = 0
|
|
trap("INT") do
|
|
sigint_received = true
|
|
int_count += 1
|
|
|
|
if int_count == 1
|
|
# TERM the supervisor. Its trap forwards to the master, which gracefully
|
|
# stops workers and Demon::Sidekiq.
|
|
begin
|
|
Process.kill("TERM", server_pid)
|
|
rescue StandardError
|
|
nil
|
|
end
|
|
|
|
if ember_cli_pid
|
|
begin
|
|
Process.kill("TERM", ember_cli_pid)
|
|
rescue StandardError
|
|
nil
|
|
end
|
|
end
|
|
|
|
# If shutdown drags, show the force-quit option.
|
|
Thread.new do
|
|
sleep 2
|
|
if process_running?(server_pid)
|
|
puts "\n[bin/ember-cli] Shutting down... press Ctrl+C again to force quit."
|
|
end
|
|
end
|
|
else
|
|
puts "\n[bin/ember-cli] Forcing shutdown..."
|
|
# Catch orphans (e.g. stuck sidekiq).
|
|
kill_tree(server_pid, "KILL")
|
|
kill_tree(ember_cli_pid, "KILL") if ember_cli_pid
|
|
exit!(1)
|
|
end
|
|
end
|
|
|
|
Process.wait(server_pid)
|
|
|
|
# Drain pgroup so shutdown messages don't print after the exit.
|
|
deadline = Time.now + 10
|
|
sleep 0.05 while Time.now < deadline && !`pgrep -g #{server_pid} 2>/dev/null`.strip.empty?
|
|
|
|
if ember_cli_pid && process_running?(ember_cli_pid)
|
|
puts "[bin/ember-cli] server process stopped. Terminating ember-cli."
|
|
Process.kill("TERM", ember_cli_pid)
|
|
end
|
|
else
|
|
exec(pnpm_env, "pnpm", *args.to_a.flatten)
|
|
end
|