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
110
111
112
113
114
115
116
{ depot, pkgs, lib, ... }:
let
  bins = depot.nix.getBins pkgs.s6-portable-utils [ "s6-mkdir" "s6-cat" "s6-ln" "s6-ls" "s6-touch" ]
    // depot.nix.getBins pkgs.coreutils [ "printf" ];

  # Deliberately the unversioned alias rather than a pinned `pythonNNPackages`:
  # a pinned one silently disappears on a channel bump, which is how this went
  # unnoticed for years while `python310Packages` no longer existed.
  pythonPackages = pkgs.python3Packages;
  buildPythonPackages = pkgs.buildPackages.python3Packages;
  python = pythonPackages.python;

  # python3 :: { name :: string
  #            , libraries :: pythonPackages -> [derivation]
  #            , flakeIgnore :: [string]  # flake8 error codes, e.g. "E501"
  #            }
  #         -> string -> derivation
  python3 =
    { name
    , libraries ? (_: [ ])
    , flakeIgnore ? [ ]
    }:
    pkgs.writers.makePythonWriter python pythonPackages buildPythonPackages name {
      libraries = libraries pythonPackages;
      flakeIgnore =
        let
          ignoreTheseErrors = [
            # whitespace after {
            "E201"
            # whitespace before }
            "E202"
            # fuck 4-space indentation
            "E121"
            "E111"
            # who cares about blank lines …
            # … at end of files
            "W391"
            # … between functions
            "E302"
            "E305"
            # … if there’s too many of them
            "E303"
            # or lines that are too long
            "E501"
          ];
        in
        ignoreTheseErrors ++ flakeIgnore;
    };

  # TODO: add the same flake check as the pyhon3 writer
  python3Lib = { name, libraries ? (_: [ ]) }: moduleString:
    let
      srcTree = depot.nix.runExecline.local name { stdin = moduleString; } [
        "importas"
        "out"
        "out"
        "if"
        [ bins.s6-mkdir "-p" "\${out}/${name}" ]
        "if"
        [
          "redirfd"
          "-w"
          "1"
          "\${out}/setup.py"
          bins.printf
          ''
            from distutils.core import setup

            setup(
              name='%s',
              packages=['%s']
            )
          ''
          name
          name
        ]
        "if"
        [
          # redirect stdin to the init py
          "redirfd"
          "-w"
          "1"
          "\${out}/${name}/__init__.py"
          bins.s6-cat
        ]
      ];
    in
    pythonPackages.buildPythonPackage {
      inherit name;
      src = srcTree;
      pyproject = true;
      build-system = [ buildPythonPackages.setuptools ];
      dependencies = libraries pythonPackages;
      doCheck = false;
    };


  ghcBins = libraries: depot.nix.getBins (pkgs.ghc.withPackages (_: libraries)) [ "runghc" ];

  writeHaskellInteractive = name: { libraries, ghcArgs ? [ ] }: path:
    depot.nix.writeExecline name { } ([
      (ghcBins libraries).runghc
      "--"
    ] ++ ghcArgs ++ [
      "--"
      path
    ]);

in
{
  inherit
    python3
    python3Lib
    writeHaskellInteractive
    ;
}