all repos

mugit @ 81b50f2

馃惍 git server that your cow will love
2 files changed, 122 insertions(+), 72 deletions(-)
nix: little bit more of type safety
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-02-17 23:51:55 +0200
Authored at: 2026-02-17 23:51:26 +0200
Change ID: tkpqotyyyspmzmroxuoyumqtxmrsslov
Parent: 5a3f570
M flake.nix
路路路
        49
        49
                 let

      
        50
        50
                   cfg = config.services.mugit;

      
        51
        51
                   format = pkgs.formats.yaml { };

      
        52
        
        -          configFile =

      
        53
        
        -            if cfg.configFile != null then cfg.configFile else format.generate "config.yaml" cfg.config;

      
        54
        
        -

      
        55
        
        -          mugitWrapper = pkgs.symlinkJoin {

      
        56
        
        -            name = "mugit";

      
        57
        
        -            paths = [ cfg.package ];

      
        58
        
        -            buildInputs = [ pkgs.makeWrapper ];

      
        59
        
        -            postBuild = ''

      
        60
        
        -              wrapProgram $out/bin/mugit \

      
        61
        
        -                --add-flags "--config ${configFile}"

      
        62
        
        -            '';

      
        63
        
        -          };

      
        64
        
        -

      
        65
        
        -          mugitWithCompletions = pkgs.stdenv.mkDerivation {

      
        66
        
        -            pname = "mugit";

      
        67
        
        -            version = cfg.package.version;

      
        68
        
        -            src = mugitWrapper;

      
        69
        
        -            nativeBuildInputs = [ pkgs.installShellFiles ];

      
        70
        
        -            installPhase = ''

      
        71
        
        -              mkdir -p $out/bin

      
        72
        
        -              cp -r $src/bin/* $out/bin/

      
        73
        
        -

      
        74
        
        -              installShellCompletion --cmd mugit \

      
        75
        
        -                --bash <($out/bin/mugit completion bash) \

      
        76
        
        -                --zsh <($out/bin/mugit completion zsh) \

      
        77
        
        -                --fish <($out/bin/mugit completion fish)

      
        78
        
        -            '';

      
        79
        
        -          };

      
        
        52
        +          configFile = format.generate "config.yaml" cfg.config;

      
        80
        53
                 in

      
        81
        54
                 {

      
        82
        55
                   options.services.mugit = {

      路路路
        95
        68
                       description = "Whether to open the firewall for mugit. Can only be used with `config`, not `configFile`.";

      
        96
        69
                     };

      
        97
        70
         

      
        98
        
        -            exposeCli = mkOption {

      
        99
        
        -              type = types.bool;

      
        100
        
        -              default = true;

      
        101
        
        -              description = "Whether to expose the mugit CLI to all users with the service configuration.";

      
        102
        
        -            };

      
        103
        
        -

      
        104
        
        -            dataDir = mkOption {

      
        105
        
        -              type = types.path;

      
        106
        
        -              default = "/var/lib/mugit";

      
        107
        
        -              description = "Directory where mugit stores its data.";

      
        108
        
        -            };

      
        109
        
        -

      
        110
        71
                     configFile = mkOption {

      
        111
        72
                       type = types.nullOr types.path;

      
        112
        73
                       default = null;

      
        113
        74
                       description = "Path to an existing mugit configuration file. Mutually exclusive with `config`.";

      
        114
        75
                     };

      
        115
        76
         

      
        116
        
        -            config = mkOption {

      
        117
        
        -              type = format.type;

      
        118
        
        -              default = { };

      
        119
        
        -              description = ''

      
        120
        
        -                Configuration for mugit. See documentation for available options.

      
        121
        
        -                https://github.com/olexsmir/mugit/blob/main/README.md

      
        122
        
        -              '';

      
        123
        
        -              example = literalExpression ''

      
        124
        
        -                {

      
        125
        
        -                  server.port = 8080;

      
        126
        
        -                  repo.dir = "/var/lib/mugit";

      
        127
        
        -                }

      
        128
        
        -              '';

      
        129
        
        -            };

      
        130
        
        -

      
        131
        77
                     user = mkOption {

      
        132
        78
                       type = types.str;

      
        133
        79
                       default = "mugit";

      路路路
        140
        86
                       description = "Group under which mugit runs.";

      
        141
        87
                     };

      
        142
        88
         

      
        
        89
        +            config = mkOption {

      
        
        90
        +              default = {};

      
        
        91
        +              description = ''

      
        
        92
        +                The primary mugit configuration.

      
        
        93
        +                See [docs](https://github.com/olexsmir/mugit) for possible values.

      
        
        94
        +              '';

      
        
        95
        +              example = literalExpression ''

      
        
        96
        +                {

      
        
        97
        +                  meta.host = "git.example.org";

      
        
        98
        +                  repo.dir = "/var/lib/mugit";

      
        
        99
        +                  ssh = {

      
        
        100
        +                    enable = true;

      
        
        101
        +                    host_key = "/var/lib/mugit/key";

      
        
        102
        +                  };

      
        
        103
        +                }

      
        
        104
        +              '';

      
        
        105
        +              type = types.submodule {

      
        
        106
        +                options.meta = {

      
        
        107
        +                  title = mkOption {

      
        
        108
        +                    type = types.str;

      
        
        109
        +                    default = "mugit";

      
        
        110
        +                    description = "Website title";

      
        
        111
        +                  };

      
        
        112
        +                  description = mkOption {

      
        
        113
        +                    type = types.str;

      
        
        114
        +                    default = "";

      
        
        115
        +                    description = "Website description";

      
        
        116
        +                  };

      
        
        117
        +                  host = mkOption {

      
        
        118
        +                    type = types.str;

      
        
        119
        +                    default = "";

      
        
        120
        +                    description = "Website CNAME (required)";

      
        
        121
        +                  };

      
        
        122
        +                };

      
        
        123
        +                options.server = {

      
        
        124
        +                  host = mkOption {

      
        
        125
        +                    type = types.str;

      
        
        126
        +                    default = "";

      
        
        127
        +                    description = "Host address";

      
        
        128
        +                  };

      
        
        129
        +                  port = mkOption {

      
        
        130
        +                    type = types.port;

      
        
        131
        +                    default = 8080;

      
        
        132
        +                    description = "Website port";

      
        
        133
        +                  };

      
        
        134
        +                };

      
        
        135
        +                options.repo = {

      
        
        136
        +                  dir = mkOption {

      
        
        137
        +                    type = types.str;

      
        
        138
        +                    default = "";

      
        
        139
        +                    description = "Directory which mugit will scan for repositories (required)";

      
        
        140
        +                  };

      
        
        141
        +                  masters = mkOption {

      
        
        142
        +                    type = types.listOf types.str;

      
        
        143
        +                    default = ["master" "main"];

      
        
        144
        +                    description = "Master branch to look for";

      
        
        145
        +                  };

      
        
        146
        +                  readmes = mkOption {

      
        
        147
        +                    type = types.listOf types.str;

      
        
        148
        +                    default = ["README.md" "readme.md" "README.html" "readme.html" "README.txt" "readme.txt" "readme"];

      
        
        149
        +                    description = "Readme files to look for";

      
        
        150
        +                  };

      
        
        151
        +                };

      
        
        152
        +                options.ssh = {

      
        
        153
        +                  enable = mkOption {

      
        
        154
        +                    type = types.bool;

      
        
        155
        +                    default = false;

      
        
        156
        +                    description = "Wharever to run ssh server";

      
        
        157
        +                  };

      
        
        158
        +                  port = mkOption {

      
        
        159
        +                    type = types.port;

      
        
        160
        +                    default = 2222;

      
        
        161
        +                    description = "Website port";

      
        
        162
        +                  };

      
        
        163
        +                  host_key = mkOption {

      
        
        164
        +                    type = types.str;

      
        
        165
        +                    default = "";

      
        
        166
        +                    description = "Path to ssh private key (required if ssh enabled)";

      
        
        167
        +                  };

      
        
        168
        +                  keys = mkOption {

      
        
        169
        +                    type = types.listOf types.str;

      
        
        170
        +                    default = [];

      
        
        171
        +                    description = "List of public ssh keys which are allows to do git pushes, and access private repositories";

      
        
        172
        +                  };

      
        
        173
        +                };

      
        
        174
        +                options.mirror = {

      
        
        175
        +                  enable = mkOption {

      
        
        176
        +                    type = types.bool;

      
        
        177
        +                    default = false;

      
        
        178
        +                    description = "Wharever to run mirroring worker";

      
        
        179
        +                  };

      
        
        180
        +                  interval = mkOption {

      
        
        181
        +                    type = types.str;

      
        
        182
        +                    default = "8h";

      
        
        183
        +                    description = "Interval in which mirroring will happen";

      
        
        184
        +                  };

      
        
        185
        +                  github_token = mkOption {

      
        
        186
        +                    type = types.str;

      
        
        187
        +                    default = "";

      
        
        188
        +                    description = "Github token for pulling from github repos";

      
        
        189
        +                  };

      
        
        190
        +                };

      
        
        191
        +                options.cache = {

      
        
        192
        +                  home_page = mkOption {

      
        
        193
        +                    type = types.str;

      
        
        194
        +                    default = "5m";

      
        
        195
        +                    description = "For how long index page is cached";

      
        
        196
        +                  };

      
        
        197
        +                  readme = mkOption {

      
        
        198
        +                    type = types.str;

      
        
        199
        +                    default = "1m";

      
        
        200
        +                    description = "For how long repos readme is cached";

      
        
        201
        +                  };

      
        
        202
        +                };

      
        
        203
        +              };

      
        
        204
        +            };

      
        143
        205
                   };

      
        144
        206
         

      
        145
        
        -          config = mkIf cfg.enable {

      
        146
        
        -            assertions = [

      
        147
        
        -              {

      
        148
        
        -                assertion = !(cfg.config != { } && cfg.configFile != null);

      
        149
        
        -                message = "services.mugit: `config` and `configFile` are mutually exclusive. Only one can be set.";

      
        150
        
        -              }

      
        151
        
        -              {

      
        152
        
        -                assertion = !(cfg.openFirewall && cfg.configFile != null);

      
        153
        
        -                message = "services.mugit: `openFirewall` cannot be used with `configFile`. Set firewall rules manually or use `config` instead.";

      
        154
        
        -              }

      
        155
        
        -            ];

      
        156
        207
         

      
        157
        
        -            environment.systemPackages = mkIf cfg.exposeCli [ mugitWithCompletions ];

      
        158
        
        -

      
        
        208
        +          config = mkIf cfg.enable {

      
        159
        209
                     networking.firewall = mkIf cfg.openFirewall {

      
        160
        210
                       allowedTCPPorts =

      
        161
        211
                         let

      路路路
        169
        219
                     users.users.${cfg.user} = {

      
        170
        220
                       isSystemUser = true;

      
        171
        221
                       group = cfg.group;

      
        172
        
        -              home = cfg.dataDir;

      
        
        222
        +              home = cfg.config.repo.dir;

      
        173
        223
                       createHome = true;

      
        174
        224
                       description = "mugit service user";

      
        175
        225
                     };

      路路路
        193
        243
                           Type = "simple";

      
        194
        244
                           User = cfg.user;

      
        195
        245
                           Group = cfg.group;

      
        196
        
        -                  WorkingDirectory = cfg.dataDir;

      
        
        246
        +                  WorkingDirectory = cfg.config.repo.dir;

      
        197
        247
                           StateDirectory = "mugit";

      
        198
        248
                           ExecStart = "${cfg.package}/bin/mugit serve --config ${configFile}";

      
        199
        249
                           Restart = "on-failure";

      路路路
        202
        252
                           PrivateTmp = true;

      
        203
        253
                           ProtectSystem = "strict";

      
        204
        254
                           ProtectHome = true;

      
        205
        
        -                  ReadWritePaths = [ cfg.dataDir ];

      
        
        255
        +                  ReadWritePaths = [ cfg.config.repo.dir ];

      
        206
        256
                           ProtectKernelTunables = true;

      
        207
        257
                           ProtectKernelModules = true;

      
        208
        258
                           ProtectControlGroups = true;

      
M internal/config/config.go
路路路
        127
        127
         

      
        128
        128
         	// meta

      
        129
        129
         	if c.Meta.Title == "" {

      
        130
        
        -		c.Meta.Title = "my cgit"

      
        
        130
        +		c.Meta.Title = "my mugit"

      
        131
        131
         	}

      
        132
        132
         

      
        133
        133
         	// repos