diff options
Diffstat (limited to 'system/services/nix-sync/default.nix')
-rw-r--r-- | system/services/nix-sync/default.nix | 159 |
1 files changed, 115 insertions, 44 deletions
diff --git a/system/services/nix-sync/default.nix b/system/services/nix-sync/default.nix index 18511b3..5c2ed80 100644 --- a/system/services/nix-sync/default.nix +++ b/system/services/nix-sync/default.nix @@ -6,47 +6,85 @@ }: let cfg = config.services.nix-sync; + mkTimer = name: repo: { + description = "Nix sync ${name} timer"; + wantedBy = ["timers.target"]; + timerConfig = { + OnActiveSec = repo.interval; + }; + after = ["network-online.target"]; + }; + + parents = path: let + split_path = builtins.split "/" path; + filename = builtins.elemAt split_path (builtins.length split_path - 1); + in + lib.strings.removeSuffix "/" (builtins.replaceStrings [filename] [""] path); + esa = lib.strings.escapeShellArg; mkUnit = name: repo: let - esa = lib.strings.escapeShellArg; - execStartScript = lib.writeShellScript "git-sync-exec" '' - cd ${esa cfg.cachePath}/${esa repo.path}; + optionalPathSeparator = + if lib.strings.hasPrefix "/" repo.path + then "" + else "/"; + repoCachePath = cfg.cachePath + optionalPathSeparator + repo.path; + execStartScript = pkgs.writeScript "nix-sync-exec" '' + #! /usr/bin/env dash + export XDG_CACHE_HOME="$CACHE_DIRECTORY"; + cd ${esa repoCachePath}; - while true; do - origin="$(git rev-parse @{u})"; - branch="$(git rev-parse @)"; + git fetch + origin="$(git rev-parse @{u})"; + branch="$(git rev-parse @)"; - if ! [ "$origin" = "$branch" ]; then - git pull; + if ! [ "$origin" = "$branch" ]; then + git pull; - out_paths=$(mktemp); - nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; - [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1) - out_path="$(cat "$out_paths")"; - rm -r ${esa repo.path}; - ln -s "$out_path" ${esa repo.path}; - rm "$out-paths"; - fi - sleep ${esa repo.interval}; - done + out_paths=$(mktemp); + nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; + [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1) + out_path="$(cat "$out_paths")"; + rm ${esa repo.path}; + ln -s "$out_path" ${esa repo.path}; + rm "$out_paths"; + fi ''; execStartPreScript = '' - if ! stat ${esa cfg.cachePath}/${esa repo.path}/.git; then - mkdir --parents ${esa cfg.cachePath}/${esa repo.path}; - git clone ${esa repo.uri} ${esa cfg.cachePath}/${esa repo.path}; + export XDG_CACHE_HOME="$CACHE_DIRECTORY"; + + if ! [ -d ${esa repoCachePath}/.git ]; then + mkdir --parents ${esa repoCachePath}; + git clone ${esa repo.uri} ${esa repoCachePath}; out_paths=$(mktemp); - nix build ${esa cfg.cachePath}/${esa repo.path} --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; + nix build ${esa repoCachePath} --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1) out_path="$(cat "$out_paths")"; ln -s "$out_path" ${esa repo.path}; - rm "$out-paths"; + rm "$out_paths"; + fi + + if ! [ -L ${esa repo.path} ]; then + cd ${esa repoCachePath}; + + git pull; + + out_paths=$(mktemp); + nix build . --print-out-paths --experimental-features 'nix-command flakes' > "$out_paths"; + [ "$(wc -l < "$out_paths")" -gt 1 ] && (echo "To many out-paths"; exit 1) + out_path="$(cat "$out_paths")"; + + [ -d ${esa repo.path} ] && rm -d ${esa repo.path}; + [ -e ${esa repo.path} ] && rm ${esa repo.path}; + + ln -s "$out_path" ${esa repo.path}; + rm "$out_paths"; fi ''; in { description = "Nix Sync ${name}"; wantedBy = ["default.target"]; after = ["network.target"]; - path = with pkgs; [openssh git nix mktemp coreutils]; + path = with pkgs; [openssh git nix mktemp coreutils dash]; preStart = execStartPreScript; serviceConfig = { @@ -56,16 +94,16 @@ User = cfg.user; Group = cfg.group; # Runtime directory and mode - RuntimeDirectory = "nginx"; + RuntimeDirectory = "nix-sync"; RuntimeDirectoryMode = "0750"; # Cache directory and mode - CacheDirectory = "nginx"; + CacheDirectory = "nix-sync"; CacheDirectoryMode = "0750"; # Logs directory and mode - LogsDirectory = "nginx"; + LogsDirectory = "nix-sync"; LogsDirectoryMode = "0750"; # Proc filesystem - ProcSubset = "pid"; + ProcSubset = "all"; ProtectProc = "invisible"; # New file permissions UMask = "0027"; # 0640 / 0750 @@ -75,7 +113,8 @@ # Security NoNewPrivileges = true; # Sandboxing (sorted by occurrence in https://www.freedesktop.org/software/systemd/man/systemd.exec.html) - ReadWritePaths = ["${repo.path}" "${cfg.cachePath}/${repo.path}"]; + ReadWritePaths = ["${esa (parents repo.path)}" "-${esa repoCachePath}" "-${esa cfg.cachePath}"]; + ReadOnlyPaths = ["/nix"]; ProtectSystem = "strict"; ProtectHome = true; PrivateTmp = true; @@ -102,10 +141,23 @@ services = lib.mapAttrs' (name: repo: { - name = "git-sync-${name}"; + name = "nix-sync-${name}"; value = mkUnit name repo; }) cfg.repositories; + timers = + lib.mapAttrs' (name: repo: { + name = "nix-sync-${name}"; + value = mkTimer name repo; + }) + cfg.repositories; + + # generate the websites directory, so systemd can mount it read write + generatedDirectories = + lib.mapAttrsToList ( + _: repo: "d ${esa (parents repo.path)} 0755 ${cfg.user} ${cfg.group}" + ) + cfg.repositories; repositoryType = lib.types.submodule ({name, ...}: { options = { @@ -123,7 +175,7 @@ uri = lib.mkOption { type = lib.types.str; - example = "git+ssh://user@example.com:/~[user]/path/to/repo.git"; + example = "ssh://user@example.com:/~[user]/path/to/repo.git"; description = '' The URI of the remote to be synchronized. This is only used in the event that the directory does not already exist. See @@ -137,24 +189,15 @@ default = 500; description = '' The interval, specified in seconds, at which the synchronization will - be triggered even without filesystem changes. + be triggered. ''; }; }; }); in { options = { - services.git-sync = { - enable = lib.mkEnableOption "git-sync services"; - - package = lib.mkOption { - type = lib.types.package; - default = pkgs.git-sync; - defaultText = lib.literalExpression "pkgs.git-sync"; - description = '' - Package containing the <command>git-sync</command> program. - ''; - }; + services.nix-sync = { + enable = lib.mkEnableOption "nix-sync services"; user = lib.mkOption { type = lib.types.str; @@ -172,7 +215,7 @@ in { type = lib.types.str; default = "/var/lib/nix-sync"; description = lib.mdDoc '' - Where to cache git directories. + Where to cache git directories. Should not end with a slash ("/") ''; }; @@ -186,7 +229,35 @@ in { }; config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = !lib.strings.hasSuffix "/" cfg.cachePath; + message = "Your cachePath ('${cfg.cachePath}') ends with a slash ('/'), please use: '${lib.strings.removeSuffix "/" cfg.cachePath}'."; + } + ]; + + systemd.tmpfiles.rules = + generatedDirectories; + systemd.services = services; + systemd.timers = timers; + users.users = + if cfg.user == "nix-sync" + then { + nix-sync = { + group = "${cfg.group}"; + isSystemUser = true; + }; + } + else lib.warnIf (cfg.user != "nix-sync") "The user (${cfg.user}) is not \"nix-sync\", thus you are responible for generating it."; + users.groups = + if cfg.group == "nix-sync" + then { + nix-sync = { + members = ["${cfg.user}"]; + }; + } + else lib.warnIf (cfg.group != "nix-sync") "The group (${cfg.group}) is not \"nix-sync\", thus you are responible for generating it."; }; } # vim: ts=2 |