{
description = "Home, home on the web";
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, nixpkgs, flake-utils, }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
erlangPackages =
pkgs.beam.packagesWith pkgs.beam.interpreters.erlangR23;
node2nix = pkgs.nodePackages.node2nix;
elixir = erlangPackages.elixir_1_12;
erlang = erlangPackages.erlang;
nodejs = pkgs.nodejs-14_x;
elixir-ls = erlangPackages.elixir_ls;
homeWebAssetDependencies = (pkgs.callPackage ./apps/home_web/assets {
inherit pkgs system nodejs;
}).shell.nodeDependencies;
in {
devShell = pkgs.mkShell {
NODE_ENV = "development";
buildInputs = [
pkgs.nodePackages.npm
pkgs.nodePackages.prettier
elixir
nodejs
pkgs.git
pkgs.postgresql
pkgs.nodePackages.eslint
pkgs.cacert
elixir-ls
node2nix
pkgs.md2gemini
pkgs.reuse
] ++ pkgs.lib.optional pkgs.stdenv.isLinux pkgs.inotifyTools;
ERL_INCLUDE_PATH = "${erlang}/lib/erlang/usr/include";
PGDATA = "$PWD/.postgres_data";
PGHOST = "$PWD/.postgres";
LOG_PATH = "$PGHOST/LOG";
PGDATABASE = "postgres";
shellHook = ''
export PGDATA=$PWD/.postgres_data
export PGHOST=$PWD/.postgres
export LOG_PATH=$PGHOST/LOG
export PGDATABASE=postgres
export DATABASE_URL="postgresql:///postgres?host=$PGHOST"
if [ ! -d $PGHOST ]; then
mkdir -p $PGHOST
fi
if [ ! -d $PGDATA ]; then
echo 'Initializing postgresql database...'
initdb $PGDATA --auth=trust --no-locale --encoding=UTF-8 >/dev/null
fi
start() {
pg_ctl start -l $LOG_PATH -o "-c listen_addresses= -c unix_socket_directories=$PGHOST"
}
'';
};
packages = let
version = "0.3.0";
src = ./.;
in flake-utils.lib.flattenTree {
home-elixir-deps = erlangPackages.fetchMixDeps {
inherit version src;
pname = "home-elixir-deps";
sha256 = "sha256-JYrJ+HNvjGZGH5DfqMF3lFOsN5lshYmrynfOTqhEYzk=";
};
home-web-fe-deps = homeWebAssetDependencies;
home-web-fe = let
deps = self.packages.${system}.home-web-fe-deps;
mixDeps = self.packages.${system}.home-elixir-deps;
in pkgs.stdenvNoCC.mkDerivation {
pname = "home-fe";
nativeBuildInputs = [ nodejs ];
inherit version src;
configurePhase = ''
export NODE_ENV=production
export TAILWIND_DISABLE_TOUCH=true
'';
buildPhase = ''
cp -r . $TEMPDIR
ln -s ${deps}/lib/node_modules $TEMPDIR/apps/home_web/assets
export PATH="${deps}/bin:$PATH"
${nodejs}/bin/npm run deploy --prefix $TEMPDIR/apps/home_web/assets
'';
installPhase = ''
cp -r $TEMPDIR/apps/home_web/priv/static $out/
'';
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "sha256-FJzw+n9iXbA4/syYWV6tKlMg3PtKDnGEdx9N8E36l44=";
};
home = let
homeWebAssetDependencies =
(pkgs.callPackage ./apps/home_web/assets {
inherit pkgs system nodejs;
}).shell.nodeDependencies;
home-web-fe = self.packages.${system}.home-web-fe;
mixFodDeps = self.packages.${system}.home-elixir-deps;
in erlangPackages.mixRelease {
inherit version src mixFodDeps;
pname = "home";
preInstall = ''
cp --no-preserve=mode,ownership,timestamps -R ${home-web-fe} ./apps/home_web/priv/static
${elixir}/bin/mix phx.digest
'';
postInstall = ''
chmod +x $out/lib/rambo-*/priv/rambo-*
'';
};
};
defaultPackage = self.packages.${system}.home;
}) // {
nixosModules.home = { config, lib, pkgs, ... }:
let
cfg = config.services.home-web;
system = config.nixpkgs.system;
home = self.defaultPackage.${system};
in {
options = {
services.home-web = {
enable = lib.mkEnableOption "home-web";
port = lib.mkOption {
type = lib.types.int;
default = 4000;
description = "Port to listen on, 4000 by default";
};
poolSize = lib.mkOption {
type = lib.types.int;
default = 10;
description = "Connection pool size, 10 by default";
};
secretKeyBaseFile = lib.mkOption {
type = lib.types.path;
description =
"A file contianing the Phoenix Secret Key Base. This should be secret, and not kept in the nix store";
};
dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/home-web";
description = "The directory to write data to";
};
databaseUrlFile = lib.mkOption {
type = lib.types.path;
description =
"A file containing the URL to use to connect to the database";
};
user = lib.mkOption {
type = lib.types.str;
default = "home-web";
description = "The user to run as";
};
group = lib.mkOption {
type = lib.types.str;
default = "home-web";
description = "The group the user is in";
};
host = lib.mkOption {
type = lib.types.str;
description =
"The host to configure the router generation from";
};
gem = {
md2gemini = {
pkg = lib.mkOption {
type = lib.types.str;
default = "${pkgs.md2gemini}/bin/md2gemini";
};
args = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "--links" "copy" "--plain" ];
};
};
cert = lib.mkOption { type = lib.types.path; };
key = lib.mkOption { type = lib.types.path; };
};
};
};
config = lib.mkIf cfg.enable {
assertions = lib.mkIf cfg.enable [{
assertion = cfg.secretKeyBaseFile != "";
message = "A base key file is necessary";
}];
environment.systemPackages = lib.optional cfg.enable home;
users.users = lib.optionalAttrs (cfg.user == "home-web") {
home-web = {
isSystemUser = true;
group = cfg.group;
home = cfg.dataDir;
createHome = true;
};
};
users.groups =
lib.optionalAttrs (cfg.group == "home-web") { home-web = { }; };
systemd.services = {
home-web-setup = lib.mkIf cfg.enable {
description = "Create and Migrate Home Web Database";
wantedBy = [ "multi-user.target" ];
script = ''
${home}/bin/home eval "Blog.Release.migrate"
'';
serviceConfig = {
Type = "oneshot";
User = cfg.user;
Group = cfg.group;
};
environment = {
RELEASE_TMP = cfg.dataDir;
TZ_DATA_DIR = cfg.dataDir;
SECRET_KEY_BASE_FILE = cfg.secretKeyBaseFile;
DATABASE_URL_FILE = cfg.databaseUrlFile;
HOSTNAME = cfg.host;
HOME_GEMINI_CERT = cfg.gem.cert;
HOME_GEMINI_KEY = cfg.gem.key;
HOME_GEMINI_CONVERTER = cfg.gem.md2gemini.pkg;
HOME_GEMINI_CONVERTER_ARGS =
pkgs.lib.concatStringsSep " " cfg.gem.md2gemini.args;
};
};
home-web = lib.mkIf cfg.enable {
description = "Home, home on the web";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "home-web-setup.service" ];
wants = [ "home-web-setup.service" ];
script = ''
${home}/bin/home start
'';
serviceConfig = {
User = cfg.user;
Group = cfg.group;
};
environment = {
RELEASE_TMP = cfg.dataDir;
TZ_DATA_DIR = cfg.dataDir;
POOL_SIZE = builtins.toString cfg.poolSize;
SECRET_KEY_BASE_FILE = cfg.secretKeyBaseFile;
PORT = builtins.toString cfg.port;
DATABASE_URL_FILE = cfg.databaseUrlFile;
HOSTNAME = cfg.host;
HOME_GEMINI_CERT = cfg.gem.cert;
HOME_GEMINI_KEY = cfg.gem.key;
HOME_GEMINI_CONVERTER = cfg.gem.md2gemini.pkg;
HOME_GEMINI_CONVERTER_ARGS =
pkgs.lib.concatStringsSep " " cfg.gem.md2gemini.args;
};
};
};
};
};
nixosModule = self.nixosModules.home;
};
}