tangled
alpha
login
or
join now
pyrox.dev
/
nixpkgs
0
fork
atom
lol
0
fork
atom
overview
issues
pulls
pipelines
nixos/cgit: init
schnusch
3 years ago
218c7795
996c7879
+262
4 changed files
expand all
collapse all
unified
split
nixos
modules
module-list.nix
services
networking
cgit.nix
tests
all-tests.nix
cgit.nix
+1
nixos/modules/module-list.nix
reviewed
···
793
793
./services/networking/bitlbee.nix
794
794
./services/networking/blockbook-frontend.nix
795
795
./services/networking/blocky.nix
796
796
+
./services/networking/cgit.nix
796
797
./services/networking/charybdis.nix
797
798
./services/networking/chisel-server.nix
798
799
./services/networking/cjdns.nix
+201
nixos/modules/services/networking/cgit.nix
reviewed
···
1
1
+
{ config, lib, pkgs, ...}:
2
2
+
3
3
+
with lib;
4
4
+
5
5
+
let
6
6
+
cfgs = config.services.cgit;
7
7
+
8
8
+
settingType = with types; oneOf [ bool int str ];
9
9
+
10
10
+
genAttrs' = names: f: listToAttrs (map f names);
11
11
+
12
12
+
regexEscape =
13
13
+
let
14
14
+
# taken from https://github.com/python/cpython/blob/05cb728d68a278d11466f9a6c8258d914135c96c/Lib/re.py#L251-L266
15
15
+
special = [
16
16
+
"(" ")" "[" "]" "{" "}" "?" "*" "+" "-" "|" "^" "$" "\\" "." "&" "~"
17
17
+
"#" " " "\t" "\n" "\r" "\v" "\f"
18
18
+
];
19
19
+
in
20
20
+
replaceStrings special (map (c: "\\${c}") special);
21
21
+
22
22
+
stripLocation = cfg: removeSuffix "/" cfg.nginx.location;
23
23
+
24
24
+
regexLocation = cfg: regexEscape (stripLocation cfg);
25
25
+
26
26
+
mkFastcgiPass = cfg: ''
27
27
+
${if cfg.nginx.location == "/" then ''
28
28
+
fastcgi_param PATH_INFO $uri;
29
29
+
'' else ''
30
30
+
fastcgi_split_path_info ^(${regexLocation cfg})(/.+)$;
31
31
+
fastcgi_param PATH_INFO $fastcgi_path_info;
32
32
+
''
33
33
+
}fastcgi_pass unix:${config.services.fcgiwrap.socketAddress};
34
34
+
'';
35
35
+
36
36
+
cgitrcLine = name: value: "${name}=${
37
37
+
if value == true then
38
38
+
"1"
39
39
+
else if value == false then
40
40
+
"0"
41
41
+
else
42
42
+
toString value
43
43
+
}";
44
44
+
45
45
+
mkCgitrc = cfg: pkgs.writeText "cgitrc" ''
46
46
+
# global settings
47
47
+
${concatStringsSep "\n" (
48
48
+
mapAttrsToList
49
49
+
cgitrcLine
50
50
+
({ virtual-root = cfg.nginx.location; } // cfg.settings)
51
51
+
)
52
52
+
}
53
53
+
${optionalString (cfg.scanPath != null) (cgitrcLine "scan-path" cfg.scanPath)}
54
54
+
55
55
+
# repository settings
56
56
+
${concatStrings (
57
57
+
mapAttrsToList
58
58
+
(url: settings: ''
59
59
+
${cgitrcLine "repo.url" url}
60
60
+
${concatStringsSep "\n" (
61
61
+
mapAttrsToList (name: cgitrcLine "repo.${name}") settings
62
62
+
)
63
63
+
}
64
64
+
'')
65
65
+
cfg.repos
66
66
+
)
67
67
+
}
68
68
+
69
69
+
# extra config
70
70
+
${cfg.extraConfig}
71
71
+
'';
72
72
+
73
73
+
mkCgitReposDir = cfg:
74
74
+
if cfg.scanPath != null then
75
75
+
cfg.scanPath
76
76
+
else
77
77
+
pkgs.runCommand "cgit-repos" {
78
78
+
preferLocalBuild = true;
79
79
+
allowSubstitutes = false;
80
80
+
} ''
81
81
+
mkdir -p "$out"
82
82
+
${
83
83
+
concatStrings (
84
84
+
mapAttrsToList
85
85
+
(name: value: ''
86
86
+
ln -s ${escapeShellArg value.path} "$out"/${escapeShellArg name}
87
87
+
'')
88
88
+
cfg.repos
89
89
+
)
90
90
+
}
91
91
+
'';
92
92
+
93
93
+
in
94
94
+
{
95
95
+
options = {
96
96
+
services.cgit = mkOption {
97
97
+
description = mdDoc "Configure cgit instances.";
98
98
+
default = {};
99
99
+
type = types.attrsOf (types.submodule ({ config, ... }: {
100
100
+
options = {
101
101
+
enable = mkEnableOption (mdDoc "cgit");
102
102
+
103
103
+
nginx.virtualHost = mkOption {
104
104
+
description = mdDoc "VirtualHost to serve cgit on, defaults to the attribute name.";
105
105
+
type = types.str;
106
106
+
default = config._module.args.name;
107
107
+
example = "git.example.com";
108
108
+
};
109
109
+
110
110
+
nginx.location = mkOption {
111
111
+
description = mdDoc "Location to serve cgit under.";
112
112
+
type = types.str;
113
113
+
default = "/";
114
114
+
example = "/git/";
115
115
+
};
116
116
+
117
117
+
repos = mkOption {
118
118
+
description = mdDoc "cgit repository settings, see cgitrc(5)";
119
119
+
type = with types; attrsOf (attrsOf settingType);
120
120
+
default = {};
121
121
+
example = {
122
122
+
blah = {
123
123
+
path = "/var/lib/git/example";
124
124
+
desc = "An example repository";
125
125
+
};
126
126
+
};
127
127
+
};
128
128
+
129
129
+
scanPath = mkOption {
130
130
+
description = mdDoc "A path which will be scanned for repositories.";
131
131
+
type = types.nullOr types.path;
132
132
+
default = null;
133
133
+
example = "/var/lib/git";
134
134
+
};
135
135
+
136
136
+
settings = mkOption {
137
137
+
description = mdDoc "cgit configuration, see cgitrc(5)";
138
138
+
type = types.attrsOf settingType;
139
139
+
default = {};
140
140
+
example = literalExpression ''
141
141
+
{
142
142
+
enable-follow-links = true;
143
143
+
source-filter = "''${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py";
144
144
+
}
145
145
+
'';
146
146
+
};
147
147
+
148
148
+
extraConfig = mkOption {
149
149
+
description = mdDoc "These lines go to the end of cgitrc verbatim.";
150
150
+
type = types.lines;
151
151
+
default = "";
152
152
+
};
153
153
+
};
154
154
+
}));
155
155
+
};
156
156
+
};
157
157
+
158
158
+
config = mkIf (any (cfg: cfg.enable) (attrValues cfgs)) {
159
159
+
assertions = mapAttrsToList (vhost: cfg: {
160
160
+
assertion = !cfg.enable || (cfg.scanPath == null) != (cfg.repos == {});
161
161
+
message = "Exactly one of services.cgit.${vhost}.scanPath or services.cgit.${vhost}.repos must be set.";
162
162
+
}) cfgs;
163
163
+
164
164
+
services.fcgiwrap.enable = true;
165
165
+
166
166
+
services.nginx.enable = true;
167
167
+
168
168
+
services.nginx.virtualHosts = mkMerge (mapAttrsToList (_: cfg: {
169
169
+
${cfg.nginx.virtualHost} = {
170
170
+
locations = (
171
171
+
genAttrs'
172
172
+
[ "cgit.css" "cgit.png" "favicon.ico" "robots.txt" ]
173
173
+
(name: nameValuePair "= ${stripLocation cfg}/${name}" {
174
174
+
extraConfig = ''
175
175
+
alias ${pkgs.cgit}/cgit/${name};
176
176
+
'';
177
177
+
})
178
178
+
) // {
179
179
+
"~ ${regexLocation cfg}/.+/(info/refs|git-upload-pack)" = {
180
180
+
fastcgiParams = rec {
181
181
+
SCRIPT_FILENAME = "${pkgs.git}/libexec/git-core/git-http-backend";
182
182
+
GIT_HTTP_EXPORT_ALL = "1";
183
183
+
GIT_PROJECT_ROOT = mkCgitReposDir cfg;
184
184
+
HOME = GIT_PROJECT_ROOT;
185
185
+
};
186
186
+
extraConfig = mkFastcgiPass cfg;
187
187
+
};
188
188
+
"${stripLocation cfg}/" = {
189
189
+
fastcgiParams = {
190
190
+
SCRIPT_FILENAME = "${pkgs.cgit}/cgit/cgit.cgi";
191
191
+
QUERY_STRING = "$args";
192
192
+
HTTP_HOST = "$server_name";
193
193
+
CGIT_CONFIG = mkCgitrc cfg;
194
194
+
};
195
195
+
extraConfig = mkFastcgiPass cfg;
196
196
+
};
197
197
+
};
198
198
+
};
199
199
+
}) cfgs);
200
200
+
};
201
201
+
}
+1
nixos/tests/all-tests.nix
reviewed
···
124
124
ceph-single-node-bluestore = handleTestOn ["x86_64-linux"] ./ceph-single-node-bluestore.nix {};
125
125
certmgr = handleTest ./certmgr.nix {};
126
126
cfssl = handleTestOn ["aarch64-linux" "x86_64-linux"] ./cfssl.nix {};
127
127
+
cgit = handleTest ./cgit.nix {};
127
128
charliecloud = handleTest ./charliecloud.nix {};
128
129
chromium = (handleTestOn ["aarch64-linux" "x86_64-linux"] ./chromium.nix {}).stable or {};
129
130
cinnamon = handleTest ./cinnamon.nix {};
+59
nixos/tests/cgit.nix
reviewed
···
1
1
+
import ./make-test-python.nix ({ pkgs, ...} : {
2
2
+
name = "cgit";
3
3
+
meta = with pkgs.lib.maintainers; {
4
4
+
maintainers = [ schnusch ];
5
5
+
};
6
6
+
7
7
+
nodes = {
8
8
+
server = { ... }: {
9
9
+
services.cgit."localhost" = {
10
10
+
enable = true;
11
11
+
nginx.location = "/(c)git/";
12
12
+
repos = {
13
13
+
some-repo = {
14
14
+
path = "/srv/git/some-repo";
15
15
+
desc = "some-repo description";
16
16
+
};
17
17
+
};
18
18
+
};
19
19
+
20
20
+
environment.systemPackages = [ pkgs.git ];
21
21
+
};
22
22
+
};
23
23
+
24
24
+
testScript = { nodes, ... }: ''
25
25
+
start_all()
26
26
+
27
27
+
server.wait_for_unit("nginx.service")
28
28
+
server.wait_for_unit("network.target")
29
29
+
server.wait_for_open_port(80)
30
30
+
31
31
+
server.succeed("curl -fsS http://localhost/%28c%29git/robots.txt")
32
32
+
33
33
+
server.succeed(
34
34
+
"curl -fsS http://localhost/%28c%29git/ | grep -F 'some-repo description'"
35
35
+
)
36
36
+
37
37
+
server.fail("curl -fsS http://localhost/robots.txt")
38
38
+
39
39
+
server.succeed("${pkgs.writeShellScript "setup-cgit-test-repo" ''
40
40
+
set -e
41
41
+
git init --bare -b master /srv/git/some-repo
42
42
+
git init -b master reference
43
43
+
cd reference
44
44
+
git remote add origin /srv/git/some-repo
45
45
+
date > date.txt
46
46
+
git add date.txt
47
47
+
git -c user.name=test -c user.email=test@localhost commit -m 'add date'
48
48
+
git push -u origin master
49
49
+
''}")
50
50
+
51
51
+
server.succeed(
52
52
+
"curl -fsS 'http://localhost/%28c%29git/some-repo/plain/date.txt?id=master' | diff -u reference/date.txt -"
53
53
+
)
54
54
+
55
55
+
server.succeed(
56
56
+
"git clone http://localhost/%28c%29git/some-repo && diff -u reference/date.txt some-repo/date.txt"
57
57
+
)
58
58
+
'';
59
59
+
})