diff options
| author | seth <[email protected]> | 2024-10-15 06:40:11 -0400 |
|---|---|---|
| committer | seth <[email protected]> | 2024-10-15 06:40:11 -0400 |
| commit | 91c3b594ba25ef82dfe0ad65567ad54d95ca46c3 (patch) | |
| tree | 93ce02237ce36b5de6fa4aa2c3706a268a934004 /modules/nixos/server | |
| parent | d166dc791de86695eb26613b926ccc6a55123448 (diff) | |
nixos/github-mirror: init module
Diffstat (limited to 'modules/nixos/server')
| -rw-r--r-- | modules/nixos/server/default.nix | 1 | ||||
| -rw-r--r-- | modules/nixos/server/github-mirror/default.nix | 101 | ||||
| -rwxr-xr-x | modules/nixos/server/github-mirror/update-mirror.sh | 78 |
3 files changed, 180 insertions, 0 deletions
diff --git a/modules/nixos/server/default.nix b/modules/nixos/server/default.nix index 2ff257a..3cc60fb 100644 --- a/modules/nixos/server/default.nix +++ b/modules/nixos/server/default.nix @@ -14,6 +14,7 @@ in }; imports = [ + ./github-mirror ./host-user.nix ./mixins ]; diff --git a/modules/nixos/server/github-mirror/default.nix b/modules/nixos/server/github-mirror/default.nix new file mode 100644 index 0000000..9d0d870 --- /dev/null +++ b/modules/nixos/server/github-mirror/default.nix @@ -0,0 +1,101 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.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.services.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 = "`services.git-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/server/github-mirror/update-mirror.sh b/modules/nixos/server/github-mirror/update-mirror.sh new file mode 100755 index 0000000..c1e392d --- /dev/null +++ b/modules/nixos/server/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"/.git ]; 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 |
