This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / lib / make-wrapper.nix
6.6 kB 222 lines
1{ lib, pkgs, ... }: 2{ 3 /** 4 Create a wrapped application that preserves all original outputs (man pages, completions, etc.) 5 6 # Arguments 7 8 - `package`: The package to wrap 9 - `runtimeInputs`: List of packages to add to PATH (optional) 10 - `env`: Attribute set of environment variables to export (optional) 11 - `flags`: Attribute set of command-line flags to add (optional) 12 - `flagSeparator`: Separator between flag names and values (optional, defaults to " ") 13 - `preHook`: Shell script to run before executing the command (optional) 14 - `passthru`: Attribute set to pass through to the wrapped derivation (optional) 15 - `aliases`: List of additional names to symlink to the wrapped executable (optional) 16 - `wrapper`: Custom wrapper function (optional, defaults to exec'ing the original binary with flags) 17 - Called with { env, flags, envString, flagsString, exePath, preHook } 18 19 # Example 20 21 ```nix 22 makeWrapper pkgs.curl { 23 runtimeInputs = [ pkgs.jq ]; 24 env = { 25 CURL_CA_BUNDLE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"; 26 }; 27 flags = { 28 "--silent" = { }; # becomes --silent 29 "--connect-timeout" = "30"; # becomes --connect-timeout 30 30 }; 31 preHook = '' 32 echo "Making request..." >&2 33 ''; 34 } 35 36 # Or with custom wrapper: 37 makeWrapper pkgs.someProgram { 38 wrapper = { exePath, flagsString, envString, preHook, ... }: '' 39 ${envString} 40 ${preHook} 41 echo "Custom logic here" 42 exec ${exePath} ${flagsString} "$@" 43 ''; 44 } 45 ``` 46 */ 47 makeWrapper = 48 package: 49 { 50 runtimeInputs ? [ ], 51 env ? { }, 52 flags ? { }, 53 flagSeparator ? " ", # " " for "--flag value" or "=" for "--flag=value" 54 preHook ? "", 55 passthru ? { }, 56 aliases ? [ ], 57 wrapper ? ( 58 { 59 exePath, 60 flagsString, 61 envString, 62 preHook, 63 ... 64 }: 65 '' 66 ${envString} 67 ${preHook} 68 exec ${exePath}${flagsString} "$@" 69 '' 70 ), 71 }: 72 let 73 # Extract binary name from the exe path 74 exePath = lib.getExe package; 75 binName = baseNameOf exePath; 76 77 # Generate environment variable exports 78 envString = 79 if env == { } then 80 "" 81 else 82 lib.concatStringsSep "\n" ( 83 lib.mapAttrsToList (name: value: ''export ${name}="${toString value}"'') env 84 ) 85 + "\n"; 86 87 # Generate flag arguments with proper line breaks and indentation 88 flagsString = 89 if flags == { } then 90 "" 91 else 92 " \\\n " 93 + lib.concatStringsSep " \\\n " ( 94 lib.mapAttrsToList ( 95 name: value: 96 if value == { } then "${name}" else "${name}${flagSeparator}${lib.escapeShellArg (toString value)}" 97 ) flags 98 ); 99 100 finalWrapper = wrapper { 101 inherit 102 env 103 flags 104 envString 105 flagsString 106 exePath 107 preHook 108 ; 109 }; 110 111 # Multi-output aware symlink join function 112 multiOutputSymlinkJoin = 113 { 114 name, 115 paths, 116 outputs ? [ "out" ], 117 originalOutputs ? { }, 118 passthru ? { }, 119 meta ? { }, 120 aliases ? [ ], 121 binName ? null, 122 ... 123 }@args: 124 pkgs.stdenv.mkDerivation ( 125 { 126 inherit name outputs; 127 128 buildCommand = '' 129 # Symlink all paths to the main output 130 mkdir -p $out 131 for path in ${lib.concatStringsSep " " (map toString paths)}; do 132 ${pkgs.lndir}/bin/lndir -silent "$path" $out 133 done 134 135 # Create symlinks for aliases 136 ${lib.optionalString (aliases != [ ] && binName != null) '' 137 mkdir -p $out/bin 138 for alias in ${lib.concatStringsSep " " (map lib.escapeShellArg aliases)}; do 139 ln -sf ${lib.escapeShellArg binName} $out/bin/$alias 140 done 141 ''} 142 143 # Handle additional outputs by symlinking from the original package's outputs 144 ${lib.concatMapStringsSep "\n" ( 145 output: 146 if output != "out" && originalOutputs ? ${output} && originalOutputs.${output} != null then 147 '' 148 if [[ -n "''${${output}:-}" ]]; then 149 mkdir -p ${"$" + output} 150 # Only symlink from the original package's corresponding output 151 ${pkgs.lndir}/bin/lndir -silent "${originalOutputs.${output}}" ${"$" + output} 152 fi 153 '' 154 else 155 "" 156 ) outputs} 157 ''; 158 159 inherit passthru meta; 160 } 161 // (removeAttrs args [ 162 "name" 163 "paths" 164 "outputs" 165 "originalOutputs" 166 "passthru" 167 "meta" 168 "aliases" 169 "binName" 170 ]) 171 ); 172 173 # Get original package outputs for symlinking 174 originalOutputs = 175 if package ? outputs then 176 lib.listToAttrs ( 177 map (output: { 178 name = output; 179 value = if package ? ${output} then package.${output} else null; 180 }) package.outputs 181 ) 182 else 183 { }; 184 185 # Create the wrapper derivation using our multi-output aware symlink join 186 wrappedPackage = multiOutputSymlinkJoin ( 187 { 188 name = package.pname or package.name; 189 paths = [ 190 (pkgs.writeShellApplication { 191 name = binName; 192 runtimeInputs = runtimeInputs; 193 text = finalWrapper; 194 }) 195 package 196 ]; 197 outputs = if package ? outputs then package.outputs else [ "out" ]; 198 inherit originalOutputs aliases binName; 199 passthru = 200 (package.passthru or { }) 201 // passthru 202 // { 203 inherit 204 env 205 flags 206 preHook 207 aliases 208 ; 209 }; 210 # Pass through original attributes 211 meta = package.meta or { }; 212 } 213 // lib.optionalAttrs (package ? version) { 214 inherit (package) version; 215 } 216 // lib.optionalAttrs (package ? pname) { 217 inherit (package) pname; 218 } 219 ); 220 in 221 wrappedPackage; 222}