about summary refs log tree commit diff
path: root/users/sterni/nix/build/buildGopherHole/default.nix
blob: eec13a86542158bad2aabe82b5919ab613bdab14 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
{ depot, pkgs, lib, ... }:

let
  inherit (pkgs)
    runCommand
    writeText
    ;

  inherit (depot.users.sterni.nix.build)
    buildGopherHole
    ;

  fileTypes = {
    # RFC1436
    text = "0";
    menu = "1";
    cso = "2";
    error = "3";
    binhex = "4";
    dos = "5";
    uuencoded = "6";
    index-server = "7";
    telnet = "8";
    binary = "9";
    mirror = "+";
    gif = "g";
    image = "I";
    tn3270 = "T";
    # non-standard
    info = "i";
    html = "h";
  };

  buildFile = { file, name, fileType ? fileTypes.text }:
    runCommand name
      {
        passthru = {
          # respect the file type the file derivation passes
          # through. otherwise use explicitly set type or
          # default value.
          fileType = file.fileType or fileType;
        };
      } ''
      ln -s ${file} "$out"
    '';

  buildGopherMap = dir:
    let
      /* strings constitute an info line or an empty line
         if their length is zero. sets that contain a menu
         value have that added to the gophermap as-is.

         all other entries should be a set which can be built using
         buildGopherHole and is linked by their name. The resulting
         derivation is expected to passthru a fileType containing the
         gopher file type char of themselves.
      */
      gopherMapLine = e:
        if builtins.isString e
        then e
        else if e ? menu
        then e.menu
        else
          let
            drv = buildGopherHole e;
            title = e.title or e.name;
          in
          "${drv.fileType}${title}\t${drv.name}";
    in
    writeText ".gophermap" (lib.concatMapStringsSep "\n" gopherMapLine dir);

  buildDir =
    { dir, name, ... }:

    let
      # filter all entries out that have to be symlinked:
      # sets with the file or dir attribute
      drvOnly = builtins.map buildGopherHole (builtins.filter
        (x: !(builtins.isString x) && (x ? dir || x ? file))
        dir);
      gopherMap = buildGopherMap dir;
    in
    runCommand name
      {
        passthru = {
          fileType = fileTypes.dir;
        };
      }
      (''
        mkdir -p "$out"
        ln -s "${gopherMap}" "$out/.gophermap"
      '' + lib.concatMapStrings
        (drv: ''
          ln -s "${drv}" "$out/${drv.name}"
        '')
        drvOnly);
in

{
  # Dispatch into different file / dir handling code
  # which is mutually recursive with this function.
  __functor = _: args:
    if args ? file then buildFile args
    else if args ? dir then buildDir args
    else builtins.throw "Unrecognized gopher hole item type: "
      + lib.generators.toPretty { } args;

  inherit fileTypes;
}