Current section
Files
Jump to
Current section
Files
lib/mix/tasks/flakify.install.ex
defmodule Mix.Tasks.Flakify.Install.Docs do
@moduledoc false
@spec short_doc() :: String.t()
def short_doc do
"Modify your Phoenix project to work in a Nix flake development shell"
end
@spec example() :: String.t()
def example do
"mix igniter_install flakify"
end
@spec long_doc() :: String.t()
def long_doc do
"""
#{short_doc()}
This task adds a `flake.nix` to your project with tailwind and esbuild
installed, and alters your tailwind and esbuild configuration to use the
versions from your Nix flake.
## Example
```sh
#{example()}
```
## Options
* `--package` - Include a package derivation for the Mix release build of the project (default). The package uses [deps_nix](https://hexdocs.pm/deps_nix/readme.html) to convert Mix dependencies to Nix derivations.
* `--no-package` - Do not include a package derivation.
"""
end
end
if Code.ensure_loaded?(Igniter) do
defmodule Mix.Tasks.Flakify.Install do
@shortdoc "#{__MODULE__.Docs.short_doc()}"
@moduledoc __MODULE__.Docs.long_doc()
use Igniter.Mix.Task
@impl Igniter.Mix.Task
def info(_argv, _composing_task) do
%Igniter.Mix.Task.Info{
# Groups allow for overlapping arguments for tasks by the same author
# See the generators guide for more.
group: :flakify,
# *other* dependencies to add
# i.e `{:foo, "~> 2.0"}`
adds_deps: [],
# *other* dependencies to add and call their associated installers, if they exist
# i.e `{:foo, "~> 2.0"}`
installs: [],
# An example invocation
example: __MODULE__.Docs.example(),
# a list of positional arguments, i.e `[:file]`
positional: [],
# Other tasks your task composes using `Igniter.compose_task`, passing in the CLI argv
# This ensures your option schema includes options from nested tasks
composes: [],
# `OptionParser` schema
schema: [package: :boolean],
# Default values for the options in the `schema`
defaults: [package: true],
# CLI aliases
aliases: [],
# A list of options in the schema that are required
required: []
}
end
@impl Igniter.Mix.Task
def igniter(igniter) do
# Do your work here and return an updated igniter
igniter
|> Igniter.Project.Config.configure(
"config.exs",
:tailwind,
[:path],
{:code,
Sourceror.parse_string!("""
System.get_env("MIX_TAILWIND_PATH")
""")}
)
|> Igniter.Project.Config.configure(
"config.exs",
:tailwind,
[:version_check],
{:code,
Sourceror.parse_string!("""
false
""")}
)
|> Igniter.Project.Config.configure(
"config.exs",
:esbuild,
[:path],
{:code,
Sourceror.parse_string!("""
System.get_env("MIX_ESBUILD_PATH")
""")}
)
|> Igniter.Project.Config.configure(
"config.exs",
:esbuild,
[:version_check],
{:code,
Sourceror.parse_string!("""
false
""")}
)
|> Igniter.create_new_file("flake.nix", """
{
inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; };
outputs = inputs:
let
supportedSystems =
[ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
forEachSupportedSystem = f:
inputs.nixpkgs.lib.genAttrs supportedSystems
(system: f { pkgs = import inputs.nixpkgs { inherit system; }; });
commonEnv = pkgs: {
MIX_TAILWIND_PATH = pkgs.lib.getExe pkgs.tailwindcss_4;
MIX_ESBUILD_PATH = pkgs.lib.getExe pkgs.esbuild;
};
beam_pkgs = pkgs: pkgs.beam.packagesWith pkgs.beam.interpreters.erlang;
in {
devShells = forEachSupportedSystem ({ pkgs }: {
default = pkgs.mkShell {
packages =
(if pkgs.stdenv.isLinux then [ pkgs.inotify-tools ] else [ ]) ++
[ (beam_pkgs pkgs).elixir pkgs.tailwindcss_4 pkgs.esbuild ];
env = commonEnv pkgs;
};
});
#{if Keyword.get(igniter.args.options, :package), do: package_text(Igniter.Project.Application.app_name(igniter))}
};
}
""")
|> then(fn igniter ->
if Igniter.Project.Deps.has_dep?(igniter, :flakify) do
Igniter.Project.Deps.remove_dep(igniter, :flakify)
else
igniter
end
end)
|> maybe_add_deps_nix()
end
defp package_text(app_name) do
"""
packages = forEachSupportedSystem ({ pkgs }: rec {
#{app_name} = let
mixNixDeps = pkgs.callPackages ./deps.nix { };
pname = "#{app_name}";
version = "0.0.1";
in (beam_pkgs pkgs).mixRelease {
inherit pname version mixNixDeps;
src = pkgs.lib.cleanSource ./.;
env = commonEnv pkgs;
postBuild = ''
# As shown in
# https://github.com/code-supply/nix-phoenix/blob/2ab9b2f63dd85d5d6a85d61bd4fc5c6d07f65643/flake-template/flake.nix#L62-L64
ln -sfv ${mixNixDeps.heroicons} deps/heroicons
mix do \\
loadpaths --no-deps-check, \\
assets.deploy --no-deps-check
'';
meta.mainProgram = "server";
};
default = #{app_name};
});
"""
end
defp maybe_add_deps_nix(igniter) do
if Keyword.get(igniter.args.options, :package) do
igniter
|> then(fn igniter ->
Igniter.Project.Deps.add_dep(igniter, {:deps_nix, "~> 2.5"})
end)
|> then(&Igniter.apply_and_fetch_dependencies/1)
|> then(&Igniter.Project.TaskAliases.add_alias(&1, "deps.get", ["deps.get", "deps.nix"]))
|> then(&Igniter.add_task(&1, "deps.get"))
else
igniter
end
end
end
else
defmodule Mix.Tasks.Flakify.Install do
@shortdoc "#{__MODULE__.Docs.short_doc()} | Install `igniter` to use"
@moduledoc __MODULE__.Docs.long_doc()
use Mix.Task
@impl Mix.Task
def run(_argv) do
Mix.shell().error("""
The task 'flakify' requires igniter. Please install igniter and try again.
For more information, see: https://hexdocs.pm/igniter/readme.html#installation
""")
exit({:shutdown, 1})
end
end
end