Browse Source

Add config generation mix task

master
Sean King 1 month ago
parent
commit
68d12df3e8
Signed by: seanking GPG Key ID: 778810DE76B9460F
9 changed files with 293 additions and 2 deletions
  1. +4
    -0
      .gitignore
  2. +2
    -1
      config/config.exs
  3. +1
    -1
      config/dev.exs
  4. +5
    -0
      lib/mix/fuck_gab.ex
  5. +152
    -0
      lib/mix/tasks/fuck_gab/config.ex
  6. +31
    -0
      priv/templates/sample_config.eex
  7. +7
    -0
      priv/templates/sample_psql.eex
  8. +11
    -0
      test/mix/fuck_gab_test.exs
  9. +80
    -0
      test/mix/tasks/fuck_gab/config_test.exs

+ 4
- 0
.gitignore View File

@ -39,3 +39,7 @@ npm-debug.log
# Files matching config/*.secret.exs pattern contain sensitive
# data and you should not commit them into version control.
/config/*.secret.exs
/config/generated_config.exs
# Database setup file, some may forget to delete it
/config/setup_db.psql

+ 2
- 1
config/config.exs View File

@ -10,7 +10,8 @@ use Mix.Config
config :fuck_gab, :site,
name: "Fuck Gab!",
description: %{
content: "You may be here because you're sick of Gab's shit. Well, no worries. You're not the only one.
content:
"You may be here because you're sick of Gab's shit. Well, no worries. You're not the only one.
And there are plenty of alternatives to Gab out there because there's this amazing thing called the fediverse.
Here's a list of some alternatives on the fediverse that you can try out.",
display: true

+ 1
- 1
config/dev.exs View File

@ -80,4 +80,4 @@ config :phoenix, :plug_init_mode, :runtime
# Finally import the config/dev.secret.exs which loads secrets
# and configuration from environment variables.
import_config "dev.secret.exs"
if File.exists?("./config/dev.secret.exs"), do: import_config("dev.secret.exs")

+ 5
- 0
lib/mix/fuck_gab.ex View File

@ -81,4 +81,9 @@ defmodule Mix.FuckGab do
def mix_shell?(_env, _mix_shell_config) do
:erlang.function_exported(Mix, :shell, 0)
end
@doc "A function for getting options"
def get_option(options, opt, prompt, defval \\ nil, defname \\ nil) do
Keyword.get(options, opt) || shell_prompt(prompt, defval, defname)
end
end

+ 152
- 0
lib/mix/tasks/fuck_gab/config.ex View File

@ -0,0 +1,152 @@
# Modified from Pleroma, lib/mix/tasks/pleroma/instance.ex
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.FuckGab.Config do
use Mix.Task
import Mix.FuckGab
alias FuckGab.Config
@shortdoc "Manages Fuck Gab configuration"
def run(["gen" | rest]) do
{options, [], []} =
OptionParser.parse(
rest,
strict: [
force: :boolean,
output: :string,
output_psql: :string,
domain: :string,
site_name: :string,
site_description: :string,
dbhost: :string,
dbname: :string,
dbuser: :string,
dbpass: :string,
listen_ip: :string,
listen_port: :string
]
)
paths =
[config_path, psql_path] = [
Keyword.get(options, :output, "config/generated_config.exs"),
Keyword.get(options, :output_psql, "config/setup_db.psql")
]
will_overwrite = Enum.filter(paths, &File.exists?/1)
proceed? = Enum.empty?(will_overwrite) or Keyword.get(options, :force, false)
if proceed? do
[domain, port | _] =
String.split(
get_option(
options,
:domain,
"What domain will your instance use? (e.g. fuckgab.com)"
),
":"
) ++ [443]
site_name =
get_option(
options,
:site_name,
"What will the name of the site be?",
Config.get([:site, :name]),
"Default site name"
)
site_description =
get_option(
options,
:site_description,
"What will the description of the site be?",
Config.get([:site, :description, :content]),
"Default description"
)
dbhost = get_option(options, :dbhost, "What is the hostname of your database?", "localhost")
dbname = get_option(options, :dbname, "What is the name of your database?", "fuck_gab")
dbuser =
get_option(
options,
:dbuser,
"What is the user used to connect to your database?",
"fuck_gab"
)
dbpass =
get_option(
options,
:dbpass,
"What is the password used to connect to your database?",
:crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64),
"autogenerated"
)
listen_ip =
get_option(
options,
:listen_ip,
"What IP address will the app listen to (leave it if you are doing the default setup with nginx)?",
"127.0.0.1"
)
listen_port =
get_option(
options,
:listen_port,
"What port will the app listen to (leave it if you are doing the default setup with nginx)?",
9002
)
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
signing_salt = :crypto.strong_rand_bytes(8) |> Base.encode64() |> binary_part(0, 8)
template_dir = Application.app_dir(:fuck_gab, "priv") <> "/templates"
result_config =
EEx.eval_file(
template_dir <> "/sample_config.eex",
domain: domain,
port: port,
site_name: site_name,
site_description: site_description,
dbhost: dbhost,
dbname: dbname,
dbuser: dbuser,
dbpass: dbpass,
secret: secret,
signing_salt: signing_salt,
listen_ip: listen_ip,
listen_port: listen_port
)
result_psql =
EEx.eval_file(
template_dir <> "/sample_psql.eex",
dbname: dbname,
dbuser: dbuser,
dbpass: dbpass
)
shell_info("Writing config to #{config_path}...")
File.write(config_path, result_config)
shell_info("Writing the postgres script to #{psql_path}...")
File.write(psql_path, result_psql)
shell_info("\nAll files successfully written!")
else
shell_error(
"The task would have overwritten the following files:\n" <>
(Enum.map(paths, &"- #{&1}\n") |> Enum.join("")) <>
"Rerun with `--force` to overwrite them."
)
end
end
end

+ 31
- 0
priv/templates/sample_config.eex View File

@ -0,0 +1,31 @@
# Fuck Gab! configuration
# NOTE: Do not commit this file to a repo or otherwise make it public without
# removing sensitive information first.
<%= if Code.ensure_loaded?(Config) or not Code.ensure_loaded?(Mix.Config) do
"import Config"
else
"use Mix.Config"
end %>
config :fuck_gab, FuckGabWeb.Endpoint,
url: [host: "<%= domain %>", scheme: "https", port: <%= port %>],
http: [ip: {<%= String.replace(listen_ip, ".", ", ") %>}, port: <%= listen_port %>],
secret_key_base: "<%= secret %>",
signing_salt: "<%= signing_salt %>"
config :fuck_gab, :instance,
site_name: "<%= site_name %>",
site_description: %{
content: "<%= site_description %>",
display: true
}
config :fuck_gab, FuckGab.Repo,
adapter: Ecto.Adapters.Postgres,
username: "<%= dbuser %>",
password: "<%= dbpass %>",
database: "<%= dbname %>",
hostname: "<%= dbhost %>",
pool_size: 10

+ 7
- 0
priv/templates/sample_psql.eex View File

@ -0,0 +1,7 @@
CREATE USER <%= dbuser %> WITH ENCRYPTED PASSWORD '<%= dbpass %>';
CREATE DATABASE <%= dbname %> OWNER <%= dbuser %>;
\c <%= dbname %>;
--Extensions made by ecto.migrate that need superuser access
CREATE EXTENSION IF NOT EXISTS citext;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

+ 11
- 0
test/mix/fuck_gab_test.exs View File

@ -94,4 +94,15 @@ defmodule Mix.FuckGabTest do
assert capture_io(:stderr, fn -> shell_error("Test error") end) == "Test error\n"
end
end
describe "get_option/3" do
test "get from options" do
assert get_option([domain: "some-domain.com"], :domain, "Promt") == "some-domain.com"
end
test "get from prompt" do
send(self(), {:mix_shell_input, :prompt, "another-domain.com"})
assert get_option([], :domain, "Prompt") == "another-domain.com"
end
end
end

+ 80
- 0
test/mix/tasks/fuck_gab/config_test.exs View File

@ -0,0 +1,80 @@
# Modified from Pleroma, test/mix/tasks/pleroma/instance_test.exs
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Mix.Tasks.FuckGab.ConfigTest do
use ExUnit.Case
defp tmp_path do
"/tmp/generated_files/"
end
setup do
File.mkdir_p!(tmp_path())
Mix.shell(Mix.Shell.Process)
on_exit(fn ->
File.rm_rf(tmp_path())
Mix.shell(Mix.Shell.IO)
end)
:ok
end
test "running gen" do
Mix.Tasks.FuckGab.Config.run([
"gen",
"--output",
tmp_path() <> "generated_config.exs",
"--output-psql",
tmp_path() <> "setup.psql",
"--domain",
"fuckgab.com",
"--site-name",
"Fuck Gab!",
"--site-description",
"Test description",
"--dbhost",
"dbhost",
"--dbname",
"dbname",
"--dbuser",
"dbuser",
"--dbpass",
"dbpass",
"--listen-port",
"9002",
"--listen-ip",
"127.0.0.1"
])
generated_config = File.read!(tmp_path() <> "generated_config.exs")
assert generated_config =~ "host: \"fuckgab.com\""
assert generated_config =~ "name: \"Fuck Gab!\""
assert generated_config =~ "content: \"Test description\""
assert generated_config =~ "hostname: \"dbhost\""
assert generated_config =~ "database: \"dbname\""
assert generated_config =~ "username: \"dbuser\""
assert generated_config =~ "password: \"dbpass\""
assert generated_config =~ "http: [ip: {127, 0, 0, 1}, port: 9002]"
assert File.read!(tmp_path() <> "setup.psql") == generated_setup_psql()
# Let's also make sure the shell_error is returned when there's no --force option and the generated files already exist.
Mix.Tasks.FuckGab.Config.run([
"gen",
"--output",
tmp_path() <> "generated_config.exs",
"--output-psql",
tmp_path() <> "setup.psql"
])
assert_received {:mix_shell, :error,
[
"The task would have overwritten the following files:\n- /tmp/generated_files/generated_config.exs\n- /tmp/generated_files/setup.psql\nRerun with `--force` to overwrite them."
]}
end
defp generated_setup_psql do
~s(CREATE USER dbuser WITH ENCRYPTED PASSWORD 'dbpass';\nCREATE DATABASE dbname OWNER dbuser;\n\\c dbname;\n--Extensions made by ecto.migrate that need superuser access\nCREATE EXTENSION IF NOT EXISTS citext;\nCREATE EXTENSION IF NOT EXISTS pg_trgm;\nCREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";\n)
end
end

Loading…
Cancel
Save