|
| 1 | +{ hoogle, cores ? 4 }: |
| 2 | +{ config, pkgs, ... }: |
| 3 | + |
| 4 | +# The Plan: |
| 5 | +# Hoogle serves on a uniquely-named UNIX domain socket which we |
| 6 | +# configure nginx to forward to via the nginxConf configuration |
| 7 | +# fragment. The Hoogle database is periodically updated by |
| 8 | +# rotate-hoogle.service which generates a new Hoogle database, |
| 9 | +# starts a new hoogle server, updates the nginx configuration |
| 10 | +# and shuts down the old server. |
| 11 | + |
| 12 | +let |
| 13 | + hoogleRun = "/run/hoogle"; |
| 14 | + nginxConf = "${hoogleRun}/nginx.conf"; |
| 15 | + socket = "/run/hoogle/hoogle.sock"; |
| 16 | +in |
| 17 | +{ |
| 18 | + users.users.hoogle = { |
| 19 | + isSystemUser = true; |
| 20 | + description = "hoogle server"; |
| 21 | + group = "hoogle"; |
| 22 | + }; |
| 23 | + |
| 24 | + users.groups.hoogle = { |
| 25 | + members = [ "nginx" ]; |
| 26 | + }; |
| 27 | + |
| 28 | + systemd.timers."generate-hoogle" = { |
| 29 | + description = "Rotate Hoogle instance"; |
| 30 | + timerConfig = { |
| 31 | + Unit = "generate-hoogle.service"; |
| 32 | + OnCalendar = "hourly"; |
| 33 | + Persistent = true; |
| 34 | + }; |
| 35 | + wantedBy = [ "timers.target" ]; |
| 36 | + }; |
| 37 | + |
| 38 | + systemd.services."generate-hoogle" = { |
| 39 | + script = '' |
| 40 | + hoogle generate --database=$DB_DIR/haskell-new.hoo --insecure --download +RTS -N${toString cores} -RTS |
| 41 | + mv $DB_DIR/haskell-new.hoo $DB_DIR/haskell.hoo |
| 42 | + ''; |
| 43 | + path = [ hoogle ]; |
| 44 | + after = [ "network.target" ]; |
| 45 | + serviceConfig = { |
| 46 | + User = "hoogle"; |
| 47 | + Group = "hoogle"; |
| 48 | + Type = "oneshot"; |
| 49 | + TimeoutStartSec = 600; |
| 50 | + ExecStartPost = "+systemctl restart hoogle.service"; |
| 51 | + BindReadOnlyPaths = [ |
| 52 | + # mount the nix store read-only |
| 53 | + "/nix/store" |
| 54 | + # getAppUserDataDirectory needs getUserEntryForID |
| 55 | + "/etc/passwd" |
| 56 | + ]; |
| 57 | + PrivateNetwork = false; |
| 58 | + RuntimeDirectory = "generate-hoogle"; |
| 59 | + StateDirectory = [ "hoogle" ]; |
| 60 | + }; |
| 61 | + environment = { |
| 62 | + DB_DIR = "%S/hoogle"; |
| 63 | + }; |
| 64 | + }; |
| 65 | + |
| 66 | + systemd.services."hoogle" = { |
| 67 | + script = '' |
| 68 | + hoogle serve \ |
| 69 | + --database=$DB_DIR/haskell.hoo \ |
| 70 | + --scope=set:stackage \ |
| 71 | + --socket=${socket} \ |
| 72 | + --links \ |
| 73 | + +RTS -T -N${toString cores} -RTS; |
| 74 | + ''; |
| 75 | + path = [ hoogle ]; |
| 76 | + serviceConfig = { |
| 77 | + User = "nginx"; |
| 78 | + Group = "hoogle"; |
| 79 | + BindReadOnlyPaths = [ |
| 80 | + # mount the nix store read-only |
| 81 | + "/nix/store" |
| 82 | + # getAppUserDataDirectory needs getUserEntryForID |
| 83 | + "/etc/passwd" |
| 84 | + #"/etc/ssl" "/etc/ssl/certs" |
| 85 | + ]; |
| 86 | + PrivateTmp = false; |
| 87 | + ProtectSystem = false; |
| 88 | + ProtectHome = false; |
| 89 | + NoNewPrivileges = false; |
| 90 | + Restart = "on-failure"; |
| 91 | + RestartSec = "5s"; |
| 92 | + RuntimeDirectory = "hoogle"; |
| 93 | + }; |
| 94 | + environment = { |
| 95 | + DB_DIR = "%S/hoogle"; |
| 96 | + SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; |
| 97 | + NIX_SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; |
| 98 | + }; |
| 99 | + wantedBy = [ "multi-user.target" ]; |
| 100 | + }; |
| 101 | + |
| 102 | + systemd.tmpfiles.rules = [ |
| 103 | + "f ${nginxConf} 0755 nginx nginx -" |
| 104 | + ]; |
| 105 | + |
| 106 | + services.nginx = { |
| 107 | + upstreams.hoogle.extraConfig = '' |
| 108 | + server unix:${socket}; |
| 109 | + ''; |
| 110 | + }; |
| 111 | +} |
| 112 | + |
0 commit comments