You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

84 lines
2.8 KiB

  1. { lib }:
  2. rec {
  3. /* Automatically convert an attribute set to command-line options.
  4. This helps protect against malformed command lines and also to reduce
  5. boilerplate related to command-line construction for simple use cases.
  6. `toGNUCommandLine` returns a list of nix strings.
  7. `toGNUCommandLineShell` returns an escaped shell string.
  8. Example:
  9. cli.toGNUCommandLine {} {
  10. data = builtins.toJSON { id = 0; };
  11. X = "PUT";
  12. retry = 3;
  13. retry-delay = null;
  14. url = [ "https://example.com/foo" "https://example.com/bar" ];
  15. silent = false;
  16. verbose = true;
  17. }
  18. => [
  19. "-X" "PUT"
  20. "--data" "{\"id\":0}"
  21. "--retry" "3"
  22. "--url" "https://example.com/foo"
  23. "--url" "https://example.com/bar"
  24. "--verbose"
  25. ]
  26. cli.toGNUCommandLineShell {} {
  27. data = builtins.toJSON { id = 0; };
  28. X = "PUT";
  29. retry = 3;
  30. retry-delay = null;
  31. url = [ "https://example.com/foo" "https://example.com/bar" ];
  32. silent = false;
  33. verbose = true;
  34. }
  35. => "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
  36. */
  37. toGNUCommandLineShell =
  38. options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
  39. toGNUCommandLine = {
  40. # how to string-format the option name;
  41. # by default one character is a short option (`-`),
  42. # more than one characters a long option (`--`).
  43. mkOptionName ?
  44. k: if builtins.stringLength k == 1
  45. then "-${k}"
  46. else "--${k}",
  47. # how to format a boolean value to a command list;
  48. # by default it’s a flag option
  49. # (only the option name if true, left out completely if false).
  50. mkBool ? k: v: lib.optional v (mkOptionName k),
  51. # how to format a list value to a command list;
  52. # by default the option name is repeated for each value
  53. # and `mkOption` is applied to the values themselves.
  54. mkList ? k: v: lib.concatMap (mkOption k) v,
  55. # how to format any remaining value to a command list;
  56. # on the toplevel, booleans and lists are handled by `mkBool` and `mkList`,
  57. # though they can still appear as values of a list.
  58. # By default, everything is printed verbatim and complex types
  59. # are forbidden (lists, attrsets, functions). `null` values are omitted.
  60. mkOption ?
  61. k: v: if v == null
  62. then []
  63. else [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ]
  64. }:
  65. options:
  66. let
  67. render = k: v:
  68. if builtins.isBool v then mkBool k v
  69. else if builtins.isList v then mkList k v
  70. else mkOption k v;
  71. in
  72. builtins.concatLists (lib.mapAttrsToList render options);
  73. }