aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Perry <np@nathanperry.dev>2022-11-28 13:13:56 -0500
committerNathan Perry <np@nathanperry.dev>2022-11-28 13:13:56 -0500
commit14a9ad0c85b0ee6f190323a8903d1239b8968d22 (patch)
treef2747f9814ea12081f4850a8970e6d800ece3902
parent22cdf56ffccaefd0c9a4cb67cac87c7620d2d3f3 (diff)
nix: write nixos test configuration
- filter rust sources to avoid spurious rebuilds - fix accidental circular reference in nix flake - fix postgres startup scripts and behavior - thulani logger doesn't log to file by default
-rw-r--r--flake.nix154
-rw-r--r--src/db/mod.rs1
-rw-r--r--src/log_setup.rs42
-rw-r--r--src/main.rs2
4 files changed, 144 insertions, 55 deletions
diff --git a/flake.nix b/flake.nix
index 6fa6db4..b1943d9 100644
--- a/flake.nix
+++ b/flake.nix
@@ -26,7 +26,8 @@
flake-utils,
...
} @ inputs: let
- buildToolchain = pkgs: pkgs.rust-bin.nightly."2022-11-20".minimal;
+ mkBuildToolchain = pkgs: pkgs.rust-bin.nightly."2022-11-20".minimal;
+
deps = pkgs: with pkgs; [
openssl
pkgconfig
@@ -35,7 +36,7 @@
];
mkPkg = pkgs: let
- buildToolchain = buildToolchain pkgs;
+ buildToolchain = mkBuildToolchain pkgs;
naersk = pkgs.callPackage inputs.naersk {
cargo = buildToolchain;
@@ -48,7 +49,24 @@
pname = "thulani";
version = self.rev or "dirty";
- src = lib.cleanSource ./.;
+ src = lib.cleanSourceWith {
+ src = lib.cleanSource ./.;
+
+ filter = path: ty: with builtins; with lib; let
+ baseName = baseNameOf "${path}";
+ extMatch = match "((.*\\.?)*\\.)?(.*)" baseName;
+ extension = elemAt extMatch 2;
+ parent = baseNameOf (dirOf "${path}");
+ isCargoFile = baseName == "Cargo.toml" || baseName == "Cargo.lock";
+ isCargoConfig = parent == ".cargo" && baseName == "config.toml";
+ in
+ ty == "directory" ||
+ isCargoFile ||
+ isCargoConfig ||
+ extension == "rs" ||
+ extension == "sql" ||
+ extension == "pest";
+ };
nativeBuildInputs = deps pkgs;
remapPathPrefix = true;
@@ -64,7 +82,7 @@
];
};
- devToolchain = (buildToolchain pkgs).override {
+ devToolchain = (mkBuildToolchain pkgs).override {
extensions = [
"rust-src"
"rust-analyzer"
@@ -93,9 +111,58 @@
}) // {
overlays.default = final: prev: let
- withRust = (import inputs.rust-overlay) final prev;
- in {
- thulani = mkPkg withRust;
+ withRust = ((import inputs.rust-overlay) final prev);
+ in withRust // {
+ thulani = mkPkg (final // withRust);
+ };
+
+ nixosConfigurations.test = nixpkgs.lib.nixosSystem {
+ system = "x86_64-linux";
+
+ modules = [
+ self.nixosModules.default
+ "${nixpkgs}/nixos/modules/virtualisation/qemu-vm.nix"
+
+ ({ lib, ... }: {
+ nixpkgs.overlays = [
+ self.overlays.default
+ ];
+
+ users = {
+ mutableUsers = false;
+
+ users.root.hashedPassword = lib.mkForce "";
+
+ users.test = {
+ password = lib.mkForce "test";
+ group = "test";
+ isNormalUser = true;
+ extraGroups = [
+ "wheel"
+ "sudo"
+ ];
+ };
+
+ groups.test = {};
+ };
+
+ virtualisation = {
+ cores = 8;
+ graphics = false;
+ diskSize = 32*1024;
+ memorySize = 12*1024;
+ writableStoreUseTmpfs = false;
+ };
+
+ services.thulani = {
+ enable = true;
+
+ postgres = {
+ enable = true;
+ };
+ };
+ })
+ ];
};
nixosModules.default = { pkgs, lib, config, ... }: let
@@ -113,7 +180,18 @@
environment = mkOption {
description = "literal environment to include";
type = attrsOf str;
- default = {};
+
+ default = {
+ RUST_BACKTRACE = "1";
+ MAX_HIST = "30";
+ DEFAULT_HIST = "5";
+ MAX_SHEET_COLUMN = "ZZZ";
+ STEAM_API_KEY = "";
+ SPREADSHEET_ID = "";
+ SHEETS_API_KEY = "";
+ } // (optionalAttrs cfg.postgres.enable {
+ DATABASE_URL = "postgres://${cfg.user}@/${cfg.postgres.db}";
+ });
};
envFiles = mkOption {
@@ -137,13 +215,15 @@
postgres = mkOption {
description = "local postgres server with automatic setup";
- type = sumodule {
- enable = mkEnableOption "postgres";
+ type = submodule {
+ options = {
+ enable = mkEnableOption "postgres";
- db = mkOption {
- description = "db name";
- type = str;
- default = "memes";
+ db = mkOption {
+ description = "db name";
+ type = str;
+ default = "memes";
+ };
};
};
};
@@ -159,30 +239,11 @@
bindsTo = [
"network-online.target"
- ];
+ ] ++ lib.optional cfg.postgres.enable "postgresql.service";
after = [
"network-online.target"
- ];
-
- preStart = lib.mkIf (cfg.postgres.enable) (let
- invokePsql = "${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} -- ${config.services.postgresql.package}/bin/psql";
-
- in ''
- ${invokePsql} <<EOF
- DO $$
- BEGIN
- CREATE ROLE ${cfg.user};
- EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
- END
- $$;
-
- SELECT 'CREATE DATABASE ${cfg.postgres.db}'
- WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${cfg.postgres.db}')\gexec
- EOF
-
- echo 'CREATE EXTENSION IF NOT EXISTS pgcrypto' | ${invokePsql} ${cfg.postgres.db}
- '');
+ ] ++ lib.optional cfg.postgres.enable "postgresql.service";
inherit (cfg) environment;
@@ -194,8 +255,29 @@
serviceConfig = {
Type = "exec";
ExecStart = "${cfg.package}/bin/thulani";
+ ExecStartPre = let
+ invokePsql = "${pkgs.sudo}/bin/sudo -u ${config.services.postgresql.superUser} -- ${config.services.postgresql.package}/bin/psql";
+ preStart = pkgs.writeShellScript "" ''
+ set -euo pipefail
+
+ ${invokePsql} <<'EOF'
+ DO $$
+ BEGIN
+ CREATE ROLE ${cfg.user} WITH LOGIN;
+ EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping', SQLERRM USING ERRCODE = SQLSTATE;
+ END
+ $$;
+
+ SELECT 'CREATE DATABASE ${cfg.postgres.db}'
+ WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${cfg.postgres.db}')\gexec
+ EOF
+
+ echo 'CREATE EXTENSION IF NOT EXISTS pgcrypto' | ${invokePsql} ${cfg.postgres.db}
+ '';
+
+ in "+${preStart}";
- EnvironmentFile = cfg.environmentFiles;
+ EnvironmentFile = cfg.envFiles;
DynamicUser = true;
User = cfg.user;
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 483665e..476d9d9 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -54,6 +54,7 @@ pub fn connection() -> Result<PgConnection> {
MIGRATE.call_once(|| {
log::info!("running migrations");
conn.run_pending_migrations(MIGRATIONS).expect("failed running migrations");
+ log::info!("migrations complete");
});
conn
diff --git a/src/log_setup.rs b/src/log_setup.rs
index a51ebcc..c01f3f5 100644
--- a/src/log_setup.rs
+++ b/src/log_setup.rs
@@ -2,13 +2,13 @@ use crate::{Result, Error};
use fern::colors::{Color, ColoredLevelConfig};
-pub fn init() -> Result<()> {
+pub fn init(file_output: bool) -> Result<()> {
let colors = ColoredLevelConfig::new()
.info(Color::Green)
.debug(Color::BrightBlue)
.trace(Color::BrightMagenta);
- fern::Dispatch::new()
+ let mut logger = fern::Dispatch::new()
.level_for("serenity::voice::connection", log::LevelFilter::Error)
.chain(fern::Dispatch::new()
.format(move |out, message, record| {
@@ -23,21 +23,27 @@ pub fn init() -> Result<()> {
.level(log::LevelFilter::Warn)
.level_for("thulani", log::LevelFilter::Debug)
.chain(std::io::stdout())
- )
- .chain(fern::Dispatch::new()
- .format(|out, message, record| {
- out.finish(format_args!(
- "{} [{}] [{}] {}",
- chrono::Local::now().format("%_m/%_d/%y %l:%M:%S%P"),
- record.level(),
- record.target(),
- message
- ))
- })
- .level(log::LevelFilter::Info)
- .level_for("thulani", log::LevelFilter::Trace)
- .chain(fern::log_file("thulani.log").expect("problem creating log file"))
- )
+ );
+
+ if file_output {
+ logger = logger
+ .chain(fern::Dispatch::new()
+ .format(|out, message, record| {
+ out.finish(format_args!(
+ "{} [{}] [{}] {}",
+ chrono::Local::now().format("%_m/%_d/%y %l:%M:%S%P"),
+ record.level(),
+ record.target(),
+ message
+ ))
+ })
+ .level(log::LevelFilter::Info)
+ .level_for("thulani", log::LevelFilter::Trace)
+ .chain(fern::log_file("thulani.log").expect("problem creating log file"))
+ );
+ }
+
+ logger
.apply()
.map_err(Error::from)
-} \ No newline at end of file
+}
diff --git a/src/main.rs b/src/main.rs
index ffcd2f5..1bf3e98 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -59,7 +59,7 @@ const BACKOFF_INIT: f64 = 100.0;
const MIN_RUN_DURATION: Duration = Duration::from_secs(120);
fn main() {
- log_setup::init().expect("initializing logging");
+ log_setup::init(false).expect("initializing logging");
let mut backoff_count: usize = 0;