From 8ca42dc0cd9c9bf462da8b167eb406a65bc83647 Mon Sep 17 00:00:00 2001 From: Profpatsch Date: Sun, 17 Mar 2024 01:21:59 +0100 Subject: feat(users/Profpatsch): add nix-run, nix-run-bin, nix-eval Change-Id: I76f6fa4866c5792c4b9babe2c3a16401162ad833 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11170 Autosubmit: Profpatsch Reviewed-by: Profpatsch Tested-by: BuildkiteCI --- users/Profpatsch/nix-tools.nix | 159 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 users/Profpatsch/nix-tools.nix diff --git a/users/Profpatsch/nix-tools.nix b/users/Profpatsch/nix-tools.nix new file mode 100644 index 0000000000..4f29274573 --- /dev/null +++ b/users/Profpatsch/nix-tools.nix @@ -0,0 +1,159 @@ +{ depot, pkgs, ... }: + +let + bins = depot.nix.getBins pkgs.nix [ "nix-build" "nix-instantiate" ]; + + # TODO: both of these don’t prevent `result` from being created. good? bad? + + # Usage (execline syntax): + # nix-run { -A foo } args... + # + # Takes an execline block of `nix-build` arguments, which should produce an executable store path. + # Then runs the store path with `prog...`. + nix-run = depot.nix.writeExecline "nix-run" { argMode = "env"; } [ + "backtick" + "-iE" + "storepath" + [ + runblock + "1" + bins.nix-build + ] + runblock + "-r" + "2" + "$storepath" + ]; + + # Usage (execline syntax): + # nix-run-bin { -A foo } args... + # + # Takes an execline block of `nix-build` arguments, which should produce a store path with a bin/ directory in it. + # Then runs the given command line with the given arguments. All executables in the built storepath’s bin directory are prepended to `PATH`. + nix-run-bin = depot.nix.writeExecline "nix-run-bin" { argMode = "env"; } [ + "backtick" + "-iE" + "storepath" + [ + runblock + "1" + bins.nix-build + ] + "importas" + "-ui" + "PATH" + "PATH" + "export" + "PATH" + "\${storepath}/bin:\${PATH}" + runblock + "-r" + "2" + ]; + + nix-eval = depot.nix.writeExecline "nix-eval" { } [ + bins.nix-instantiate + "--read-write-mode" + "--eval" + "--strict" + "$@" + ]; + + # 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. + # + # TODO: this was added to recent execline versions, + # but it doesn’t seem to be a drop-in replacement, + # if I use execline’s runblock in nix-run-bin above, + # I get errors like + # > export: fatal: unable to exec runblock: Success + 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 + nix-run + nix-run-bin + nix-eval + ; +} -- cgit 1.4.1