{ config, lib, libNginx, libPlausible, pkgs, this, ... }: let cfg = config.nixfiles.modules.git; in { options.nixfiles.modules.git = { client.enable = lib.mkEnableOption "Git client"; server = { enable = lib.mkEnableOption "Git server"; domain = lib.mkOption { description = "Domain name sans protocol scheme."; type = with lib.types; nullOr str; default = "git.${config.networking.domain}"; }; package = lib.mkOption { description = "Package."; type = lib.types.package; default = pkgs.cgit; }; }; }; config = lib.mkMerge [ (lib.mkIf cfg.client.enable { secrets = { # TODO Use this. # gh-hosts = { # file = "${inputs.self}/secrets/gh-hosts"; # path = "${config.dirs.config}/gh/hosts.yml"; # owner = my.username; # }; }; nixfiles.modules.common.shell.aliases.gl = "glab"; hm = { home.packages = with pkgs; [ git-extras glab ]; programs = { git = { enable = true; package = if this.isHeadful then pkgs.gitFull else pkgs.gitMinimal; userName = lib.my.username; userEmail = lib.my.email; extraConfig = { color.ui = true; core = { fsmonitor = true; untrackedCache = true; whitespace = "trailing-space"; }; log.showSignature = true; init.defaultBranch = "master"; status.submoduleSummary = true; commit.verbose = true; push = { autoSetupRemote = true; default = "simple"; followTags = true; }; fetch = { prune = true; pruneTags = true; all = true; }; pull.rebase = true; merge.conflictstyle = "zdiff3"; rebase = { autoSquash = true; autoStash = true; updateRefs = true; }; rerere = { enabled = true; autoupdate = true; }; branch.sort = "-committerdate"; tag.sort = "version:refname"; diff = { algorithm = "histogram"; colorMoved = "plain"; mnemonicPrefix = true; renames = true; submodule = "log"; }; submodule.recurse = true; sendemail = rec { smtpServer = lib.my.domain.shire; smtpUser = "${lib.my.username}@${smtpServer}"; smtpEncryption = "ssl"; smtpServerPort = 465; annotate = true; confirm = "always"; }; column.ui = "auto"; } // lib.mapAttrs' (n: v: lib.nameValuePair ''url "git@${v}:"'' { insteadOf = "${n}:"; }) { "codeberg" = "codeberg.org"; "github" = "github.com"; "gitlab" = "gitlab.com"; } // lib.mapAttrs' (n: v: lib.nameValuePair ''url "https://${v}/"'' { insteadOf = "${n}:"; }) { "alpine" = "gitlab.alpinelinux.org"; "bitbucket" = "bitbucket.com"; "clan" = "git.clan.lol"; "debian" = "salsa.debian.org"; "freedesktop" = "gitlab.freedesktop.org"; "gnome" = "gitlab.gnome.org"; "haskell" = "gitlab.haskell.org"; "homotopic" = "gitlab.homotopic.tech"; "horizon" = "gitlab.horizon-haskell.net"; "kde" = "invent.kde.org"; "nixca" = "gitlab.nixca.dev"; "notabug" = "notabug.org"; "opencode" = "opencode.net"; "sourcehut" = "git.sr.ht"; "syndicate" = "git.syndicate-lang.org"; "torproject" = "gitlab.torproject.org"; "videolan" = "code.videolan.org"; }; aliases = let git = lib.getExe config.hm.programs.git.package; curl = lib.getExe pkgs.curl; in { amend = "commit --amend"; cat = "cat-file -p"; fast = "clone --depth=1 --single-branch"; fixup = "commit --fixup"; fuck = "!${git} reset --hard && ${git} clean --force -dx"; get = "pull --all --recurse-submodules --autostash"; gud = ''commit -m "git gud"''; refresh = "clean --force -dx"; tree = "log --graph --date=relative --pretty=tformat:'%Cred%h%Creset -%C(auto)%d%Creset %s %Cgreen(%an %ad)%Creset'"; uncommit = "reset --soft HEAD~1"; untrack = "rm --cache --"; wtc = "!${curl} -sq whatthecommit.com/index.txt | ${git} commit -F -"; }; # All helper tools/editor generated files should go here. This must # be kept void of any project-specific files. ignores = [ "*~" ".DS_Store" ".cache/clangd/" ".ccls-cache/" ".gdb_history" ".netrwhist" ".projectile" "[._]*.s[a-v][a-z]" "[._]*.sw[a-p]" "[._]s[a-rt-v][a-z]" "[._]ss[a-gi-z]" "[._]sw[a-p]" "\#*\#" "compile_commands*.json" "cscope.*" "vgcore.*" ]; }; gh = { enable = true; settings.git_protocol = "ssh"; }; }; }; }) (lib.mkIf cfg.server.enable { ark.directories = [ config.services.gitolite.dataDir ]; nixfiles.modules.nginx = { enable = true; virtualHosts.${cfg.server.domain}.locations = { }; }; services = { cgit.${cfg.server.domain} = { enable = true; package = pkgs.cgit-pink; # We make gitolite repos readable by the common group. user = "git"; group = "git"; scanPath = "${config.services.gitolite.dataDir}/repositories"; settings = { root-title = "git.azahi.cc"; root-desc = "Personal projects and other stuff."; footer = "${pkgs.writeText "cgit-footer" ''

Consider giving Nix/NixOS a try! <3

''}"; about-filter = "${pkgs.writeScript "cgit-about-filter.sh" '' #!${pkgs.bash}/bin/sh filename=$1 case "$filename" in *.md) exec ${pkgs.pandoc}/bin/pandoc -f markdown -t html ;; *.org) exec ${pkgs.pandoc}/bin/pandoc -f org -t html ;; *) echo "
"
                  ${pkgs.coreutils}/bin/cat
                  echo "
" ;; esac ''}"; source-filter = "${cfg.server.package}/lib/cgit/filters/syntax-highlighting.py"; commit-filter = "${cfg.server.package}/lib/cgit/filters/commit-links.sh"; readme = [ ":README" ":README.md" ":readme.md" ":readme.org" ]; clone-url = "https://$HTTP_HOST/$CGIT_REPO_URL"; enable-blame = true; enable-commit-graph = true; enable-follow-links = true; enable-git-config = true; enable-gitweb-owner = true; enable-html-serving = true; enable-http-clone = true; enable-index-links = false; enable-index-owner = false; enable-log-filecount = true; enable-log-linecount = true; enable-subject-links = true; enable-tree-linenumbers = true; branch-sort = "age"; repository-sort = "age"; remove-suffix = true; logo = "/logo.gif"; logo-link = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"; }; }; gitolite = { enable = true; user = "git"; group = "git"; extraGitoliteRc = '' # This allows cgit to scan repositories while running under a # different user. $RC{UMASK} = 0027; # This allows hiding repositories via "cgit.ignore"[1]. # # [1]: https://www.omarpolo.com/post/cgit-gitolite.html $RC{GIT_CONFIG_KEYS} = '.*'; ''; }; nginx.virtualHosts.${cfg.server.domain}.locations = let extraHead = '' ${libNginx.config.appendHead [ '''' (libPlausible.htmlPlausibleScript { inherit (cfg.server) domain; }) ]} ''; in { "/" = { extraConfig = lib.mkBefore (libNginx.config.noAICrawlers + extraHead); fastcgiParams.HTTP_ACCEPT_ENCODING = ""; }; "~ /.+/(info/refs|git-upload-pack)" = { extraConfig = lib.mkBefore (libNginx.config.noAICrawlers + extraHead); fastcgiParams.HTTP_ACCEPT_ENCODING = ""; }; "= /logo.gif" = { alias = "${./logo.gif}"; extraConfig = lib.mkForce ""; }; "= /favicon.ico" = { alias = "${./favicon.ico}"; extraConfig = lib.mkForce ""; }; "= /cgit.css" = { alias = pkgs.writeText "cgit.css" '' ${builtins.readFile "${cfg.server.package}/cgit/cgit.css"} * { line-height: 1.25em; } div#cgit { font-family: ${ lib.concatMapStringsSep ", " (f: ''"${f}"'') config.fonts.fontconfig.defaultFonts.monospace }, monospace; -moz-tab-size: 2; tab-size: 2; max-width: 117ch; margin: auto; } div#cgit table#header td.sub { border-top: none; } div#cgit table#header td.sub.right { padding-right: 1em; } div#cgit table.tabs { border-bottom: none; } div#cgit div.content { border-bottom: none; } div#cgit table.list th a { color: inherit; } div#cgit table.list tr:nth-child(even) { background: inherit; } div#cgit table.list tr:hover { background: inherit; } div#cgit table.list tr.nohover-highlight:hover:nth-child(even) { background: inherit; } div#cgit table.blob td.linenumbers a:target { color: goldenrod; text-decoration: underline; outline: none; } div#cgit div#summary { max-width: 80ch; } ''; extraConfig = lib.mkForce ""; }; }; }; }) ]; }