Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 50 additions & 19 deletions lib/mix/tasks/phoenix_kit.install.ex
Original file line number Diff line number Diff line change
Expand Up @@ -135,18 +135,40 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
# CRITICAL: Check if required configuration exists BEFORE starting app
# This prevents configuration timing issues where config is added via Igniter
# but the app has already started with cached (missing) configuration

# Check if this is a retry pass (automatic restart after adding config)
is_retry = Process.get(:phoenix_kit_retry_pass, false)
config_status = check_required_configuration()

case config_status do
:missing ->
case {config_status, is_retry} do
{:missing, false} ->
# First pass: Add configuration via Igniter without starting app
# Store status in Process dictionary for tracking
Process.put(:phoenix_kit_config_status, :missing)

show_missing_config_message(argv)
result = super(argv)
show_config_added_message(argv)
result
super(argv)

# AUTOMATIC RESTART instead of asking user to run again manually
Mix.shell().info("""

✅ Configuration added successfully!
🔄 Automatically restarting to complete the installation...
""")

:ok ->
# Clean Process dictionary to ensure fresh state for retry
Process.delete(:phoenix_kit_config_status)

# Mark this as a retry pass to prevent infinite loops
Process.put(:phoenix_kit_retry_pass, true)

# Recursive call with same arguments - automatic restart
run(argv)

{:ok, _} ->
# Second pass: Configuration exists, safe to start app and complete installation
Process.put(:phoenix_kit_config_status, :ok)

# Run standard igniter process
result = super(argv)

Expand All @@ -158,7 +180,27 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
AssetRebuild.check_and_rebuild(verbose: true)
end

# Clean up retry flag on successful completion
Process.delete(:phoenix_kit_retry_pass)
result

{:missing, true} ->
# Safety check: Configuration still missing after automatic retry
# This prevents infinite loops if configuration addition fails
Mix.shell().error("""

❌ Configuration was not added successfully after automatic retry.

Please check config/config.exs manually and ensure it contains:
- config :ueberauth, Ueberauth (with providers: %{})
- config :hammer (with backend and expiry_ms)
- config :phoenix_kit, Oban (with queues configuration)

Then run: mix phoenix_kit.install #{Enum.join(argv, " ")}
""")

Process.delete(:phoenix_kit_retry_pass)
:error
end
end
end
Expand Down Expand Up @@ -286,17 +328,6 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
""")
end

# Display message after configuration is added
defp show_config_added_message(argv) do
Mix.shell().info("""

✅ Configuration added successfully!

Next step: Run the install command again to complete the installation:
mix phoenix_kit.install #{Enum.join(argv, " ")}
""")
end

# Check if all required configuration exists
# Returns :ok if all config present, :missing if any config is missing
defp check_required_configuration do
Expand Down Expand Up @@ -361,9 +392,9 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
has_oban_config =
Enum.any?(lines, fn line ->
trimmed = String.trim(line)
# Not a comment and contains config :phoenix_kit, Oban
# Not a comment and contains config :any_app, Oban
!String.starts_with?(trimmed, "#") and
String.contains?(line, "config :phoenix_kit, Oban")
String.contains?(line, ", Oban")
end)

has_queues =
Expand Down
50 changes: 9 additions & 41 deletions lib/mix/tasks/phoenix_kit.status.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,15 @@ defmodule Mix.Tasks.PhoenixKit.Status do
]

def run(argv) do
# Conditionally start the application if repositories aren't available
app_started_by_us = ensure_app_started()

try do
{opts, _argv, _errors} = OptionParser.parse(argv, switches: @switches, aliases: @aliases)

prefix = opts[:prefix] || "public"
verbose = opts[:verbose] || false

show_comprehensive_status(prefix, verbose)
after
# Stop the application if we started it
if app_started_by_us do
# Note: Mix doesn't have app.stop task, and typically apps stay running
# This is normal behavior for Mix tasks
:ok
end
end
# Start the application to ensure repo is available
Mix.Task.run("app.start")

{opts, _argv, _errors} = OptionParser.parse(argv, switches: @switches, aliases: @aliases)

prefix = opts[:prefix] || "public"
verbose = opts[:verbose] || false

show_comprehensive_status(prefix, verbose)
end

# Main status display function
Expand Down Expand Up @@ -526,29 +517,6 @@ defmodule Mix.Tasks.PhoenixKit.Status do
_ -> false
end

# Ensure application is started only if needed
# Returns true if we started the app, false if it was already running
defp ensure_app_started do
# Check if we can get repo configuration
case get_repo_with_fallback() do
nil ->
# No repo found, start app and try again
Mix.Task.run("app.start")
true

repo ->
# Repo found, check if it's actually available
if repo_available?(repo) do
# Repo is available, no need to start app
false
else
# Repo not available, start app
Mix.Task.run("app.start")
true
end
end
end

# Pad version number for consistent display
defp pad_version(version) when version < 10, do: "0#{version}"
defp pad_version(version), do: to_string(version)
Expand Down
65 changes: 45 additions & 20 deletions lib/mix/tasks/phoenix_kit.update.ex
Original file line number Diff line number Diff line change
Expand Up @@ -167,26 +167,60 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
# CRITICAL: Check if required configuration exists BEFORE starting app
# This prevents configuration timing issues where config is added via Igniter
# but the app has already started with cached (missing) configuration

# Check if this is a retry pass (automatic restart after adding config)
is_retry = Process.get(:phoenix_kit_retry_pass, false)
config_status = check_required_configuration()

case config_status do
:missing ->
case {config_status, is_retry} do
{:missing, false} ->
# First pass: Add configuration via Igniter without starting app
# Store config status in Process dictionary for igniter/1 to read
Process.put(:phoenix_kit_config_status, :missing)
show_missing_config_message(argv)
result = super(argv)
show_config_added_message(argv)
result
super(argv)

# Automatic restart instead of manual prompt
Mix.shell().info("""

✅ Configuration added successfully!
🔄 Automatically restarting to complete the update...
""")

:ok ->
# Second pass: Configuration exists, safe to start app and update
# Clean Process dictionary for fresh state
Process.delete(:phoenix_kit_config_status)
Process.put(:phoenix_kit_retry_pass, true)

# Recursive call with same arguments
run(argv)

{:ok, _} ->
# Second pass (automatic or manual): Configuration exists, safe to start app
# Store config status in Process dictionary for igniter/1 to read
Process.put(:phoenix_kit_config_status, :ok)
Mix.Task.run("app.start")
result = super(argv)
post_igniter_tasks(elem(opts, 0))

# Clean retry flag
Process.delete(:phoenix_kit_retry_pass)
result

{:missing, true} ->
# Safety: Configuration still missing after retry
Mix.shell().error("""

❌ Configuration was not added successfully after automatic retry.

This may indicate a problem with your config/config.exs file.
Please check the file manually and ensure it's writable.

Then run manually:
mix phoenix_kit.update #{Enum.join(argv, " ")}
""")

Process.delete(:phoenix_kit_retry_pass)
:error
end
end
end
Expand All @@ -201,6 +235,7 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
PhoenixKit requires configuration for:
- Ueberauth (OAuth authentication)
- Hammer (rate limiting)
- Oban (background jobs for file processing)

This configuration will be added now.

Expand All @@ -209,17 +244,6 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
""")
end

# Display message after configuration is added
defp show_config_added_message(argv) do
Mix.shell().info("""

✅ Configuration added successfully!

Next step: Run the update command again to complete the upgrade:
mix phoenix_kit.update #{Enum.join(argv, " ")}
""")
end

# Check if all required configuration exists
# Returns :ok if all config present, :missing if any config is missing
defp check_required_configuration do
Expand Down Expand Up @@ -284,9 +308,10 @@ if Code.ensure_loaded?(Igniter.Mix.Task) do
has_oban_config =
Enum.any?(lines, fn line ->
trimmed = String.trim(line)
# Not a comment and contains config :phoenix_kit, Oban
# Not a comment and contains config for any app with Oban
# Matches: "config :any_app, Oban" or "config :any_app, Oban,"
!String.starts_with?(trimmed, "#") and
String.contains?(line, "config :phoenix_kit, Oban")
String.contains?(line, ", Oban")
end)

has_queues =
Expand Down
2 changes: 2 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ defmodule PhoenixKit.MixProject do
{:finch, "~> 0.18"},

# Code generation and project patching
# Note: Available in all environments for library code, but typically
# only needed in :dev when used as a dependency in parent projects
{:igniter, "~> 0.7"}
]
end
Expand Down
Loading