{ config, lib, pkgs, ... }: { options.zpha.websites."git.zaphyra.eu".enable = lib.mkEnableOption ""; config = lib.mkIf config.zpha.websites."git.zaphyra.eu".enable ( let adminPubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILTOkSPzd70xNTgPOylix/lb5JKYdt+URoewlmGRP3oZ"; title = "zaphyra's git"; mail = "git@zaphyra.eu"; categories = [ "nix" "etc" "javascript" "golang" "nimlang" "nimlang libraries" "archive" ]; stagitFunctions = pkgs.writeShellScript "stagitFunctions" '' is_public_and_listed() { if [ ! -f "$1/git-daemon-export-ok" ]; then return 1 fi return 0 } is_forced_update() { test "$oldrev" = "0000000000000000000000000000000000000000" && return 1 test "$newrev" = "0000000000000000000000000000000000000000" && return 1 hasrevs="$(${pkgs.git}/bin/git rev-list "$oldrev" "^$newrev" | ${pkgs.gnused}/bin/sed 1q)" if test -n "$hasrevs"; then return 0 fi return 1 } build_stagit_repo() { reponame="$(basename "$1" ".git")" printf "[%s] Generate stagit HTML pages... " "$reponame" mkdir -p "${config.common.services.gitolite.dataDir}/stagit-cache" mkdir -p "/var/lib/stagit/$reponame" cd "/var/lib/stagit/$reponame" || return 1 # build repo pages ${lib.getExe pkgs.zpha.stagit} -c "${config.common.services.gitolite.dataDir}/stagit-cache/$reponame" -n "${title}" -h 'https://git.zaphyra.eu/' -s 'git@git.zaphyra.eu:' "$1" # set correct permissions chown git:git -R /var/lib/stagit/$reponame; chmod 755 -R /var/lib/stagit/$reponame; echo "done" } build_stagit_index() { printf "Generating stagit index... " # set assets if not already there ln -sf "${pkgs.zpha.stagit}/share/doc/stagit/highlight.min.js" "/var/lib/stagit/highlight.min.js" 2> /dev/null ln -sf "${pkgs.zpha.stagit}/share/doc/stagit/style.css" "/var/lib/stagit/style.css" 2> /dev/null # generate index arguments args="-n \"${title}\" -e '${mail}'" for category in ${lib.escapeShellArgs categories}; do args="$args -c '$category'" for repo in "$HOME/repositories/"*.git/; do repo="''${repo%/}" is_public_and_listed "$repo" || continue [ "$(${pkgs.gawk}/bin/awk -F '=' '/category/ {print $2}' $repo/config | ${pkgs.gnused}/bin/sed -e 's/^[[:space:]]*//')" = "$category" ] && args="$args $repo" done done # build index echo "$args" | xargs ${pkgs.zpha.stagit}/bin/stagit-index > /var/lib/stagit/index.html # set correct permissions chown git:git /var/lib/stagit/index.html; chmod 755 /var/lib/stagit/index.html; echo "done" } update_stagit_repo() { repo="$(pwd)" reponame="$(basename "$repo" ".git")" cd "$repo" || return 1 is_public_and_listed "$repo" || return 0 # if forced update, remove directory and cache file is_forced_update && printf "[%s] Forced update, trigger complete regeneration of stagit-pages... \n" "$reponame" && rm -rf "/var/lib/stagit/$reponame" "/var/lib/gitolite/stagit-cache/$reponame" build_stagit_repo "$repo" build_stagit_index } ''; rebuildWebdir = '' source ${stagitFunctions} # clear webdir rm -rf /var/lib/stagit/* # clear cache rm -rf ${config.common.services.gitolite.dataDir}/stagit-cache/* # generate pages per repo for repo in "$HOME/repositories/"*.git/; do repo="''${repo%/}" is_public_and_listed "$repo" || continue build_stagit_repo "$repo" done # generate index page build_stagit_index ''; in { dns.zones = { "zaphyra.eu".subdomains."git".CNAME = lib.singleton "${config.networking.fqdn}."; "katja.wtf".subdomains."git".CNAME = lib.singleton "${config.networking.fqdn}."; "ctu.cx".subdomains."git".CNAME = lib.singleton "${config.networking.fqdn}."; }; sops.secrets = { "restic/gitolite/repositoryPassword" = { }; "restic/gitolite/sshPrivateKey" = { }; }; common = { configure.persist.system.dirs = [ { directory = "/var/lib/stagit"; mode = "0755"; inherit (config.common.services.gitolite) user group; } ]; services.resticBackup.gitolite = { inherit (config.common.services.gitolite) user; enable = true; targets = [ "isodon.fc9f.de" ]; sshKeyFile = config.sops.secrets."restic/gitolite/sshPrivateKey".path; passwordFile = config.sops.secrets."restic/gitolite/repositoryPassword".path; paths = [ config.common.services.gitolite.dataDir ]; }; services.gitolite = { enable = true; user = "git"; group = "git"; inherit adminPubkey; extraGitoliteRc = '' $RC{GIT_CONFIG_KEYS} = ".*"; $RC{UMASK} = 0027; push(@{$RC{ENABLE}}, 'cgit'); push(@{$RC{ENABLE}}, 'symbolic-ref'); push(@{$RC{ENABLE}}, 'rebuild-webdir'); push(@{$RC{ENABLE}}, 'rebuild-webdir'); $RC{NON_CORE} = "rebuild-webdir-trigger POST_COMPILE rebuild-stagit"; ''; triggers.rebuild-webdir = rebuildWebdir; commands.rebuild-webdir = rebuildWebdir; commonHooks.post-receive = '' # update stagit pages source ${stagitFunctions} update_stagit_repo "$1" ''; }; }; services = { fcgiwrap = { instances.git = { process.user = "git"; process.group = "git"; socket.user = "nginx"; socket.group = "nginx"; }; }; nginx = { enable = true; virtualHosts = { "git.ctu.cx" = { serverAliases = [ "git.katja.wtf" ]; useACMEHost = config.networking.fqdn; forceSSL = true; kTLS = true; locations."/".return = "307 https://git.zaphyra.eu$request_uri"; }; "git.zaphyra.eu" = { useACMEHost = config.networking.fqdn; forceSSL = true; kTLS = true; root = "/var/lib/stagit"; locations = { "@redir".return = "307 ../log.html"; "~ '^/([a-zA-Z0-9_.]+)/commit/.*$'".extraConfig = "error_page 404 = @redir;"; "~* \.html$".extraConfig = '' add_header Last-Modified $date_gmt; add_header Cache-Control 'private no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; if_modified_since off; expires off; etag off; ''; "~ '^/[a-zA-Z0-9._-]+/raw'".extraConfig = '' types { application/json json; application/wasm wasm; font/woff woff; font/woff2 woff2; application/pdf pdf; image/gif gif; image/jpeg jpeg jpg; image/png png; image/svg+xml svg svgz; image/webp webp; image/x-icon ico; } default_type text/plain; try_files $uri =404; ''; "~ '^/[a-zA-Z0-9._-]+/(git-(receive|upload)-pack|HEAD|info/refs|objects/(info/(http-)?alternates|packs)|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))$'".extraConfig = '' if ($query_string = service=git-receive-pack) { return 403; } include "${pkgs.nginx}/conf/fastcgi_params"; fastcgi_param SCRIPT_FILENAME "${pkgs.git}/libexec/git-core/git-http-backend"; fastcgi_param GIT_PROJECT_ROOT /var/lib/gitolite/repositories; fastcgi_param PATH_INFO $uri; fastcgi_pass unix:${config.services.fcgiwrap.instances.git.socket.address}; ''; }; }; }; }; }; } ); }