diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | common/default.nix | 45 | ||||
-rw-r--r-- | default.nix | 18 | ||||
-rw-r--r-- | hosts/flora/configuration.nix | 69 | ||||
-rw-r--r-- | hosts/flora/hardware-configuration.nix | 25 | ||||
-rw-r--r-- | hosts/flora/services/daemoniones.nix | 34 | ||||
-rw-r--r-- | hosts/flora/services/hedgedoc.nix | 66 | ||||
-rw-r--r-- | hosts/flora/services/nginx.nix | 21 | ||||
-rw-r--r-- | hosts/flora/services/workadventure.nix | 104 | ||||
-rw-r--r-- | lib/deploy.nix | 23 | ||||
-rw-r--r-- | lib/hosts.nix | 80 | ||||
-rw-r--r-- | modules/default.nix | 5 | ||||
-rw-r--r-- | modules/deploy/default.nix | 50 | ||||
-rw-r--r-- | nix/sources.json | 38 | ||||
-rw-r--r-- | nix/sources.nix | 171 | ||||
-rw-r--r-- | pkgs/default.nix | 18 |
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 + |