How to run mix task without compilation?

I like to make my mix tasks double up as escripts for this purpose:

# lib/mix/tasks/secrets/mix.exs
defmodule Bonfire.Secrets do
  use Mix.Project

  def project do
    [
      app: :secrets,
      version: "0.1.0-alpha.1",
      elixir: "~> 1.11",
      escript: [main_module: Mix.Tasks.Bonfire.Secrets]
    ]
  end
end

# lib/mix/tasks/secrets/lib/secrets.ex
defmodule Mix.Tasks.Bonfire.Secrets do
  @shortdoc "Generates some secrets"

  @moduledoc """
  Generates random secrets and prints to the terminal.
  > mix bonfire.secrets [length]

  Can also compile/run it as an escript (without having to first compile the app):
  > cd lib/mix/tasks/secrets && mix escript.build && ./secrets [length]
  """
  use Mix.Task

  # for running as escript
  def main(args) do
    run(args)
  end

  @doc false
  def run([]), do: run(["64"])

  def run([int]),
    do: int |> parse!() |> random_string() |> Kernel.<>("\r\n") |> IO.puts()

  def run([int, iterate]), do: for(_ <- 1..parse!(iterate), do: run([int]))
  def run(args), do: nil

  defp parse!(int) do
    case Integer.parse(int) do
      {int, ""} -> int
      _ -> 64
    end
  end

  defp random_string(length) when length > 31 do
    :crypto.strong_rand_bytes(length)
    |> Base.encode64()
    |> binary_part(0, length)
  end
end
2 Likes