ugit @main -
refs -
log -
-
https://git.jolheiser.com/ugit.git
The code powering this h*ckin' site
multiple nix module instances
Signature
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgBTEvCQk6VqUAdN2RuH6bj1dNkY
oOpbPWj+jw4ua1B1cAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5
AAAAQItLYcEkzIXqhxcUK6d6uqIV9lKib4/17JJH8NKdIGNvInsejNbuZqz5s9Wc9nfuuS
yDqfc9e/i/p4y8u9+uCwk=
-----END SSH SIGNATURE-----
2 changed files, 134 additions(+), 99 deletions(-)
diff --git a/cmd/ugitd/args.go b/cmd/ugitd/args.go
index 24109585663c4b7156f95becaddbb4609d543d39..5dd586ad4dc96aaabe420f74e02da5e4f4b09777 100644
--- a/cmd/ugitd/args.go
+++ b/cmd/ugitd/args.go
@@ -101,6 +101,7 @@ return nil
})
fs.BoolVar(&c.Log.JSON, "log.json", c.Log.JSON, "Print logs in JSON(L) format")
fs.StringVar(&c.RepoDir, "repo-dir", c.RepoDir, "Path to directory containing repositories")
+ fs.BoolVar(&c.ShowPrivate, "show-private", c.ShowPrivate, "Show private repos in web interface")
fs.BoolVar(&c.SSH.Enable, "ssh.enable", c.SSH.Enable, "Enable SSH server")
fs.StringVar(&c.SSH.AuthorizedKeys, "ssh.authorized-keys", c.SSH.AuthorizedKeys, "Path to authorized_keys")
fs.StringVar(&c.SSH.CloneURL, "ssh.clone-url", c.SSH.CloneURL, "SSH clone URL base")
diff --git a/nix/module.nix b/nix/module.nix
index d544007c55b669bc4de843a580ea62fe267e4dfd..aed867c7806f164d1524db64f02382d7678de6b0 100644
--- a/nix/module.nix
+++ b/nix/module.nix
@@ -8,18 +8,13 @@ let
cfg = config.services.ugit;
pkg = pkgs.callPackage ./pkg.nix { inherit pkgs; };
yamlFormat = pkgs.formats.yaml { };
- configFile = pkgs.writeText "ugit.yaml" (
- builtins.readFile (yamlFormat.generate "ugit-yaml" cfg.config)
- );
- authorizedKeysFile = pkgs.writeText "ugit_keys" (builtins.concatStringsSep "\n" cfg.authorizedKeys);
-in
-{
- options =
+ instanceOptions =
+ { name, config, ... }:
let
inherit (lib) mkEnableOption mkOption types;
in
{
- services.ugit = {
+ options = {
enable = mkEnableOption "Enable ugit";
package = mkOption {
@@ -28,10 +23,16 @@ description = "ugit package to use";
default = pkg;
};
+ homeDir = mkOption {
+ type = types.str;
+ description = "ugit home directory";
+ default = "/var/lib/${name}";
+ };
+
repoDir = mkOption {
type = types.str;
description = "where ugit stores repositories";
- default = "/var/lib/ugit/repos";
+ default = "/var/lib/${name}/repos";
};
authorizedKeys = mkOption {
@@ -43,13 +44,13 @@
authorizedKeysFile = mkOption {
type = types.str;
description = "path to authorized_keys file ugit uses for auth";
- default = "/var/lib/ugit/authorized_keys";
+ default = "/var/lib/${name}/authorized_keys";
};
hostKeyFile = mkOption {
type = types.str;
description = "path to host key file (will be created if it doesn't exist)";
- default = "/var/lib/ugit/ugit_ed25519";
+ default = "/var/lib/${name}/ugit_ed25519";
};
config = mkOption {
@@ -60,21 +61,16 @@ };
user = mkOption {
type = types.str;
- default = "ugit";
+ default = "ugit-${name}";
description = "User account under which ugit runs";
};
group = mkOption {
type = types.str;
- default = "ugit";
+ default = "ugit-${name}";
description = "Group account under which ugit runs";
};
- openFirewall = mkOption {
- type = types.bool;
- default = false;
- };
-
hooks = mkOption {
type = types.listOf (
types.submodule {
@@ -95,95 +91,133 @@ default = [ ];
};
};
};
- config = lib.mkIf cfg.enable {
- users.users."${cfg.user}" = {
- home = "/var/lib/ugit";
- createHome = true;
- group = "${cfg.group}";
- isSystemUser = true;
- isNormalUser = false;
- description = "user for ugit service";
- };
- users.groups."${cfg.group}" = { };
- networking.firewall = lib.mkIf cfg.openFirewall {
- allowedTCPPorts = [
- 8448
- 8449
- ];
+in
+{
+ options = {
+ services.ugit = lib.mkOption {
+ type = lib.types.attrsOf (lib.types.submodule instanceOptions);
+ default = { };
+ description = "Attribute set of ugit instances";
};
+ };
+ config = lib.mkIf (cfg != { }) {
+ users.users = lib.mapAttrs' (
+ name: instanceCfg:
+ lib.nameValuePair instanceCfg.user {
+ home = instanceCfg.homeDir;
+ createHome = true;
+ group = instanceCfg.group;
+ isSystemUser = true;
+ isNormalUser = false;
+ description = "user for ugit ${name} service";
+ }
+ ) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg);
- systemd.services = {
- ugit = {
- enable = true;
- script =
- let
- authorizedKeysPath =
- if (builtins.length cfg.authorizedKeys) > 0 then authorizedKeysFile else cfg.authorizedKeysFile;
- args = [
- "--config=${configFile}"
- "--repo-dir=${cfg.repoDir}"
- "--ssh.authorized-keys=${authorizedKeysPath}"
- "--ssh.host-key=${cfg.hostKeyFile}"
+ users.groups = lib.mapAttrs' (name: instanceCfg: lib.nameValuePair instanceCfg.group { }) (
+ lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg
+ );
+
+ systemd.services = lib.foldl' (
+ acc: name:
+ let
+ instanceCfg = cfg.${name};
+ in
+ lib.recursiveUpdate acc (
+ lib.optionalAttrs instanceCfg.enable {
+ "ugit-${name}" = {
+ enable = true;
+ description = "ugit instance ${name}";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "network.target" ];
+ path = [
+ instanceCfg.package
+ pkgs.git
+ pkgs.bash
];
- in
- "${cfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}";
- wantedBy = [ "multi-user.target" ];
- after = [ "network.target" ];
- path = [
- cfg.package
- pkgs.git
- pkgs.bash
- ];
- serviceConfig = {
- User = cfg.user;
- Group = cfg.group;
- Restart = "always";
- RestartSec = "15";
- WorkingDirectory = "/var/lib/ugit";
- };
- };
- ugit-hooks = {
- wantedBy = [ "multi-user.target" ];
- after = [ "ugit.service" ];
- requires = [ "ugit.service" ];
- serviceConfig = {
- Type = "oneshot";
- ExecStart =
- let
- script = pkgs.writeShellScript "ugit-hooks-link" (
- builtins.concatStringsSep "\n" (
- map (
+ serviceConfig = {
+ User = instanceCfg.user;
+ Group = instanceCfg.group;
+ Restart = "always";
+ RestartSec = "15";
+ WorkingDirectory = instanceCfg.homeDir;
+ ExecStart =
+ let
+ configFile = pkgs.writeText "ugit-${name}.yaml" (
+ builtins.readFile (yamlFormat.generate "ugit-${name}-yaml" instanceCfg.config)
+ );
+ authorizedKeysFile = pkgs.writeText "ugit_${name}_keys" (
+ builtins.concatStringsSep "\n" instanceCfg.authorizedKeys
+ );
+
+ authorizedKeysPath =
+ if (builtins.length instanceCfg.authorizedKeys) > 0 then
+ authorizedKeysFile
+ else
+ instanceCfg.authorizedKeysFile;
+ args = [
+ "--config=${configFile}"
+ "--repo-dir=${instanceCfg.repoDir}"
+ "--ssh.authorized-keys=${authorizedKeysPath}"
+ "--ssh.host-key=${instanceCfg.hostKeyFile}"
+ ];
+ in
+ "${instanceCfg.package}/bin/ugitd ${builtins.concatStringsSep " " args}";
+ };
+ };
+
+ "ugit-${name}-hooks" = {
+ description = "Setup hooks for ugit instance ${name}";
+ wantedBy = [ "multi-user.target" ];
+ after = [ "ugit-${name}.service" ];
+ requires = [ "ugit-${name}.service" ];
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExit = true;
+ User = instanceCfg.user;
+ Group = instanceCfg.group;
+ ExecStart =
+ let
+ hookDir = "${instanceCfg.repoDir}/hooks/pre-receive.d";
+ mkHookScript =
hook:
let
- script = pkgs.writeShellScript hook.name hook.content;
- path = "${cfg.repoDir}/hooks/pre-receive.d/${hook.name}";
+ script = pkgs.writeShellScript "ugit-${name}-${hook.name}" hook.content;
in
- "ln -s ${script} ${path}"
- ) cfg.hooks
- )
- );
- in
- "${script}";
- };
- };
- };
-
- systemd.tmpfiles.settings.ugit = builtins.listToAttrs (
- map (
- hook:
- let
- script = pkgs.writeShellScript hook.name hook.content;
- path = "${cfg.repoDir}/hooks/pre-receive.d/${hook.name}";
- in
- {
- name = path;
- value = {
- "L" = {
- argument = "${script}";
+ ''
+ mkdir -p ${hookDir}
+ ln -sf ${script} ${hookDir}/${hook.name}
+ '';
+ in
+ pkgs.writeShellScript "ugit-${name}-hooks-setup" ''
+ ${builtins.concatStringsSep "\n" (map mkHookScript instanceCfg.hooks)}
+ '';
};
};
}
- ) cfg.hooks
- );
+ )
+ ) { } (builtins.attrNames cfg);
+
+ systemd.tmpfiles.settings = lib.mapAttrs' (
+ name: instanceCfg:
+ lib.nameValuePair "ugit-${name}" (
+ builtins.listToAttrs (
+ map (
+ hook:
+ let
+ script = pkgs.writeShellScript hook.name hook.content;
+ path = "${instanceCfg.repoDir}/hooks/pre-receive.d/${hook.name}";
+ in
+ {
+ name = path;
+ value = {
+ "L" = {
+ argument = "${script}";
+ };
+ };
+ }
+ ) instanceCfg.hooks
+ )
+ )
+ ) (lib.filterAttrs (name: instanceCfg: instanceCfg.enable) cfg);
};
}