Current section

Files

Jump to
igniter lib mix tasks igniter.phx.install.ex
Raw

lib/mix/tasks/igniter.phx.install.ex

# SPDX-FileCopyrightText: 2024 igniter contributors <https://github.com/ash-project/igniter/graphs.contributors>
#
# SPDX-License-Identifier: MIT
defmodule Mix.Tasks.Igniter.Phx.Install do
@moduledoc false
use Igniter.Mix.Task
@example "mix igniter.phx.install . --module MyApp --app my_app"
# No docs yet, its only for testing
# @shortdoc "Creates a new Phoenix project in the current application."
# @moduledoc """
# #{@shortdoc}
#
# ## Example
#
# ```bash
# #{@example}
# ```
#
# ## Options
#
# * `--app` - the name of the OTP application
#
# * `--module` - the name of the base module in
# the generated skeleton
#
# * `--database` - specify the database adapter for Ecto. One of:
#
# * `postgres` - via https://github.com/elixir-ecto/postgrex
# * `mysql` - via https://github.com/elixir-ecto/myxql
# * `mssql` - via https://github.com/livehelpnow/tds
# * `sqlite3` - via https://github.com/elixir-sqlite/ecto_sqlite3
#
# Please check the driver docs for more information
# and requirements. Defaults to "postgres".
#
# * `--adapter` - specify the http adapter. One of:
# * `cowboy` - via https://github.com/elixir-plug/plug_cowboy
# * `bandit` - via https://github.com/mtrudel/bandit
#
# Please check the adapter docs for more information
# and requirements. Defaults to "bandit".
#
# * `--no-assets` - equivalent to `--no-esbuild` and `--no-tailwind`
#
# * `--no-dashboard` - do not include Phoenix.LiveDashboard
#
# * `--no-ecto` - do not generate Ecto files
#
# * `--no-esbuild` - do not include esbuild dependencies and assets.
# We do not recommend setting this option, unless for API only
# applications, as doing so requires you to manually add and
# track JavaScript dependencies
#
# * `--no-gettext` - do not generate gettext files
#
# * `--no-html` - do not generate HTML views
#
# * `--no-live` - comment out LiveView socket setup in your Endpoint
# and assets/js/app.js. Automatically disabled if --no-html is given
#
# * `--no-mailer` - do not generate Swoosh mailer files
#
# * `--no-tailwind` - do not include tailwind dependencies and assets.
# The generated markup will still include Tailwind CSS classes, those
# are left-in as reference for the subsequent styling of your layout
# and components
#
# * `--binary-id` - use `binary_id` as primary key type in Ecto schemas
#
# * `--verbose` - use verbose output
#
# When passing the `--no-ecto` flag, Phoenix generators such as
# `phx.gen.html`, `phx.gen.json`, `phx.gen.live`, and `phx.gen.context`
# may no longer work as expected as they generate context files that rely
# on Ecto for the database access. In those cases, you can pass the
# `--no-context` flag to generate most of the HTML and JSON files
# but skip the context, allowing you to fill in the blanks as desired.
#
# Similarly, if `--no-html` is given, the files generated by
# `phx.gen.html` will no longer work, as important HTML components
# will be missing.
#
# """
def info(_argv, _source) do
%Igniter.Mix.Task.Info{
group: :igniter,
example: @example,
positional: [:base_path],
schema: [
app: :string,
module: :string,
database: :string,
adapter: :string,
assets: :boolean,
dashboard: :boolean,
ecto: :boolean,
esbuild: :boolean,
gettext: :boolean,
html: :boolean,
live: :boolean,
mailer: :boolean,
tailwind: :boolean,
binary_id: :boolean,
verbose: :boolean
]
}
end
def igniter(igniter) do
elixir_version_check!()
if !Code.ensure_loaded?(Phx.New.Generator) do
Mix.raise("""
Phoenix installer is not available. Please install it before proceeding:
mix archive.install hex phx_new
""")
end
if igniter.args.options[:umbrella] do
Mix.raise("Umbrella projects are not supported yet.")
end
%{base_path: base_path} = igniter.args.positional
generate(igniter, base_path, {Phx.New.Single, Igniter.Phoenix.Single}, igniter.args.options)
end
defp generate(igniter, base_path, {phx_generator, igniter_generator}, opts) do
project =
apply(Phx.New.Project, :new, [base_path, opts])
|> phx_generator.prepare_project()
project =
apply(Phx.New.Generator, :put_binding, [project])
|> validate_project()
igniter
|> Igniter.compose_task("igniter.add_extension", ["phoenix"])
|> igniter_generator.generate(project)
end
defp validate_project(%{opts: opts} = project) do
check_app_name!(project.app, !!opts[:app])
check_module_name_validity!(project.root_mod)
project
end
defp check_app_name!(name, from_app_flag) do
unless name =~ Regex.recompile!(~r/^[a-z][a-z0-9_]*$/) do
extra =
if from_app_flag do
""
else
". The application name is inferred from the path, if you'd like to " <>
"explicitly name the application then use the `--app APP` option."
end
Mix.raise(
"Application name must start with a letter and have only lowercase " <>
"letters, numbers and underscore, got: #{inspect(name)}" <> extra
)
end
end
defp check_module_name_validity!(name) do
unless inspect(name) =~ Regex.recompile!(~r/^[A-Z]\w*(\.[A-Z]\w*)*$/) do
Mix.raise(
"Module name must be a valid Elixir alias (for example: Foo.Bar), got: #{inspect(name)}"
)
end
end
defp elixir_version_check! do
unless Version.match?(System.version(), "~> 1.15") do
Mix.raise(
"mix igniter.phx.install requires at least Elixir v1.15\n " <>
"You have #{System.version()}. Please update accordingly."
)
end
end
end