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 <mail@profpatsch.de> Reviewed-by: Profpatsch <mail@profpatsch.de> Tested-by: BuildkiteCI
This commit is contained in:
		
							parent
							
								
									11a2098e0b
								
							
						
					
					
						commit
						8ca42dc0cd
					
				
					 1 changed files with 159 additions and 0 deletions
				
			
		
							
								
								
									
										159
									
								
								users/Profpatsch/nix-tools.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								users/Profpatsch/nix-tools.nix
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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 <more_nix_options> } 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 <more_nix_options> } <foo_bin_name> 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
 | 
				
			||||||
 | 
					    ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue