diff options
| author | Seth Flynn <[email protected]> | 2025-02-13 21:07:48 -0500 |
|---|---|---|
| committer | Seth Flynn <[email protected]> | 2025-02-13 22:09:11 -0500 |
| commit | fd4925111408439dc8a8b875a6c3c4aff970ff12 (patch) | |
| tree | 16ac6134d3f5f0aa60d1d39cf9df55e3f75a665f /modules/nixos/custom/github-mirror | |
| parent | b816b91e4f1fcf090832f8bb81aa4484fc470cf6 (diff) | |
modules: group services & traits into "custom" modules
Diffstat (limited to 'modules/nixos/custom/github-mirror')
| -rw-r--r-- | modules/nixos/custom/github-mirror/default.nix | 103 | ||||
| -rwxr-xr-x | modules/nixos/custom/github-mirror/update-mirror.sh | 78 |
2 files changed, 181 insertions, 0 deletions
diff --git a/modules/nixos/custom/github-mirror/default.nix b/modules/nixos/custom/github-mirror/default.nix new file mode 100644 index 0000000..76d8853 --- /dev/null +++ b/modules/nixos/custom/github-mirror/default.nix @@ -0,0 +1,103 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.borealis.github-mirror; + cgitInstance = config.services.cgit.${cfg.hostname}; + + update-mirror = + pkgs.runCommand "update-mirror" + { + nativeBuildInputs = [ pkgs.patsh ]; + + buildInputs = [ + config.programs.git.package + pkgs.curl + pkgs.jq + ]; + } + '' + patsh -s ${builtins.storeDir} ${./update-mirror.sh} $out + chmod 755 $out + patchShebangs $out + ''; +in + +{ + options.borealis.github-mirror = { + enable = lib.mkEnableOption "the github-mirror service"; + + hostname = lib.mkOption { + type = lib.types.str; + description = "Hostname of the cgit service to create"; + example = lib.literalExpression "git.example.com"; + }; + + mirroredUsers = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "List of GitHub users to mirror repositories for"; + example = lib.literalExpression ''[ "edolstra" ]''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.mirroredUsers != [ ]; + message = "`borealis.github-mirror.mirroredUsers` must have at least one user"; + } + ]; + + services.cgit.${cfg.hostname} = { + enable = true; + + scanPath = "/var/lib/cgit/${cfg.hostname}"; + settings = { + robots = "none"; # noindex, nofollow + }; + + user = "cgit"; + group = "cgit"; + }; + + systemd = { + services.github-mirror = { + description = "Mirror a GitHub repository"; + + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + + script = toString ( + [ + "exec" + (toString update-mirror) + "--directory" + cgitInstance.scanPath + ] + ++ cfg.mirroredUsers + ); + + serviceConfig = { + Type = "oneshot"; + User = cgitInstance.user; + Group = cgitInstance.group; + }; + }; + + timers.github-mirror = { + description = "Hourly timer for %N"; + timerConfig.OnCalendar = "hourly"; + }; + + tmpfiles.settings."10-github-mirror" = { + ${cgitInstance.scanPath}.d = { + inherit (cgitInstance) user group; + }; + }; + }; + }; +} diff --git a/modules/nixos/custom/github-mirror/update-mirror.sh b/modules/nixos/custom/github-mirror/update-mirror.sh new file mode 100755 index 0000000..88ff6eb --- /dev/null +++ b/modules/nixos/custom/github-mirror/update-mirror.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -euo pipefail + +help() { + echo "Mirror a GitHub user's repositories + +Usage: $(basename "$0") [options] <user>... + +Options: + -h --help Show this screen + -d --directory DIRECTORY Where to clone repositories (defaults to ./git)" +} + +create_if_not_exists() { + if [ ! -d "$1" ]; then + mkdir -p "$1" + fi +} + +repo_endpoint() { + echo "https://api.github.com/users/$1/repos" +} + +users=() +output_directory="git" + +while [ "$#" -gt 0 ]; do + case $1 in + -h | --help) + help + exit 0 + ;; + -d | --directory) + output_directory="$2" + shift + shift + ;; + -*) + echo "error: unknown option $1" + help + exit 1 + ;; + *) + users+=("$1") + shift + ;; + esac +done + +if [ "${#users[@]}" -lt 1 ]; then + echo "error: at least one user must be specified" + help + exit 1 +fi + +create_if_not_exists "$output_directory" +cd "$output_directory" + +for user in "${users[@]}"; do + create_if_not_exists "$user" + + url="$(repo_endpoint "$user")" + curl --fail --location --show-error --silent "$url" | jq --raw-output '.[].name' | while read -r repo; do + repo_path="$user"/"$repo" + + if [ -d "$repo_path" ]; then + pushd "$repo_path" &>/dev/null + echo "Pulling $repo_path..." + if ! git remote update --prune &>/dev/null; then + echo "Unable to pull $repo_path! Continuing..." + fi + popd &>/dev/null + else + echo "Cloning $repo_path..." + git clone --bare --mirror https://github.com/"$repo_path".git "$repo_path" &>/dev/null + fi + done +done |
