forked from rails/rails
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes rails#52459 The current default `bin/dev` execs the Rails server directly and doesn't support Procfiles. Therefore, gems like `jsbundling-rails`, `tailwindcss-rails`, and soon `solid_queue` need to overwrite the `bin/dev` script with their own version. With this new version, gems can skip overwriting the `bin/dev` script and add to the Procfile instead. It spawns Foreman in the background to allow breakpoints in the Rails process without Foreman eating the inputs or interleaving its output.
- Loading branch information
Showing
2 changed files
with
128 additions
and
1 deletion.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
railties/lib/rails/commands/devserver/devserver_command.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# frozen_string_literal: true | ||
|
||
module Rails | ||
module Command | ||
class DevserverCommand < Base # :nodoc: | ||
DEFAULT_PORT = 3000 | ||
PROCFILE = "Procfile.dev" | ||
|
||
class_option :verbose, aliases: "-v", type: :boolean, default: false, | ||
desc: "Show all process outputs." | ||
option :port, aliases: "-p", type: :numeric, | ||
desc: "Run Rails on the specified port - defaults to 3000.", banner: :port | ||
|
||
desc "devserver", "Start everything" | ||
def perform | ||
exec_rails unless procfile_exists? | ||
|
||
Signal.trap("INT") { } | ||
|
||
install_foreman | ||
|
||
begin | ||
start_foreman | ||
start_rails | ||
ensure | ||
stop | ||
end | ||
end | ||
|
||
private | ||
attr_reader :foreman_pgid, :pid | ||
|
||
def start_foreman | ||
@foreman_pgid = | ||
Process.spawn( | ||
env, | ||
*%W(foreman start -f Procfile.dev -m all=1,web=0 --env /dev/null), | ||
in: "/dev/null", | ||
out: (verbose ? STDOUT : "/dev/null"), | ||
err: (verbose ? STDOUT : "/dev/null"), | ||
pgroup: true, | ||
).then(&Process.method(:getpgid)) | ||
end | ||
|
||
def install_foreman | ||
if system(env, *%w(gem list --no-installed --exact --silent foreman)) | ||
puts "Installing foreman..." | ||
system(env, *%w(gem install foreman)) | ||
end | ||
end | ||
|
||
def start_rails | ||
@pid = Process.spawn(*%W(bundle exec rails server --port=#{port})) | ||
Process.wait(pid) | ||
@pid = false | ||
end | ||
|
||
def exec_rails | ||
Process.exec(env, *%W(bundle exec rails server --port=#{port})) | ||
end | ||
|
||
def stop | ||
Process.kill("INT", -foreman_pgid) if foreman_pgid | ||
Process.wait(-foreman_pgid) if foreman_pgid | ||
|
||
begin | ||
Process.kill("KILL", pid) if pid | ||
rescue Errno::ESRCH | ||
end | ||
end | ||
|
||
def procfile_exists? | ||
File.exist?(Rails::Command.application_root.join(PROCFILE)) | ||
end | ||
|
||
def env | ||
{ | ||
"BUNDLER_SETUP" => nil, | ||
"RUBYOPT" => nil, | ||
} | ||
end | ||
|
||
def verbose | ||
options[:verbose] | ||
end | ||
|
||
def port | ||
options[:port] || ENV.fetch("PORT", DEFAULT_PORT).to_i | ||
end | ||
end | ||
end | ||
end |
37 changes: 36 additions & 1 deletion
37
railties/lib/rails/generators/rails/app/templates/bin/dev.tt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,36 @@ | ||
exec "./bin/rails", "server", *ARGV | ||
# !/usr/bin/env ruby | ||
|
||
ENV["PORT"] ||= "3000" | ||
VERBOSE = ARGV.include?("--verbose") || ARGV.include?("-v") || ENV["VERBOSE"] | ||
|
||
PROCFILE = 'Procfile.dev' | ||
Process.exec(*%w[bundle exec rails server], *ARGV) unless File.exist?(PROCFILE) | ||
|
||
Signal.trap("INT") { } | ||
|
||
if system(*%w[gem list --no-installed --exact --silent foreman]) | ||
puts "Installing foreman..." | ||
system(*%w[gem install foreman]) | ||
end | ||
|
||
begin | ||
foreman_pid = Process.spawn( | ||
*%w[foreman start -f Procfile.dev -m all=1,web=0 --env /dev/null], | ||
in: "/dev/null", | ||
out: (VERBOSE ? STDOUT : "/dev/null"), | ||
err: (VERBOSE ? STDOUT : "/dev/null"), | ||
pgroup: true, | ||
) | ||
foreman_pgid = Process.getpgid(foreman_pid) | ||
pid = Process.spawn(*%w[bundle exec rails server]) | ||
|
||
Process.wait(pid) | ||
pid = nil | ||
ensure | ||
Process.kill("INT", -foreman_pgid) | ||
Process.wait(-foreman_pgid) | ||
begin | ||
Process.kill("KILL", pid) if pid | ||
rescue Errno::ESRCH | ||
end | ||
end |