about summary refs log tree commit diff
path: root/pkgs/profpatsch/execline/runblock.nix
blob: bcc90b0c58f9a408ffc38bc557e92794ac44821b (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
{ pkgs }:
let

  # This is a rewrite of execline’s runblock.
  # It adds the feature that instead of just
  # executing the block it reads, it can also
  # pass it as argv to given commands.
  #
  # This is going to be added to a future version
  # of execline by skarnet, but for now it’s easier
  # to just dirtily reimplement it in Python.
  runblock = pkgs.writers.writePython3 "runblock" {
    flakeIgnore = [ "E501" "E226" ];
  } ''
    import sys
    import os
    from pathlib import Path

    skip = False
    one = sys.argv[1]
    if one == "-r":
        skip = True
        block_number = int(sys.argv[2])
        block_start = 3
    elif one.startswith("-"):
        print("runblock-python: only -r supported", file=sys.stderr)
        sys.exit(100)
    else:
        block_number = int(one)
        block_start = 2

    execline_argv_no = int(os.getenvb(b"#"))
    runblock_argv = [os.getenv(str(no)) for no in range(1, execline_argv_no + 1)]


    def parse_block(args):
        new_args = []
        if args == []:
            print(
                "runblock-python: empty block",
                file=sys.stderr
            )
            sys.exit(100)
        for arg in args:
            if arg == "":
                break
            elif arg.startswith(" "):
                new_args.append(arg[1:])
            else:
                print(
                    "runblock-python: unterminated block: {}".format(args),
                    file=sys.stderr
                )
                sys.exit(100)
        args_rest = args[len(new_args)+1:]
        return (new_args, args_rest)


    if skip:
        rest = runblock_argv
        for _ in range(0, block_number-1):
            (_, rest) = parse_block(rest)
        new_argv = rest
    else:
        new_argv = []
        rest = runblock_argv
        for _ in range(0, block_number):
            (new_argv, rest) = parse_block(rest)

    given_argv = sys.argv[block_start:]
    run = given_argv + new_argv
    if os.path.isabs(run[0]):
        # TODO: ideally I’d check if it’s an executable here, but it was too hard to figure out and I couldn’t be bothered tbh
        if not Path(run[0]).is_file():
            print(
                "runblock-python: Executable {} does not exist or is not a file.".format(run[0]),
                file=sys.stderr
            )
            sys.exit(100)
    os.execvp(
        file=run[0],
        args=run
    )
  '';

in { inherit runblock; }