Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at netboot-syslinux-multiplatform 158 lines 5.8 kB view raw
1{ lib 2}: 3 4/* 5 This is a set of tools to manipulate update scripts as recognized by update.nix. 6 It is still very experimental with **instability** almost guaranteed so any use 7 outside Nixpkgs is discouraged. 8 9 update.nix currently accepts the following type: 10 11 type UpdateScript 12 // Simple path to script to execute script 13 = FilePath 14 // Path to execute plus arguments to pass it 15 | [ (FilePath | String) ] 16 // Advanced attribue set (experimental) 17 | { 18 // Script to execute (same as basic update script above) 19 command : (FilePath | [ (FilePath | String) ]) 20 // Features that the script supports 21 // - commit: (experimental) returns commit message in stdout 22 // - silent: (experimental) returns no stdout 23 supportedFeatures : ?[ ("commit" | "silent") ] 24 // Override attribute path detected by update.nix 25 attrPath : ?String 26 } 27*/ 28 29let 30 /* 31 type ShellArg = String | { __rawShell : String } 32 */ 33 34 /* 35 Quotes all arguments to be safely passed to the Bourne shell. 36 37 escapeShellArgs' : [ShellArg] -> String 38 */ 39 escapeShellArgs' = lib.concatMapStringsSep " " (arg: if arg ? __rawShell then arg.__rawShell else lib.escapeShellArg arg); 40 41 /* 42 processArg : { maxArgIndex : Int, args : [ShellArg], paths : [FilePath] } (String|FilePath) { maxArgIndex : Int, args : [ShellArg], paths : [FilePath] } 43 Helper reducer function for building a command arguments where file paths are replaced with argv[x] reference. 44 */ 45 processArg = 46 { maxArgIndex, args, paths }: 47 arg: 48 if builtins.isPath arg then { 49 args = args ++ [ { __rawShell = "\"\$${builtins.toString maxArgIndex}\""; } ]; 50 maxArgIndex = maxArgIndex + 1; 51 paths = paths ++ [ arg ]; 52 } else { 53 args = args ++ [ arg ]; 54 inherit maxArgIndex paths; 55 }; 56 /* 57 extractPaths : Int [ (String|FilePath) ] { maxArgIndex : Int, args : [ShellArg], paths : [FilePath] } 58 Helper function that extracts file paths from command arguments and replaces them with argv[x] references. 59 */ 60 extractPaths = maxArgIndex: command: builtins.foldl' processArg { inherit maxArgIndex; args = [ ]; paths = [ ]; } command; 61 /* 62 processCommand : { maxArgIndex : Int, commands : [[ShellArg]], paths : [FilePath] } [ (String|FilePath) ] { maxArgIndex : Int, commands : [[ShellArg]], paths : [FilePath] } 63 Helper reducer function for extracting file paths from individual commands. 64 */ 65 processCommand = 66 { maxArgIndex, commands, paths }: 67 command: 68 let 69 new = extractPaths maxArgIndex command; 70 in 71 { 72 commands = commands ++ [ new.args ]; 73 paths = paths ++ new.paths; 74 maxArgIndex = new.maxArgIndex; 75 }; 76 /* 77 extractCommands : Int [[ (String|FilePath) ]] { maxArgIndex : Int, commands : [[ShellArg]], paths : [FilePath] } 78 Helper function for extracting file paths from a list of commands and replacing them with argv[x] references. 79 */ 80 extractCommands = maxArgIndex: commands: builtins.foldl' processCommand { inherit maxArgIndex; commands = [ ]; paths = [ ]; } commands; 81 82 /* 83 commandsToShellInvocation : [[ (String|FilePath) ]] [ (String|FilePath) ] 84 Converts a list of commands into a single command by turning them into a shell script and passing them to `sh -c`. 85 */ 86 commandsToShellInvocation = commands: 87 let 88 extracted = extractCommands 0 commands; 89 in 90 [ 91 "sh" 92 "-c" 93 (lib.concatMapStringsSep ";" escapeShellArgs' extracted.commands) 94 # We need paths as separate arguments so that update.nix can ensure they refer to the local directory 95 # rather than a store path. 96 ] ++ extracted.paths; 97in 98rec { 99 /* 100 normalize : UpdateScript UpdateScript 101 EXPERIMENTAL! Converts a basic update script to the experimental attribute set form. 102 */ 103 normalize = updateScript: { 104 command = lib.toList (updateScript.command or updateScript); 105 supportedFeatures = updateScript.supportedFeatures or [ ]; 106 } // lib.optionalAttrs (updateScript ? attrPath) { 107 inherit (updateScript) attrPath; 108 }; 109 110 /* 111 sequence : [UpdateScript] UpdateScript 112 EXPERIMENTAL! Combines multiple update scripts to run in sequence. 113 */ 114 sequence = 115 scripts: 116 117 let 118 scriptsNormalized = builtins.map normalize scripts; 119 in 120 let 121 scripts = scriptsNormalized; 122 hasCommitSupport = lib.findSingle ({ supportedFeatures, ... }: supportedFeatures == [ "commit" ]) null null scripts != null; 123 validateFeatures = 124 if hasCommitSupport then 125 ({ supportedFeatures, ... }: supportedFeatures == [ "commit" ] || supportedFeatures == [ "silent" ]) 126 else 127 ({ supportedFeatures, ... }: supportedFeatures == [ ]); 128 in 129 130 assert lib.assertMsg (lib.all validateFeatures scripts) "Combining update scripts with features enabled (other than a single script with commit and all other with silent) is currently unsupported."; 131 assert lib.assertMsg (builtins.length (lib.unique (builtins.map ({ attrPath ? null, ... }: attrPath) scripts)) == 1) "Combining update scripts with different attr paths is currently unsupported."; 132 133 { 134 command = commandsToShellInvocation (builtins.map ({ command, ... }: command) scripts); 135 supportedFeatures = lib.optionals hasCommitSupport [ 136 "commit" 137 ]; 138 }; 139 140 /* 141 copyAttrOutputToFile : String FilePath UpdateScript 142 EXPERIMENTAL! Simple update script that copies the output of Nix derivation built by `attr` to `path`. 143 */ 144 copyAttrOutputToFile = 145 attr: 146 path: 147 148 { 149 command = [ 150 "sh" 151 "-c" 152 "cp --no-preserve=all \"$(nix-build -A ${attr})\" \"$0\" > /dev/null" 153 path 154 ]; 155 supportedFeatures = [ "silent" ]; 156 }; 157 158}