react_on_rails 16.1.2 → 16.2.0
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/.rspec +2 -0
- data/.rubocop.yml +85 -0
- data/Gemfile.development_dependencies +8 -7
- data/Gemfile.lock +158 -119
- data/Steepfile +56 -0
- data/lib/generators/react_on_rails/base_generator.rb +43 -120
- data/lib/generators/react_on_rails/dev_tests_generator.rb +2 -1
- data/lib/generators/react_on_rails/generator_helper.rb +102 -2
- data/lib/generators/react_on_rails/install_generator.rb +36 -156
- data/lib/generators/react_on_rails/js_dependency_manager.rb +383 -0
- data/lib/generators/react_on_rails/templates/base/base/.dev-services.yml.example +76 -0
- data/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook +30 -0
- data/lib/generators/react_on_rails/templates/base/base/bin/switch-bundler +141 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +44 -45
- data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt} +28 -3
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +15 -9
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +42 -6
- data/lib/react_on_rails/configuration.rb +149 -32
- data/lib/react_on_rails/controller.rb +3 -3
- data/lib/react_on_rails/dev/pack_generator.rb +168 -2
- data/lib/react_on_rails/dev/process_manager.rb +136 -14
- data/lib/react_on_rails/dev/server_manager.rb +194 -26
- data/lib/react_on_rails/dev/service_checker.rb +200 -0
- data/lib/react_on_rails/doctor.rb +341 -12
- data/lib/react_on_rails/engine.rb +75 -1
- data/lib/react_on_rails/git_utils.rb +3 -1
- data/lib/react_on_rails/helper.rb +70 -192
- data/lib/react_on_rails/locales/base.rb +17 -5
- data/lib/react_on_rails/packer_utils.rb +79 -2
- data/lib/react_on_rails/packs_generator.rb +57 -39
- data/lib/react_on_rails/prerender_error.rb +74 -17
- data/lib/react_on_rails/pro_helper.rb +64 -0
- data/lib/react_on_rails/react_component/render_options.rb +7 -7
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +2 -5
- data/lib/react_on_rails/smart_error.rb +326 -0
- data/lib/react_on_rails/system_checker.rb +8 -9
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +16 -7
- data/lib/react_on_rails/utils.rb +241 -55
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +383 -35
- data/lib/tasks/generate_packs.rake +12 -6
- data/lib/tasks/locale.rake +6 -1
- data/rakelib/docker.rake +26 -0
- data/rakelib/dummy_apps.rake +30 -0
- data/rakelib/example_type.rb +121 -0
- data/rakelib/examples_config.yml +52 -0
- data/rakelib/lint.rake +52 -0
- data/rakelib/node_package.rake +15 -0
- data/rakelib/rbs.rake +70 -0
- data/rakelib/run_rspec.rake +223 -0
- data/rakelib/shakapacker_examples.rake +171 -0
- data/rakelib/task_helpers.rb +134 -0
- data/rakelib/update_changelog.rake +73 -0
- data/react_on_rails.gemspec +4 -3
- data/sig/README.md +52 -0
- data/sig/react_on_rails/configuration.rbs +96 -0
- data/sig/react_on_rails/controller.rbs +15 -0
- data/sig/react_on_rails/dev/file_manager.rbs +15 -0
- data/sig/react_on_rails/dev/pack_generator.rbs +19 -0
- data/sig/react_on_rails/dev/process_manager.rbs +22 -0
- data/sig/react_on_rails/dev/server_manager.rbs +39 -0
- data/sig/react_on_rails/dev/service_checker.rbs +22 -0
- data/sig/react_on_rails/error.rbs +4 -0
- data/sig/react_on_rails/generators/js_dependency_manager.rbs +123 -0
- data/sig/react_on_rails/git_utils.rbs +8 -0
- data/sig/react_on_rails/helper.rbs +65 -0
- data/sig/react_on_rails/json_parse_error.rbs +10 -0
- data/sig/react_on_rails/locales.rbs +46 -0
- data/sig/react_on_rails/packer_utils.rbs +15 -0
- data/sig/react_on_rails/prerender_error.rbs +21 -0
- data/sig/react_on_rails/server_rendering_pool.rbs +12 -0
- data/sig/react_on_rails/smart_error.rbs +28 -0
- data/sig/react_on_rails/test_helper.rbs +11 -0
- data/sig/react_on_rails/utils.rbs +34 -0
- data/sig/react_on_rails/version_checker.rbs +12 -0
- data/sig/react_on_rails.rbs +17 -0
- metadata +49 -32
- data/AI_AGENT_INSTRUCTIONS.md +0 -63
- data/CHANGELOG.md +0 -1836
- data/CLAUDE.md +0 -135
- data/CODING_AGENTS.md +0 -313
- data/CONTRIBUTING.md +0 -668
- data/Dockerfile_tests +0 -12
- data/KUDOS.md +0 -114
- data/LICENSE.md +0 -47
- data/LICENSES/README.md +0 -14
- data/NEWS.md +0 -62
- data/PROJECTS.md +0 -63
- data/REACT-ON-RAILS-PRO-LICENSE.md +0 -129
- data/README.md +0 -217
- data/SUMMARY.md +0 -88
- data/TODO.md +0 -135
- data/bin/lefthook/check-trailing-newlines +0 -38
- data/bin/lefthook/get-changed-files +0 -26
- data/bin/lefthook/prettier-format +0 -26
- data/bin/lefthook/ruby-autofix +0 -26
- data/bin/lefthook/ruby-lint +0 -27
- data/docker-compose.yml +0 -11
- data/eslint.config.ts +0 -232
- data/knip.ts +0 -114
- data/lib/react_on_rails/pro/NOTICE +0 -21
- data/lib/react_on_rails/pro/helper.rb +0 -122
- data/lib/react_on_rails/pro/utils.rb +0 -53
- data/tsconfig.eslint.json +0 -6
- data/tsconfig.json +0 -19
|
@@ -1,26 +1,192 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "English"
|
|
4
|
+
require "stringio"
|
|
5
|
+
require_relative "../packer_utils"
|
|
4
6
|
|
|
5
7
|
module ReactOnRails
|
|
6
8
|
module Dev
|
|
9
|
+
# PackGenerator triggers the generation of React on Rails packs
|
|
10
|
+
#
|
|
11
|
+
# Design decisions:
|
|
12
|
+
# 1. Why trigger via Rake task instead of direct Ruby code?
|
|
13
|
+
# - The actual pack generation logic lives in lib/react_on_rails/packs_generator.rb
|
|
14
|
+
# - The rake task (lib/tasks/generate_packs.rake) provides a stable, documented interface
|
|
15
|
+
# - This allows the implementation to evolve without breaking bin/dev
|
|
16
|
+
# - Users can also run the task directly: `rake react_on_rails:generate_packs`
|
|
17
|
+
#
|
|
18
|
+
# 2. Why two execution strategies (direct vs bundle exec)?
|
|
19
|
+
# - Direct Rake execution: Faster when already in Bundler/Rails context (bin/dev)
|
|
20
|
+
# - Bundle exec fallback: Required when called outside Rails context
|
|
21
|
+
# - This optimization avoids subprocess overhead in the common case
|
|
22
|
+
#
|
|
23
|
+
# 3. Why is the class named "PackGenerator" when it delegates?
|
|
24
|
+
# - It's a semantic wrapper around pack generation for the dev workflow
|
|
25
|
+
# - Provides a clean API for bin/dev without exposing Rake internals
|
|
26
|
+
# - Handles hook detection, error handling, and output formatting
|
|
7
27
|
class PackGenerator
|
|
8
28
|
class << self
|
|
9
29
|
def generate(verbose: false)
|
|
30
|
+
# Skip if shakapacker has a precompile hook configured
|
|
31
|
+
if ReactOnRails::PackerUtils.shakapacker_precompile_hook_configured?
|
|
32
|
+
if verbose
|
|
33
|
+
hook_value = ReactOnRails::PackerUtils.shakapacker_precompile_hook_value
|
|
34
|
+
puts "⏭️ Skipping pack generation (handled by shakapacker precompile hook: #{hook_value})"
|
|
35
|
+
end
|
|
36
|
+
return
|
|
37
|
+
end
|
|
38
|
+
|
|
10
39
|
if verbose
|
|
11
40
|
puts "📦 Generating React on Rails packs..."
|
|
12
|
-
success =
|
|
41
|
+
success = run_pack_generation(silent: false, verbose: true)
|
|
13
42
|
else
|
|
14
43
|
print "📦 Generating packs... "
|
|
15
|
-
success =
|
|
44
|
+
success = run_pack_generation(silent: true, verbose: false)
|
|
16
45
|
puts success ? "✅" : "❌"
|
|
17
46
|
end
|
|
18
47
|
|
|
19
48
|
return if success
|
|
20
49
|
|
|
21
50
|
puts "❌ Pack generation failed"
|
|
51
|
+
unless verbose
|
|
52
|
+
puts ""
|
|
53
|
+
puts "💡 Run with #{Rainbow('--verbose').cyan.bold} flag for detailed output:"
|
|
54
|
+
puts " #{Rainbow('bin/dev --verbose').green.bold}"
|
|
55
|
+
end
|
|
22
56
|
exit 1
|
|
23
57
|
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def run_pack_generation(silent: false, verbose: false)
|
|
62
|
+
# Set environment variable for child processes to respect verbose mode
|
|
63
|
+
ENV["REACT_ON_RAILS_VERBOSE"] = verbose ? "true" : "false"
|
|
64
|
+
|
|
65
|
+
# If we're already inside a Bundler context AND Rails is available (e.g., called from bin/dev),
|
|
66
|
+
# we can directly require and run the task. Otherwise, use bundle exec.
|
|
67
|
+
if should_run_directly?
|
|
68
|
+
run_rake_task_directly(silent: silent)
|
|
69
|
+
else
|
|
70
|
+
run_via_bundle_exec(silent: silent, verbose: verbose)
|
|
71
|
+
end
|
|
72
|
+
ensure
|
|
73
|
+
# Clean up environment variable
|
|
74
|
+
ENV.delete("REACT_ON_RAILS_VERBOSE")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def should_run_directly?
|
|
78
|
+
# Check if we're in a meaningful Bundler context with BUNDLE_GEMFILE
|
|
79
|
+
return false unless defined?(Bundler)
|
|
80
|
+
return false unless ENV["BUNDLE_GEMFILE"]
|
|
81
|
+
return false unless rails_available?
|
|
82
|
+
|
|
83
|
+
true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def rails_available?
|
|
87
|
+
return false unless defined?(Rails)
|
|
88
|
+
return false unless Rails.respond_to?(:application)
|
|
89
|
+
return false if Rails.application.nil?
|
|
90
|
+
|
|
91
|
+
# Verify Rails app can actually load tasks
|
|
92
|
+
begin
|
|
93
|
+
Rails.application.respond_to?(:load_tasks)
|
|
94
|
+
rescue StandardError
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def run_rake_task_directly(silent: false)
|
|
100
|
+
require "rake"
|
|
101
|
+
|
|
102
|
+
load_rake_tasks
|
|
103
|
+
task = prepare_rake_task
|
|
104
|
+
|
|
105
|
+
capture_output(silent) do
|
|
106
|
+
task.invoke
|
|
107
|
+
true
|
|
108
|
+
end
|
|
109
|
+
rescue StandardError => e
|
|
110
|
+
handle_rake_error(e, silent)
|
|
111
|
+
false
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def load_rake_tasks
|
|
115
|
+
return if Rake::Task.task_defined?("react_on_rails:generate_packs")
|
|
116
|
+
|
|
117
|
+
Rails.application.load_tasks
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def prepare_rake_task
|
|
121
|
+
task = Rake::Task["react_on_rails:generate_packs"]
|
|
122
|
+
task.reenable # Allow re-execution if called multiple times
|
|
123
|
+
task
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def capture_output(silent)
|
|
127
|
+
return yield unless silent
|
|
128
|
+
|
|
129
|
+
original_stdout = $stdout
|
|
130
|
+
original_stderr = $stderr
|
|
131
|
+
output_buffer = StringIO.new
|
|
132
|
+
$stdout = output_buffer
|
|
133
|
+
$stderr = output_buffer
|
|
134
|
+
|
|
135
|
+
begin
|
|
136
|
+
yield
|
|
137
|
+
ensure
|
|
138
|
+
$stdout = original_stdout
|
|
139
|
+
$stderr = original_stderr
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def handle_rake_error(error, _silent)
|
|
144
|
+
error_msg = "Error generating packs: #{error.message}"
|
|
145
|
+
error_msg += "\n#{error.backtrace.join("\n")}" if ENV["DEBUG"]
|
|
146
|
+
|
|
147
|
+
# Always write to stderr, even in silent mode
|
|
148
|
+
# Use STDERR constant instead of warn/$stderr to bypass capture_output redirection
|
|
149
|
+
# rubocop:disable Style/StderrPuts, Style/GlobalStdStream
|
|
150
|
+
STDERR.puts error_msg
|
|
151
|
+
# rubocop:enable Style/StderrPuts, Style/GlobalStdStream
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def run_via_bundle_exec(silent: false, verbose: false)
|
|
155
|
+
# Environment variable is already set in run_pack_generation, but we make it explicit here
|
|
156
|
+
# for clarity and to ensure it's passed to the subprocess
|
|
157
|
+
env = { "REACT_ON_RAILS_VERBOSE" => verbose ? "true" : "false" }
|
|
158
|
+
|
|
159
|
+
# Need to unbundle to prevent Bundler from intercepting our bundle exec call
|
|
160
|
+
# when already running inside a Bundler context (e.g., from bin/dev)
|
|
161
|
+
with_unbundled_context do
|
|
162
|
+
if silent
|
|
163
|
+
system(
|
|
164
|
+
env,
|
|
165
|
+
"bundle", "exec", "rake", "react_on_rails:generate_packs",
|
|
166
|
+
out: File::NULL, err: File::NULL
|
|
167
|
+
)
|
|
168
|
+
else
|
|
169
|
+
system(env, "bundle", "exec", "rake", "react_on_rails:generate_packs")
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# DRY helper method for Bundler context switching with API compatibility
|
|
175
|
+
# Supports both new (with_unbundled_env) and legacy (with_clean_env) Bundler APIs
|
|
176
|
+
def with_unbundled_context(&block)
|
|
177
|
+
if defined?(Bundler)
|
|
178
|
+
if Bundler.respond_to?(:with_unbundled_env)
|
|
179
|
+
Bundler.with_unbundled_env(&block)
|
|
180
|
+
elsif Bundler.respond_to?(:with_clean_env)
|
|
181
|
+
Bundler.with_clean_env(&block)
|
|
182
|
+
else
|
|
183
|
+
# Fallback if neither method is available (very old Bundler versions)
|
|
184
|
+
yield
|
|
185
|
+
end
|
|
186
|
+
else
|
|
187
|
+
yield
|
|
188
|
+
end
|
|
189
|
+
end
|
|
24
190
|
end
|
|
25
191
|
end
|
|
26
192
|
end
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "timeout"
|
|
4
|
+
|
|
3
5
|
module ReactOnRails
|
|
4
6
|
module Dev
|
|
5
7
|
class ProcessManager
|
|
8
|
+
# Timeout for version check operations to prevent hanging
|
|
9
|
+
VERSION_CHECK_TIMEOUT = 5
|
|
10
|
+
|
|
6
11
|
class << self
|
|
12
|
+
# Check if a process is available and usable in the current execution context
|
|
13
|
+
# This accounts for bundler context where system commands might be intercepted
|
|
7
14
|
def installed?(process)
|
|
8
|
-
|
|
9
|
-
true
|
|
10
|
-
rescue Errno::ENOENT
|
|
11
|
-
false
|
|
15
|
+
installed_in_current_context?(process)
|
|
12
16
|
end
|
|
13
17
|
|
|
14
18
|
def ensure_procfile(procfile)
|
|
@@ -31,20 +35,138 @@ module ReactOnRails
|
|
|
31
35
|
# Clean up stale files before starting
|
|
32
36
|
FileManager.cleanup_stale_files
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
# Try process managers in order of preference
|
|
39
|
+
# run_process_if_available returns:
|
|
40
|
+
# - true/false (exit status) if process was found and executed
|
|
41
|
+
# - nil if process was not found
|
|
42
|
+
overmind_result = run_process_if_available("overmind", ["start", "-f", procfile])
|
|
43
|
+
return if overmind_result == true # Overmind ran successfully
|
|
44
|
+
|
|
45
|
+
foreman_result = run_process_if_available("foreman", ["start", "-f", procfile])
|
|
46
|
+
return if foreman_result == true # Foreman ran successfully
|
|
47
|
+
|
|
48
|
+
# If either process was found but exited with error, don't show "not found" message
|
|
49
|
+
# The process manager itself will have shown its own error message
|
|
50
|
+
exit 1 if overmind_result == false || foreman_result == false
|
|
51
|
+
|
|
52
|
+
# Neither process manager was found
|
|
53
|
+
show_process_manager_installation_help
|
|
54
|
+
exit 1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
# Check if a process is actually usable in the current execution context
|
|
60
|
+
# This is important for commands that might be intercepted by bundler
|
|
61
|
+
def installed_in_current_context?(process)
|
|
62
|
+
# Try to execute the process with version flags to see if it works
|
|
63
|
+
# Use system() because that's how we'll actually call it later
|
|
64
|
+
version_flags_for(process).any? do |flag|
|
|
65
|
+
# Add timeout to prevent hanging on version checks
|
|
66
|
+
Timeout.timeout(VERSION_CHECK_TIMEOUT) do
|
|
67
|
+
system(process, flag, out: File::NULL, err: File::NULL)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
rescue Errno::ENOENT, Timeout::Error
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Get appropriate version flags for different processes
|
|
75
|
+
def version_flags_for(process)
|
|
76
|
+
case process
|
|
77
|
+
when "overmind"
|
|
78
|
+
["--version"]
|
|
79
|
+
when "foreman"
|
|
80
|
+
["--version", "-v"]
|
|
38
81
|
else
|
|
39
|
-
|
|
40
|
-
NOTICE:
|
|
41
|
-
For this script to run, you need either 'overmind' or 'foreman' installed on your machine. Please try this script after installing one of them.
|
|
42
|
-
MSG
|
|
43
|
-
exit 1
|
|
82
|
+
["--version", "-v", "-V"]
|
|
44
83
|
end
|
|
45
84
|
end
|
|
46
85
|
|
|
47
|
-
|
|
86
|
+
# Try to run a process if it's available, with intelligent fallback strategy
|
|
87
|
+
# Returns:
|
|
88
|
+
# - true if process ran and exited successfully (exit code 0)
|
|
89
|
+
# - false if process ran but exited with error (non-zero exit code)
|
|
90
|
+
# - nil if process was not found/available
|
|
91
|
+
def run_process_if_available(process, args)
|
|
92
|
+
# First attempt: try in current context (works for bundled processes)
|
|
93
|
+
return system(process, *args) if installed?(process)
|
|
94
|
+
|
|
95
|
+
# Second attempt: try in system context (works for system-installed processes)
|
|
96
|
+
return run_process_outside_bundle(process, args) if process_available_in_system?(process)
|
|
97
|
+
|
|
98
|
+
# Process not available in either context
|
|
99
|
+
nil
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Run a process outside of bundler context
|
|
103
|
+
# This allows using system-installed processes even when they're not in the Gemfile
|
|
104
|
+
def run_process_outside_bundle(process, args)
|
|
105
|
+
if defined?(Bundler)
|
|
106
|
+
with_unbundled_context do
|
|
107
|
+
system(process, *args)
|
|
108
|
+
end
|
|
109
|
+
else
|
|
110
|
+
# Fallback if Bundler is not available
|
|
111
|
+
system(process, *args)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Check if a process is available system-wide (outside bundle context)
|
|
116
|
+
def process_available_in_system?(process)
|
|
117
|
+
return false unless defined?(Bundler)
|
|
118
|
+
|
|
119
|
+
with_unbundled_context do
|
|
120
|
+
# Try version flags to check if process exists outside bundler context
|
|
121
|
+
version_flags_for(process).any? do |flag|
|
|
122
|
+
# Add timeout to prevent hanging on version checks
|
|
123
|
+
Timeout.timeout(VERSION_CHECK_TIMEOUT) do
|
|
124
|
+
system(process, flag, out: File::NULL, err: File::NULL)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
rescue Errno::ENOENT, Timeout::Error
|
|
129
|
+
false
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# DRY helper method for Bundler context switching with API compatibility
|
|
133
|
+
# Supports both new (with_unbundled_env) and legacy (with_clean_env) Bundler APIs
|
|
134
|
+
def with_unbundled_context(&block)
|
|
135
|
+
if Bundler.respond_to?(:with_unbundled_env)
|
|
136
|
+
Bundler.with_unbundled_env(&block)
|
|
137
|
+
elsif Bundler.respond_to?(:with_clean_env)
|
|
138
|
+
Bundler.with_clean_env(&block)
|
|
139
|
+
else
|
|
140
|
+
# Fallback if neither method is available (very old Bundler versions)
|
|
141
|
+
yield
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Improved error message with helpful guidance
|
|
146
|
+
def show_process_manager_installation_help
|
|
147
|
+
warn <<~MSG
|
|
148
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
149
|
+
ERROR: Process Manager Not Found
|
|
150
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
151
|
+
|
|
152
|
+
To run the React on Rails development server, you need either 'overmind' or
|
|
153
|
+
'foreman' installed on your system.
|
|
154
|
+
|
|
155
|
+
RECOMMENDED INSTALLATION:
|
|
156
|
+
|
|
157
|
+
macOS: brew install overmind
|
|
158
|
+
Linux: gem install foreman
|
|
159
|
+
|
|
160
|
+
IMPORTANT:
|
|
161
|
+
DO NOT add foreman to your Gemfile. Install it globally on your system.
|
|
162
|
+
|
|
163
|
+
For more information about why foreman should not be in your Gemfile, see:
|
|
164
|
+
https://github.com/ddollar/foreman/wiki/Don't-Bundle-Foreman
|
|
165
|
+
|
|
166
|
+
After installation, try running this script again.
|
|
167
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
168
|
+
MSG
|
|
169
|
+
end
|
|
48
170
|
|
|
49
171
|
def valid_procfile_path?(procfile)
|
|
50
172
|
# Reject paths with shell metacharacters
|