Packages
phoenix_kit
1.7.27
1.7.208
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/phoenix_kit/install/common.ex
defmodule PhoenixKit.Install.Common do
@moduledoc """
Common utilities shared between PhoenixKit installation and update tasks.
This module provides shared functionality for:
- Timestamp generation
- Version formatting
- Status checking
- Migration detection
"""
alias PhoenixKit.Config
alias PhoenixKit.Migrations.Postgres
@doc """
Generates timestamp in Ecto migration format.
## Examples
iex> PhoenixKit.Install.Common.generate_timestamp()
"20250908123045"
"""
def generate_timestamp do
{{y, m, d}, {hh, mm, ss}} = :calendar.universal_time()
"#{y}#{pad(m)}#{pad(d)}#{pad(hh)}#{pad(mm)}#{pad(ss)}"
end
@doc """
Pads a number with leading zero if less than 10.
## Examples
iex> PhoenixKit.Install.Common.pad(5)
"05"
iex> PhoenixKit.Install.Common.pad(12)
"12"
"""
def pad(i) when i < 10, do: <<?0, ?0 + i>>
def pad(i), do: to_string(i)
@doc """
Pads version number for consistent naming.
## Examples
iex> PhoenixKit.Install.Common.pad_version(1)
"01"
iex> PhoenixKit.Install.Common.pad_version(15)
"15"
"""
def pad_version(version) when version < 10, do: "0#{version}"
def pad_version(version), do: to_string(version)
@doc """
Checks the current installation status for a given prefix.
Returns one of:
- `{:not_installed}` - PhoenixKit is not installed
- `{:current_version, version}` - PhoenixKit is installed with given version
## Parameters
- `prefix` - Database schema prefix (default: "public")
## Examples
iex> PhoenixKit.Install.Common.check_installation_status("public")
{:current_version, 3}
iex> PhoenixKit.Install.Common.check_installation_status("auth")
{:not_installed}
"""
def check_installation_status(prefix \\ "public") do
# Use the same version detection logic as the migration system
opts = %{
prefix: prefix,
escaped_prefix: String.replace(prefix, "'", "\\'")
}
try do
# Use PhoenixKit's centralized runtime version detection function
current_version = Postgres.migrated_version_runtime(opts)
if current_version > 0 do
# Valid version found in database
{:current_version, current_version}
else
# Primary detection failed, try alternative detection methods
check_alternative_version_detection(prefix, opts)
end
rescue
error ->
# Database error - genuine connection/query failure
IO.puts("Warning: Database connection failed during version detection: #{inspect(error)}")
# Try alternative methods before giving up
check_alternative_version_detection(prefix, opts)
end
end
# Alternative version detection when primary method fails
defp check_alternative_version_detection(prefix, opts) do
# Strategy 1: Try direct database query (like status command does)
case try_direct_database_version_check(opts) do
version when version > 0 ->
{:current_version, version}
_ ->
# Strategy 2: Check if tables exist and try to infer version
case check_installation_from_tables(prefix) do
{:current_version, version} ->
{:current_version, version}
{:not_installed} ->
{:not_installed}
end
end
end
# Try direct database connection (similar to what status command does)
defp try_direct_database_version_check(opts) do
# Try to get the repo from application config first (same as status command)
repo = Config.get(:repo, nil)
if repo do
escaped_prefix = Map.fetch!(opts, :escaped_prefix)
query_version_directly(repo, escaped_prefix)
else
0
end
rescue
_ -> 0
end
# Direct version query (simplified version of the runtime check)
defp query_version_directly(repo, escaped_prefix) do
# Check if phoenix_kit table exists first
table_check =
"SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'phoenix_kit' AND table_schema = '#{escaped_prefix}')"
case repo.query(table_check, [], log: false) do
{:ok, %{rows: [[true]]}} ->
# Table exists, get version comment
version_query = """
SELECT pg_catalog.obj_description(pg_class.oid, 'pg_class')
FROM pg_class
LEFT JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE pg_class.relname = 'phoenix_kit'
AND pg_namespace.nspname = '#{escaped_prefix}'
"""
case repo.query(version_query, [], log: false) do
{:ok, %{rows: [[version]]}} when is_binary(version) ->
String.to_integer(version)
_ ->
# Table exists but no version comment - assume version 1
1
end
_ ->
0
end
rescue
_ -> 0
end
# Check installation based on table presence and schema analysis
defp check_installation_from_tables(_prefix) do
case find_existing_phoenix_kit_migrations() do
[] ->
{:not_installed}
_migrations ->
# Migration files exist - try to determine actual version from database
# This is a last resort, assume recent version if tables are expected to exist
{:current_version, 1}
end
end
@doc """
Finds existing PhoenixKit migrations in the project.
Returns a list of migration file paths.
"""
def find_existing_phoenix_kit_migrations do
if File.exists?("priv/repo/migrations") do
"priv/repo/migrations"
|> File.ls!()
|> Enum.filter(&phoenix_kit_migration?/1)
|> Enum.map(&Path.join("priv/repo/migrations", &1))
else
[]
end
rescue
_ -> []
end
@doc """
Checks if a filename matches PhoenixKit migration pattern.
## Examples
iex> PhoenixKit.Install.Common.phoenix_kit_migration?("20250908_add_phoenix_kit_tables.exs")
true
iex> PhoenixKit.Install.Common.phoenix_kit_migration?("20250908_create_users.exs")
false
"""
def phoenix_kit_migration?(filename) do
(String.contains?(filename, "phoenix_kit") ||
String.contains?(filename, "add_phoenix_kit") ||
String.contains?(filename, "upgrade_phoenix_kit") ||
String.contains?(filename, "update_phoenix_kit")) &&
String.ends_with?(filename, ".exs")
end
@doc """
Describes what changed between versions.
## Parameters
- `from_version` - Starting version number
- `to_version` - Target version number
## Returns
String describing the changes between versions.
"""
def describe_version_changes(from_version, to_version) do
case {from_version, to_version} do
{1, 3} ->
"- Remove is_active column from role assignments (simplified role system)\n" <>
"- Add settings table with user preferences support"
{2, 3} ->
"- Add settings table with user preferences support"
{_, _} when from_version < to_version ->
"- Various improvements and new features"
{_, _} ->
"- No changes (already up to date)"
end
end
@doc """
Gets current PhoenixKit version from migrations system.
"""
def current_version, do: Postgres.current_version()
@doc """
Gets migrated version for given prefix.
## Parameters
- `prefix` - Database schema prefix
"""
def migrated_version(prefix \\ "public") do
opts = %{prefix: prefix, escaped_prefix: String.replace(prefix, "'", "\\'")}
Postgres.migrated_version_runtime(opts)
rescue
_ -> 0
end
@doc """
Checks if an update is needed from current to target version.
## Parameters
- `prefix` - Database schema prefix
- `force` - Force update even if already up to date
## Returns
- `{:up_to_date, current_version}` - Already up to date
- `{:update_needed, current_version, target_version}` - Update available
- `{:not_installed}` - PhoenixKit not installed
"""
def check_update_needed(prefix \\ "public", force \\ false) do
case check_installation_status(prefix) do
{:not_installed} ->
{:not_installed}
{:current_version, current_version} ->
target_version = current_version()
cond do
current_version >= target_version && !force ->
{:up_to_date, current_version}
current_version < target_version || force ->
{:update_needed, current_version, target_version}
true ->
{:up_to_date, current_version}
end
end
end
end