nixpkgs/pkgs/development/misc/resholve/resholve-package.nix
Travis A. Everett 6fd9283bba
resholve: init at 0.4.0 (#85827)
resholve: init at 0.4.0

resholve attempts to resolve executables in shell scripts.
Includes Nix builder for resolving dependencies in Nix-built
shell projects.
2021-01-05 11:56:59 -05:00

98 lines
3.2 KiB
Nix

{ stdenv, lib, resholve }:
{ pname
, src
, version
, passthru ? { }
, solutions
, ...
}@attrs:
let
inherit stdenv;
/* These functions break up the work of partially validating the
* 'solutions' attrset and massaging it into env/cli args.
*
* Note: some of the left-most args do not *have* to be passed as
* deep as they are, but I've done so to provide more error context
*/
# for brevity / line length
spaces = l: builtins.concatStringsSep " " l;
semicolons = l: builtins.concatStringsSep ";" l;
/* Throw a fit with dotted attr path context */
nope = path: msg:
throw "${builtins.concatStringsSep "." path}: ${msg}";
/* Special-case directive value representations by type */
makeDirective = solution: env: name: val:
if builtins.isInt val then builtins.toString val
else if builtins.isString val then name
else if true == val then name
else if false == val then "" # omit!
else if null == val then "" # omit!
else if builtins.isList val then "${name}:${semicolons val}"
else nope [ solution env name ] "unexpected type: ${builtins.typeOf val}";
/* Build fake/fix/keep directives from Nix types */
makeDirectives = solution: env: val:
lib.mapAttrsToList (makeDirective solution env) val;
/* Special-case value representation by type/name */
makeEnvVal = solution: env: val:
if env == "inputs" then lib.makeBinPath val
else if builtins.isString val then val
else if builtins.isList val then spaces val
else if builtins.isAttrs val then spaces (makeDirectives solution env val)
else nope [ solution env ] "unexpected type: ${builtins.typeOf val}";
/* Shell-format each env value */
shellEnv = solution: env: value:
lib.escapeShellArg (makeEnvVal solution env value);
/* Build a single ENV=val pair */
makeEnv = solution: env: value:
"RESHOLVE_${lib.toUpper env}=${shellEnv solution env value}";
/* Discard attrs claimed by makeArgs */
removeCliArgs = value:
removeAttrs value [ "scripts" "flags" ];
/* Verify required arguments are present */
validateSolution = { scripts, inputs, interpreter, ... }: true;
/* Pull out specific solution keys to build ENV=val pairs */
makeEnvs = solution: value:
spaces (lib.mapAttrsToList (makeEnv solution) (removeCliArgs value));
/* Pull out specific solution keys to build CLI argstring */
makeArgs = { flags ? [ ], scripts, ... }:
spaces (flags ++ scripts);
/* Build a single resholve invocation */
makeInvocation = solution: value:
if validateSolution value then
"${makeEnvs solution value} resholve --overwrite ${makeArgs value}"
else throw "invalid solution"; # shouldn't trigger for now
/* Build resholve invocation for each solution. */
makeCommands = solutions:
lib.mapAttrsToList makeInvocation solutions;
self = (stdenv.mkDerivation ((removeAttrs attrs [ "solutions" ])
// {
inherit pname version src;
buildInputs = [ resholve ];
# enable below for verbose debug info if needed
# supports default python.logging levels
# LOGLEVEL="INFO";
preFixup = ''
pushd "$out"
${builtins.concatStringsSep "\n" (makeCommands solutions)}
popd
'';
}));
in
lib.extendDerivation true passthru self