summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorstuebinm2021-03-03 00:51:39 +0100
committerstuebinm2021-03-03 00:51:39 +0100
commitd96fbd63510048bf56d3d600a65f7983096c1bb1 (patch)
tree192afecb97bcdb829e1461bebc283cc86fb99586
migrating config
This deploy logic is primarily based on hxchn's deploy lib [1], with some slight modifications to make it work with my setup. Everything seems to work fine for now. However, I am unsure about the usage of niv — the config doesn't seem to gain much from it, apart from (some) additional complexity. [1] https://gitlab.com/hexchen/nixfiles
Diffstat (limited to '')
-rw-r--r--.gitignore2
-rw-r--r--common/default.nix45
-rw-r--r--default.nix18
-rw-r--r--hosts/flora/configuration.nix69
-rw-r--r--hosts/flora/hardware-configuration.nix25
-rw-r--r--hosts/flora/services/daemoniones.nix34
-rw-r--r--hosts/flora/services/hedgedoc.nix66
-rw-r--r--hosts/flora/services/nginx.nix21
-rw-r--r--hosts/flora/services/workadventure.nix104
-rw-r--r--lib/deploy.nix23
-rw-r--r--lib/hosts.nix80
-rw-r--r--modules/default.nix5
-rw-r--r--modules/deploy/default.nix50
-rw-r--r--nix/sources.json38
-rw-r--r--nix/sources.nix171
-rw-r--r--pkgs/default.nix18
16 files changed, 769 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..80c8890
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+result
+secrets.nix
diff --git a/common/default.nix b/common/default.nix
new file mode 100644
index 0000000..69c6309
--- /dev/null
+++ b/common/default.nix
@@ -0,0 +1,45 @@
+{ config, lib, pkgs, ... }:
+
+let
+ sources = import ../nix/sources.nix;
+
+in {
+ imports = [
+ ../modules
+ ];
+
+ networking.domain = lib.mkDefault "stuebinm.eu";
+
+ services.journald.extraConfig = "MaxRetentionSec=48h";
+ nix.gc = {
+ automatic = lib.mkDefault true;
+ options = lib.mkDefault "--delete-older-than 1w";
+ };
+
+
+ i18n.defaultLocale = "en_US.UTF-8";
+ time.timeZone = "Europe/Amsterdam";
+
+ environment.systemPackages = with pkgs; [
+ wget vim htop
+ ];
+
+
+ users.users.root.openssh.authorizedKeys.keys = [
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCTeuG1alKNNqoT2d5nUAlH0Otsk0NHM7nmkYC5Yfk8qcLsgY4v2dXlyrMzieajYgDjndEApgO3/S/V0EQGhvHc0UugC6LU84jHPwsgYVABRmFS74v/ww8NigaNIAevwWl+DxlnK4nnWdB1lo4xS69ooQdvoAjbubk16dP04LsAbH8Z+3cPB5WKAaayNx62DUwObzDSpztqCagCZzlqpwKG1UGJngrqEhk7B5Q0v9iCk91gqVkLSPllsB00+bqIimgkMVIZnoLLh7pcEgOvbG0yP2EG3ttDNN3jPpqE6mu+znfLq+ua/MwJy5hjmY5R54yPlcvFdsIU34jrdMCDvWqpV49VrLwVvkFN3lRZln/9eifkXXJciP4Ber3xEl8JltysV1PE5iJunWfbcOy0fwsYvBChDeyR5G3CLG2c25jKL9f1Iq95QBBMVYgIxq/dpGy0tjB+24w1JzsorvElsmz5etXLXCydLP07ic9PfSu1Wmwu7F0tweIk52x97sra6ePhtY+TTRffjjDz0DEho1bWDfrPV0xfPPAWXWTKYisVO4VVmMQsJbtXrfxUJbappM5vIXcJ+2JpT2Oh7Kiy3rjm+pd7rukgoCp7yN5z8v+2vuOfHqBuKUwlaRg/XNMyPrbnGGzVR1xzUuhwdOnjAyMmAr95Ne9hRBPwfVo2NR/ZZw=="
+ ];
+
+ services.openssh = {
+ enable = true;
+ permitRootLogin = "prohibit-password";
+ passwordAuthentication = false;
+ };
+
+ security.sudo.enable = false;
+
+ security.acme = {
+ acceptTerms = true;
+ email = "stuebinm@disroot.org";
+ };
+
+}
diff --git a/default.nix b/default.nix
new file mode 100644
index 0000000..f13eb77
--- /dev/null
+++ b/default.nix
@@ -0,0 +1,18 @@
+let
+ sources = import ./nix/sources.nix;
+ pkgs = import ./pkgs {};
+
+ hosts = import ./lib/hosts.nix {
+ inherit pkgs;
+ hostsDir = ./hosts;
+ commonImports = [ ./common ];
+ pkgsPath = ./pkgs;
+ };
+in
+{
+ inherit sources pkgs;
+ inherit (hosts) hosts groups;
+ deploy = import ./lib/deploy.nix { inherit pkgs; inherit (hosts) hosts groups; };
+}
+
+
diff --git a/hosts/flora/configuration.nix b/hosts/flora/configuration.nix
new file mode 100644
index 0000000..43f7f8e
--- /dev/null
+++ b/hosts/flora/configuration.nix
@@ -0,0 +1,69 @@
+{ config, pkgs, ... }:
+
+{
+ imports = [
+ ./hardware-configuration.nix
+ ./services/hedgedoc.nix
+ ./services/daemoniones.nix
+ ./services/nginx.nix
+ ./services/workadventure.nix
+ # ./services/pleroma
+ ];
+
+ # Use the GRUB 2 boot loader.
+ boot.loader.grub.enable = true;
+ boot.loader.grub.version = 2;
+ boot.loader.grub.devices = [ "/dev/sda" ];
+
+ hexchen.deploy = {
+ ssh.host = "flora";
+ };
+
+ networking = {
+ hostName = "flora";
+
+ #enableIPv6 = true;
+ #defaultGateway6 = {
+ # address = "fe80::1";
+ # interface = "ens3";
+ #};
+
+ #interfaces.ens3.ipv6.addresses = [ {
+ # address = "2a01:4f9:c010:d319::1";
+ # prefixLength = 64;
+ #} ];
+
+ useDHCP = false;
+ interfaces.ens3.useDHCP = true;
+
+ firewall.logRefusedConnections = false;
+ };
+
+ services.fail2ban = {
+ enable = true;
+ bantime-increment.enable = true;
+ bantime-increment.overalljails = true;
+ bantime-increment.maxtime = "1312m";
+ };
+
+ services.logrotate = {
+ enable = true;
+ paths.nginx = {
+ path = "/var/log/nginx";
+ frequency = "weekly";
+ };
+ };
+
+
+ # This value determines the NixOS release from which the default
+ # settings for stateful data, like file locations and database versions
+ # on your system were taken. It‘s perfectly fine and recommended to leave
+ # this value at the release version of the first install of this system.
+ # Before changing this value read the documentation for this option
+ # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+ system = {
+ stateVersion = "20.09"; # Did you read the comment?
+ };
+
+}
+
diff --git a/hosts/flora/hardware-configuration.nix b/hosts/flora/hardware-configuration.nix
new file mode 100644
index 0000000..faac1af
--- /dev/null
+++ b/hosts/flora/hardware-configuration.nix
@@ -0,0 +1,25 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, ... }:
+
+{
+ imports =
+ [ <nixpkgs/nixos/modules/profiles/qemu-guest.nix>
+ ];
+
+ boot.initrd.availableKernelModules = [ "ata_piix" "virtio_pci" "xhci_pci" "sd_mod" "sr_mod" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/5d31cad5-9076-4d2f-93f6-6af817bc368b";
+ fsType = "ext4";
+ };
+
+ swapDevices = [ ];
+
+ nix.maxJobs = lib.mkDefault 1;
+}
+
diff --git a/hosts/flora/services/daemoniones.nix b/hosts/flora/services/daemoniones.nix
new file mode 100644
index 0000000..6c96b3c
--- /dev/null
+++ b/hosts/flora/services/daemoniones.nix
@@ -0,0 +1,34 @@
+{ config, pkgs, ...}:
+
+{
+ systemd.services =
+ let simpledaemon = name: command: {
+ enable = true;
+ description = name;
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig.Type = "simple";
+ script = command;
+ };
+ in {
+ choclo = simpledaemon "choclo signalling server" "/root/simple-signalling/target/release/chaski -b 127.0.0.1:5000";
+ wasi = simpledaemon "wasi backend" "/root/wasi-minimal/target/release/wasi";
+ picarones = simpledaemon "picarones backend" "/root/picarones-server/target/release/picarones -b 127.0.0.1:6000";
+ };
+
+ services.nginx = {
+ virtualHosts =
+ let websocketproxy = addr: {
+ locations."/".proxyPass = addr;
+ forceSSL = true;
+ enableACME = true;
+ locations."/".proxyWebsockets = true;
+ };
+ in {
+ "wasi.stuebinm.eu" = websocketproxy "http://127.0.0.1:9000";
+ "choclo.stuebinm.eu" = websocketproxy "http://127.0.0.1:5000";
+ "picarones.stuebinm.eu" = websocketproxy "http://127.0.0.1:6000";
+ };
+ };
+
+
+}
diff --git a/hosts/flora/services/hedgedoc.nix b/hosts/flora/services/hedgedoc.nix
new file mode 100644
index 0000000..4ce2256
--- /dev/null
+++ b/hosts/flora/services/hedgedoc.nix
@@ -0,0 +1,66 @@
+{ config, lib, pkgs, ... }:
+
+{
+ # Container containing CodiMD and its database
+ # has its own internal network; needs a reverse-proxy to be reachable from the outside
+ # TODO: persistent memory for pads
+ containers.codimd = {
+ autoStart = true;
+ privateNetwork = true;
+ hostAddress6 = "fd00::42:10";
+ localAddress6 = "fd00::42:11";
+
+ config = {config, pkgs, ... }: {
+ # open CodiMD port
+ networking.firewall.allowedTCPPorts = [ config.services.codimd.configuration.port ];
+
+ # database (postgres 11), with default database reachable for CodiMD; no imperative config needed!
+ services.postgresql = {
+ enable = true;
+ package = pkgs.postgresql_11;
+ ensureDatabases = [ "codimd" ];
+ ensureUsers = [ {
+ name = "codimd";
+ ensurePermissions = { "DATABASE codimd" = "ALL PRIVILEGES";};
+ } ];
+ # ugly workaround to allow CodiMD to login without password — this service has lots of options,
+ # but apparently not for authentification, which even needs to be forced …
+ authentication = pkgs.lib.mkForce ''
+ # Generated file; do not edit!
+ local all all trust
+ host codimd codimd ::1/128 trust
+ '';
+ };
+ # CodiMD itself
+ services.hedgedoc = {
+ enable = true;
+ workDir = "/var/codimd/";
+ configuration = {
+ dbURL = "postgres:///codimd";
+ port = 3000;
+ domain = "nix.stuebinm.eu";
+ urlAddPort = false;
+ protocolUseSSL = true;
+ allowPDFExport = true;
+ host = "::";
+ allowEmailRegister = false;
+ allowFreeURL = true;
+ uploadsPath = "/var/codimd/uploads";
+ #email = false;
+ };
+ };
+ };
+ };
+
+
+ networking.firewall.allowedTCPPorts = [ 80 443 ];
+
+ services.nginx.virtualHosts."nix.stuebinm.eu" = {
+ locations."/" = {
+ proxyPass = "http://[" + config.containers.codimd.localAddress6 + "]:3000";
+ proxyWebsockets = true;
+ };
+ forceSSL = true;
+ enableACME = true;
+ };
+}
diff --git a/hosts/flora/services/nginx.nix b/hosts/flora/services/nginx.nix
new file mode 100644
index 0000000..5d21a14
--- /dev/null
+++ b/hosts/flora/services/nginx.nix
@@ -0,0 +1,21 @@
+{ config, lib, pkgs, ... }:
+
+{
+ networking.firewall.allowedTCPPorts = [ 80 443 ];
+
+ services.nginx = {
+ enable = true;
+
+ recommendedOptimisation = true;
+ recommendedTlsSettings = true;
+ recommendedProxySettings = true;
+
+ # virtualHosts = {
+ # "stuebinm.eu" = {
+ # forceSSL = true;
+ # enableACME = true;
+ # root = "/var/www/stats";
+ # };
+ # };
+ };
+}
diff --git a/hosts/flora/services/workadventure.nix b/hosts/flora/services/workadventure.nix
new file mode 100644
index 0000000..f38f5da
--- /dev/null
+++ b/hosts/flora/services/workadventure.nix
@@ -0,0 +1,104 @@
+{pkgs, config, ...}:
+
+
+let
+ haccpkgssrc = pkgs.fetchgit {
+ url = "https://gitlab.infra4future.de/stuebinm/workadventure-nix-hacc";
+ rev = "a4ffb828aadf5ffd54a269f8a9ec9553c016069b";
+ sha256 = "12qfisfwr170b94j12rhy2q3smrwc7a3nh6xzbxlphnr3vadplvz";
+ };
+ haccpkgs = import "${haccpkgssrc}";
+ fediventure = pkgs.fetchgit {
+ url = "https://gitlab.infra4future.de/stuebinm/fediventure-simple";
+ rev = "f32d3c5efd39df558f80b862c60b2866c567d999";
+ sha256 = "0kdb29hzh6s7rsz8s9z40hsmj09rrww1lcyfdi7wpng9ixi1jfvx";
+ };
+in
+
+{
+
+ containers.wa-test = {
+ autoStart = true;
+ privateNetwork = true;
+ hostAddress6 = "fd00::42:20";
+ localAddress6 = "fd00::42:21";
+
+ config = {config, pkgs, ...}: {
+ imports = [ "${fediventure}/workadventure.nix" ];
+ networking.firewall.allowedTCPPorts = [ 80 443 5000 7890 ];
+
+ services.workadventure.instances."space.stuebinm.eu" = {
+ nginx.default = true;
+ nginx.domain = "space.stuebinm.eu";
+ maps.path = haccpkgs.workadventure-hacc-rc3-map.outPath + "/";
+ frontend.settings.startRoomUrl = "space.stuebinm.eu/maps/main.json";
+ frontend.settings = {
+ stunServer = "stun:chaski.stuebinm.eu:3478";
+ turnServer = "turn:95.217.159.23";
+ turnUser = "chaski";
+ turnPassword = "chaski";
+ jitsiUrl = "meet.ffmuc.net";
+ };
+ };
+
+ services.prometheus = {
+ enable = true;
+ port = 9001;
+ scrapeConfigs = [ {
+ job_name = "workadventure-back";
+ static_configs = [ {
+ targets = [ "localhost:8080" ];
+ } ];
+ } ];
+ };
+
+ services.grafana = {
+ enable = true;
+ port = 5000;
+ addr = "[::]";
+ rootUrl = "https://space.stuebinm.eu/metrics/";
+ auth.anonymous.enable = true;
+ provision = {
+ enable = true;
+ datasources = [ {
+ name = "workadventure";
+ type = "prometheus";
+ url = "http://localhost:9001";
+ } ];
+ };
+ };
+
+ systemd.services.goaccess = {
+ enable = true;
+ description = "Uses goaccess to publish a neat acces log on /var/www/index.html";
+ requires = [ "nginx.service" ];
+ wantedBy = [ "multi-user.target" ];
+ serviceConfig.Type = "simple";
+ path = [ pkgs.goaccess ];
+ environment = {"HOME" = "/tmp";}; # necessary as goaccess will crash otherwise — is fixed upstream, but not yet in nixos
+ script = ''
+ mkdir -p /var/www-goaccess/
+ goaccess /var/log/nginx/access.log -o /var/www-goaccess/index.html --log-format=COMBINED --html
+ '';
+ };
+
+ services.nginx.virtualHosts."space.stuebinm.eu" = {
+ locations."/stats/".alias = "/var/www-goaccess/";
+ };
+ };
+ };
+
+ services.nginx.virtualHosts."space.stuebinm.eu" = {
+ extraConfig = ''
+ proxy_read_timeout 300s;
+ proxy_connect_timeout 75s;
+ '';
+ locations."/metrics/".proxyPass = "http://[${config.containers.wa-test.localAddress6}]:5000/";
+ locations."/metrics/".proxyWebsockets = true;
+ locations."/".proxyPass = "http://[${config.containers.wa-test.localAddress6}]:80";
+ locations."/".proxyWebsockets = true;
+ enableACME = true;
+ forceSSL = true;
+ };
+}
+
diff --git a/lib/deploy.nix b/lib/deploy.nix
new file mode 100644
index 0000000..1b8d1f2
--- /dev/null
+++ b/lib/deploy.nix
@@ -0,0 +1,23 @@
+{ pkgs, hosts, groups }:
+
+with pkgs.lib;
+
+(
+ mapAttrs (name: hosts: pkgs.writeScript "deploy-group-${name}" ''
+ #!${pkgs.runtimeShell}
+ export PATH=
+ ${concatMapStrings (host: ''
+ echo "deploying ${host.config.networking.hostName}..."
+ ${host.config.system.build.deployScript} $1 &
+ PID_LIST+=" $!"
+ '') hosts}
+ # FIXME: remove jobs from PIDLIST once they finish
+ trap "kill $PID_LIST" SIGINT
+ wait $PID_LIST
+ '') groups
+) // (
+ mapAttrs
+ (name: host: host.config.system.build.deployScript)
+ (filterAttrs (_: host: host.config.hexchen.deploy.enable) hosts)
+)
+
diff --git a/lib/hosts.nix b/lib/hosts.nix
new file mode 100644
index 0000000..91b6b40
--- /dev/null
+++ b/lib/hosts.nix
@@ -0,0 +1,80 @@
+{
+ pkgs,
+ hostsDir ? ../hosts,
+ commonImports ? [],
+ pkgsPath ? ../pkgs,
+ modules ? {},
+ overlays ? {},
+ profiles ? {},
+ users ? {},
+ sources ? {}
+}:
+
+with pkgs.lib;
+
+rec {
+ hostNames = attrNames (
+ filterAttrs (
+ name: type: type == "directory"
+ ) (
+ builtins.readDir hostsDir
+ )
+ );
+
+ hostConfig = hostName: { config, ... }: {
+ _module.args = {
+ inherit hosts groups;
+ };
+ imports = [
+ (import (hostsDir + "/${hostName}/configuration.nix"))
+ # urgh, yes, we still need to manually import the deploy module for now
+ # at least if i want to keep my thing reusable.
+ ../modules/deploy
+ ] ++ commonImports;
+ networking = {
+ inherit hostName;
+ };
+ nixpkgs.pkgs =
+ let pkgs = import pkgsPath {
+ inherit (config.nixpkgs) config system;
+ };
+ in if pkgs ? nixpkgs then pkgs.nixpkgs else pkgs;
+ };
+
+ hosts = listToAttrs (
+ map (
+ hostName: nameValuePair hostName (
+ import (pkgs.path + "/nixos/lib/eval-config.nix") {
+ modules = [
+ (hostConfig hostName)
+ (if sources ? home-manager then sources.home-manager + "/nixos" else {})
+ ];
+ specialArgs = { inherit modules overlays profiles users sources; };
+ }
+ )
+ ) hostNames
+ );
+
+ groupNames = unique (
+ concatLists (
+ mapAttrsToList (
+ name: host: host.config.hexchen.deploy.groups
+ ) hosts
+ )
+ );
+
+ groups = listToAttrs (
+ map (
+ groupName: nameValuePair groupName (
+ filter (
+ host: elem groupName host.config.hexchen.deploy.groups
+ ) (
+ attrValues (
+ filterAttrs (_: h: h.config.hexchen.deploy.enable) hosts
+ )
+ )
+ )
+ ) groupNames
+ );
+}
+
diff --git a/modules/default.nix b/modules/default.nix
new file mode 100644
index 0000000..23a8abc
--- /dev/null
+++ b/modules/default.nix
@@ -0,0 +1,5 @@
+{...}:
+
+{
+ imports = [ ];
+}
diff --git a/modules/deploy/default.nix b/modules/deploy/default.nix
new file mode 100644
index 0000000..e8bc827
--- /dev/null
+++ b/modules/deploy/default.nix
@@ -0,0 +1,50 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.hexchen.deploy;
+
+in {
+ options = {
+ hexchen.deploy = {
+ enable = mkOption {
+ type = types.bool;
+ default = true;
+ };
+ ssh.host = mkOption {
+ type = types.str;
+ default = "${config.networking.hostName}.${config.networking.domain}";
+ };
+ ssh.port = mkOption {
+ type = types.int;
+ default = head config.services.openssh.ports;
+ };
+ substitute = mkOption {
+ type = types.bool;
+ default = true;
+ };
+ groups = mkOption {
+ type = with types; listOf str;
+ default = [];
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ hexchen.deploy.groups = [ "all" ];
+
+ system.build.deployScript = let
+ superuser = if config.security.sudo.enable then "sudo" else "";
+ in pkgs.writeScript "deploy-${config.networking.hostName}" ''
+ #!${pkgs.runtimeShell}
+ set -xeo pipefail
+ export PATH=${with pkgs; lib.makeBinPath [ coreutils openssh nix ]}
+ export NIX_SSHOPTS="$NIX_SSHOPTS -p${toString cfg.ssh.port}"
+ nix copy ${if cfg.substitute then "-s" else ""} --no-check-sigs --to ssh://${cfg.ssh.host} ${config.system.build.toplevel}
+ ssh $NIX_SSHOPTS ${cfg.ssh.host} "${superuser} nix-env -p /nix/var/nix/profiles/system -i ${config.system.build.toplevel}"
+ ssh $NIX_SSHOPTS ${cfg.ssh.host} "${superuser} /nix/var/nix/profiles/system/bin/switch-to-configuration $1"
+ '';
+ };
+}
+
diff --git a/nix/sources.json b/nix/sources.json
new file mode 100644
index 0000000..9bff238
--- /dev/null
+++ b/nix/sources.json
@@ -0,0 +1,38 @@
+{
+ "niv": {
+ "branch": "master",
+ "description": "Easy dependency management for Nix projects",
+ "homepage": "https://github.com/nmattia/niv",
+ "owner": "nmattia",
+ "repo": "niv",
+ "rev": "af958e8057f345ee1aca714c1247ef3ba1c15f5e",
+ "sha256": "1qjavxabbrsh73yck5dcq8jggvh3r2jkbr6b5nlz5d9yrqm9255n",
+ "type": "tarball",
+ "url": "https://github.com/nmattia/niv/archive/af958e8057f345ee1aca714c1247ef3ba1c15f5e.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ },
+ "nixpkgs": {
+ "branch": "release-20.09",
+ "description": "Nix Packages collection",
+ "homepage": "",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "70646d6578be464fe81c3fbc891baa7066a43ad1",
+ "sha256": "1cvjrdi38l78yan3jspidw34m27cpkwyvw1a5k9zqfccb4hp8abs",
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/70646d6578be464fe81c3fbc891baa7066a43ad1.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ },
+ "nixpkgs-unstable": {
+ "branch": "nixpkgs-unstable",
+ "description": "Nix Packages collection",
+ "homepage": "",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "04ac9dcd311956d1756d77f4baf9258392ee7bdd",
+ "sha256": "10r7s2bimvijq1znhiypc99zvzzfqilzyzzg62q5xk2cr4gs03g9",
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/04ac9dcd311956d1756d77f4baf9258392ee7bdd.tar.gz",
+ "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
+ }
+}
diff --git a/nix/sources.nix b/nix/sources.nix
new file mode 100644
index 0000000..b796fff
--- /dev/null
+++ b/nix/sources.nix
@@ -0,0 +1,171 @@
+# This file has been generated by Niv.
+
+let
+
+ #
+ # The fetchers. fetch_<type> fetches specs of type <type>.
+ #
+
+ fetch_file = pkgs: name: spec:
+ let
+ name' = sanitizeName name + "-src";
+ in
+ if spec.builtin or true then
+ builtins_fetchurl { inherit (spec) url sha256; name = name'; }
+ else
+ pkgs.fetchurl { inherit (spec) url sha256; name = name'; };
+
+ fetch_tarball = pkgs: name: spec:
+ let
+ name' = sanitizeName name + "-src";
+ in
+ if spec.builtin or true then
+ builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
+ else
+ pkgs.fetchzip { name = name'; inherit (spec) url sha256; };
+
+ fetch_git = name: spec:
+ let
+ ref =
+ if spec ? ref then spec.ref else
+ if spec ? branch then "refs/heads/${spec.branch}" else
+ if spec ? tag then "refs/tags/${spec.tag}" else
+ abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!";
+ in
+ builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; };
+
+ fetch_local = spec: spec.path;
+
+ fetch_builtin-tarball = name: throw
+ ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
+ $ niv modify ${name} -a type=tarball -a builtin=true'';
+
+ fetch_builtin-url = name: throw
+ ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
+ $ niv modify ${name} -a type=file -a builtin=true'';
+
+ #
+ # Various helpers
+ #
+
+ # https://github.com/NixOS/nixpkgs/pull/83241/files#diff-c6f540a4f3bfa4b0e8b6bafd4cd54e8bR695
+ sanitizeName = name:
+ (
+ concatMapStrings (s: if builtins.isList s then "-" else s)
+ (
+ builtins.split "[^[:alnum:]+._?=-]+"
+ ((x: builtins.elemAt (builtins.match "\\.*(.*)" x) 0) name)
+ )
+ );
+
+ # The set of packages used when specs are fetched using non-builtins.
+ mkPkgs = sources: system:
+ let
+ sourcesNixpkgs =
+ import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) { inherit system; };
+ hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
+ hasThisAsNixpkgsPath = <nixpkgs> == ./.;
+ in
+ if builtins.hasAttr "nixpkgs" sources
+ then sourcesNixpkgs
+ else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
+ import <nixpkgs> {}
+ else
+ abort
+ ''
+ Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
+ add a package called "nixpkgs" to your sources.json.
+ '';
+
+ # The actual fetching function.
+ fetch = pkgs: name: spec:
+
+ if ! builtins.hasAttr "type" spec then
+ abort "ERROR: niv spec ${name} does not have a 'type' attribute"
+ else if spec.type == "file" then fetch_file pkgs name spec
+ else if spec.type == "tarball" then fetch_tarball pkgs name spec
+ else if spec.type == "git" then fetch_git name spec
+ else if spec.type == "local" then fetch_local spec
+ else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
+ else if spec.type == "builtin-url" then fetch_builtin-url name
+ else
+ abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";
+
+ # If the environment variable NIV_OVERRIDE_${name} is set, then use
+ # the path directly as opposed to the fetched source.
+ replace = name: drv:
+ let
+ saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name;
+ ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}";
+ in
+ if ersatz == "" then drv else ersatz;
+
+ # Ports of functions for older nix versions
+
+ # a Nix version of mapAttrs if the built-in doesn't exist
+ mapAttrs = builtins.mapAttrs or (
+ f: set: with builtins;
+ listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
+ );
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
+ range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
+ stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));
+
+ # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
+ stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
+ concatMapStrings = f: list: concatStrings (map f list);
+ concatStrings = builtins.concatStringsSep "";
+
+ # https://github.com/NixOS/nixpkgs/blob/8a9f58a375c401b96da862d969f66429def1d118/lib/attrsets.nix#L331
+ optionalAttrs = cond: as: if cond then as else {};
+
+ # fetchTarball version that is compatible between all the versions of Nix
+ builtins_fetchTarball = { url, name ? null, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchTarball;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchTarball ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
+ else
+ fetchTarball attrs;
+
+ # fetchurl version that is compatible between all the versions of Nix
+ builtins_fetchurl = { url, name ? null, sha256 }@attrs:
+ let
+ inherit (builtins) lessThan nixVersion fetchurl;
+ in
+ if lessThan nixVersion "1.12" then
+ fetchurl ({ inherit url; } // (optionalAttrs (!isNull name) { inherit name; }))
+ else
+ fetchurl attrs;
+
+ # Create the final "sources" from the config
+ mkSources = config:
+ mapAttrs (
+ name: spec:
+ if builtins.hasAttr "outPath" spec
+ then abort
+ "The values in sources.json should not have an 'outPath' attribute"
+ else
+ spec // { outPath = replace name (fetch config.pkgs name spec); }
+ ) config.sources;
+
+ # The "config" used by the fetchers
+ mkConfig =
+ { sourcesFile ? if builtins.pathExists ./sources.json then ./sources.json else null
+ , sources ? if isNull sourcesFile then {} else builtins.fromJSON (builtins.readFile sourcesFile)
+ , system ? builtins.currentSystem
+ , pkgs ? mkPkgs sources system
+ }: rec {
+ # The sources, i.e. the attribute set of spec name to spec
+ inherit sources;
+
+ # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
+ inherit pkgs;
+ };
+
+in
+mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }
diff --git a/pkgs/default.nix b/pkgs/default.nix
new file mode 100644
index 0000000..94d012a
--- /dev/null
+++ b/pkgs/default.nix
@@ -0,0 +1,18 @@
+{ ... }:
+
+let
+ sources = import ../nix/sources.nix;
+ pkgs = import sources.nixpkgs {};
+
+ callPackage = pkgs.lib.callPackageWith (pkgs // newpkgs);
+
+ newpkgs = {
+# pleroma = callPackage "${sources.pbb-nixfiles}/pkgs/pleroma" {};
+# dendrite = callPackage "${sources.nixchen}/pkgs/dendrite" {};
+
+ inherit callPackage;
+ appendOverlays = overlays: (pkgs.appendOverlays overlays) // newpkgs;
+ };
+
+in pkgs // newpkgs
+