diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55478ab..22cd1a6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,10 +47,10 @@ You may optionally set the `meta.description` option to provide a short descript ## Guidelines and Examples: -When you provide an option to `enable` or `disable` something, you should call it `enable` regardless of its default value. +- When you provide an option to `enable` or `disable` something, you should call it `enable` regardless of its default value. This prevents people from needing to look it up to use it, and prevents contributors from having to think too hard about which to call it. -When you provide a `wlib.types.file` option, you should name it the actual filename, especially if there are multiple, but `configFile` is also OK, especially if it is unambiguous. +- When you provide a `wlib.types.file` option, you should name it the actual filename, especially if there are multiple, but `configFile` is also OK, especially if it is unambiguous. If you do name it `configFile` instead, you can fix the filename if necessary/desired by setting `default.path` explicitly, as shown in the example below. @@ -60,6 +60,14 @@ However, this makes the user of your module search for it, and in some situation So making use of the `wlib.types.file` type or giving some other method of overriding the filepath when providing a file is generally recommended for this reason. +- When you generate a file, it is generally better to do so as a string, and create it using the `constructFiles` option. + +This is because, this will make placeholders such as `${placeholder "out"}` work consistently across all your options. + +What this allows you to do, is manually build files later using `buildCommand` option or a stdenv phase, and then refer to that created file within your settings! + +Making placeholders work in your module makes your modules generally more easily extensible, and is preferred when it is possible to generate a usable string. + Example: ```nix @@ -70,31 +78,40 @@ Example: pkgs, ... }: -let - gitIniFmt = pkgs.formats.gitIni { }; -in { imports = [ wlib.modules.default ]; options = { settings = lib.mkOption { - inherit (gitIniFmt) type; + inherit (pkgs.formats.gitIni { }) type; default = { }; description = '' Git configuration settings. See {manpage}`git-config(1)` for available options. ''; }; - configFile = lib.mkOption { type = wlib.types.file pkgs; - default.path = gitIniFmt.generate "gitconfig" config.settings; + default = { + path = config.constructFiles.gitconfig.path; # <- we can refer to the placeholder of our constructed file! + content = ""; + }; description = "Generated git configuration file."; }; }; - - config.env.GIT_CONFIG_GLOBAL = config.configFile.path; - config.package = lib.mkDefault pkgs.git; - config.meta.maintainers = [ wlib.maintainers.birdee ]; + config = { + env.GIT_CONFIG_GLOBAL = config.configFile.path; + package = lib.mkDefault pkgs.git; + constructFiles.gitconfig = { # <- constructs the path directly in the final wrapper derivation, such that placeholders work correctly. + relPath = "${config.binName}config"; + # A string, which is to become the file contents + content = + # nixpkgs has a lot of handy generation functions! + lib.generators.toGitINI config.settings + # and gitconfig format allows you to arbitrarily append contents! + + "\n" + config.configFile.content; + }; + meta.maintainers = [ wlib.maintainers.birdee ]; # <- don't forget to make yourself the maintainer of your module! + }; } ``` diff --git a/lib/core.nix b/lib/core.nix index 27043c8..85e645c 100644 --- a/lib/core.nix +++ b/lib/core.nix @@ -526,37 +526,25 @@ in It is added via the apply field of the option for you. ''; }; - wrapperFunction = lib.mkOption { - type = lib.types.nullOr (lib.types.functionTo lib.types.raw); - default = null; + buildCommand = lib.mkOption { + type = wlib.types.dagOf lib.types.lines; + default = { }; description = '' - Arguments: - - This option takes a function receiving the following arguments: + This option is to be used to fulfill the contract formed by `config.wrapperPaths` - module arguments + `pkgs.callPackage` - - ``` - { - config, - wlib, - ... # <- anything you can get from pkgs.callPackage - } - ``` - - The result of this function is passed DIRECTLY to the value of the `builderFunction` function. + This option is used by builderFunction to create a build script which will be ran in the resulting derivation. The relative path to the thing to wrap is `config.wrapperPaths.input` - This function is to return a value which creates a result at `config.wrapperPaths.placeholder` + The result should be created at `config.wrapperPaths.placeholder` - The type this value is to return is dictated by `config.builderFunction`. + In most wrapper modules, this contract has been fulfilled for you by `wlib.modules.makeWrapper` + and `wlib.modules.symlinkScript`, which are imported by `wlib.modules.default` - The default implementation, as well as the implementation from `wlib.modules.symlinkScript` - accept either a string which will be prepended to `buildCommand` (preferred), - or a derivation which can be symlinked into the resulting derivation output to create the desired path. + However, you may add extra entries, and place them before or after the commands provided by those modules. - Again, the result is passed DIRECTLY as an argument to the function which is the value of `config.builderFunction` + This is a more flexible form of providing derivation build commands than the normal `drv.buildPhase` style options. + However, those are also usable, as are the other `drv` attributes such as things like `drv.__structuredAttrs`. ''; }; builderFunction = lib.mkOption { @@ -564,40 +552,38 @@ in lib.types.either lib.types.str (lib.types.functionTo (lib.types.attrsOf lib.types.raw)) ); description = '' - Outside of importing `wlib.modules.symlinkScript` module, - which is included in `wlib.modules.default`, This is usually an option you will never have to redefine. This option takes a function receiving the following arguments: - module arguments + `wrapper` + `pkgs.callPackage` + module arguments + `buildCommand` + `pkgs.callPackage` + + `buildCommand` is the already sorted and concatenated result of the `config.buildCommand` DAG option, + for convenience. + + This function is in charge of running the generated `buildCommand` build script, + generated from the `config.buildCommand` option. + + The function provided may be in 1 of 3 forms. + + - The function is to return a string which will be added to the buildCommand of the wrapper. ``` { wlib, config, - wrapper, + buildCommand, ... # <- anything you can get from pkgs.callPackage }@initialArgs: - "" + buildCommand # <- gets provided to buildCommand attribute of the final drv ``` - It is in charge of linking `wrapper` and `config.outputs` to the final package. - - `wrapper` is the unchecked result of calling `wrapperFunction`, or null if one was not provided. - - - The function is to return a string which will be added to the buildCommand of the wrapper. - - The builtin implementation, and also the `wlib.modules.symlinkScript` module, - accept either a string to prepend to the returned `buildCommand` string, - or a derivation to link with lndir - - Alternatively, it may return a function which returns a set like: ```nix - { wlib, config, wrapper, ... }@initialArgs: + { wlib, config, buildCommand, ... }@initialArgs: drvArgs: - drvArgs // {} + drvArgs // { inherit buildCommand; } ``` If it does this, that function will be given the final computed derivation attributes, @@ -612,7 +598,7 @@ in - You can also return a _functor_ with a (required) `mkDerivation` field. ```nix - { config, stdenv, wrapper, wlib, ... }@initialArgs: + { config, stdenv, buildCommand, wlib, ... }@initialArgs: { inherit (stdenv) mkDerivation; __functor = { @@ -624,7 +610,12 @@ in ... }@self: defaultArgs: - defaultArgs // (if config.sourceStdenv then { } else { buildCommand = ""; } + defaultArgs // { + buildCommand = + lib.optionalString config.sourceStdenv (setupPhases defaultPhases) + + buildCommand + + lib.optionalString config.sourceStdenv runPhases; + }; } ``` @@ -642,44 +633,7 @@ in Tip: A _functor_ is a set with a `{ __functor = self: args: ...; }` field. You can call it like a function and it gets passed itself as its first argument! ''; - default = - { - wlib, - config, - wrapper, - lib, - lndir, - ... - }: - let - originalOutputs = wlib.getPackageOutputsSet config.package; - in - "mkdir -p ${placeholder config.outputName} \n" - + ( - if builtins.isString wrapper then - wrapper - else if wrapper != null then - "${lndir}/bin/lndir -silent \"${toString wrapper}\" ${placeholder config.outputName}" - else - "" - ) - + '' - - # Handle additional outputs by symlinking from the original package's outputs - ${lib.concatMapStringsSep "\n" ( - output: - if originalOutputs ? ${output} && originalOutputs.${output} != null then - '' - if [[ -n "''${${output}:-}" ]]; then - mkdir -p ${placeholder output} - # Only symlink from the original package's corresponding output - ${lndir}/bin/lndir -silent "${originalOutputs.${output}}" ${placeholder output} - fi - '' - else - "" - ) config.outputs} - ''; + default = { buildCommand, ... }: buildCommand; }; sourceStdenv = lib.mkOption { type = lib.types.bool; @@ -835,9 +789,22 @@ in ''; initial = pkgs.callPackage config.builderFunction ( args - // { - wrapper = - if config.wrapperFunction == null then null else pkgs.callPackage config.wrapperFunction args; + // rec { + wrapper = lib.warn '' + the `wrapper` argument of config.builderFunction is deprecated. + + Instead of `wrapper`, you will need to run `buildCommand` argument instead. + + It contains the sorted and concatenated value of `config.buildCommand` DAG option + + If you wish to sort the `config.buildCommand` DAG yourself instead, this is fine, + but it has been provided in sorted form via the `buildCommand` argument for convenience. + '' buildCommand; + buildCommand = lib.pipe config.buildCommand [ + (wlib.dag.unwrapSort "buildCommand") + (map (v: v.data)) + (builtins.concatStringsSep "\n") + ]; } ); in diff --git a/modules/constructFiles/module.nix b/modules/constructFiles/module.nix new file mode 100644 index 0000000..eb96ee1 --- /dev/null +++ b/modules/constructFiles/module.nix @@ -0,0 +1,175 @@ +{ + config, + lib, + wlib, + ... +}@top: +{ + options.constructFiles = lib.mkOption { + description = '' + An option for creating files with content of arbitrary length in the final wrapper derivation, + in which the nix placeholders like `''${placeholder "out"}` can be used + ''; + default = { }; + type = lib.types.attrsOf ( + lib.types.submodule ( + { config, name, ... }: + { + config.outPath = + if config.relPath == "" then + "${top.config.wrapper.${config.output}}" + else + "${top.config.wrapper.${config.output}}/${config.relPath}"; + config.path = + if config.relPath == "" then + "${placeholder config.output}" + else + "${placeholder config.output}/${config.relPath}"; + options = { + key = lib.mkOption { + type = wlib.types.nonEmptyLine; + default = name; + description = '' + The attribute to add the file contents to on the final derivation + ''; + }; + content = lib.mkOption { + type = lib.types.lines; + default = ""; + description = '' + The content for the file to be added to the final derivation + ''; + }; + output = lib.mkOption { + type = wlib.types.nonEmptyLine; + default = top.config.outputName; + description = '' + The output the generated file will be created in. + ''; + }; + outPath = lib.mkOption { + type = lib.types.str; + readOnly = true; + description = "The path to the output file available from outside of the wrapper module"; + }; + path = lib.mkOption { + type = lib.types.str; + readOnly = true; + description = "The path to the output file available from inside of the wrapper module"; + }; + relPath = lib.mkOption { + type = lib.types.str; + description = '' + relative output path within the named output to create the file (no leading slash) + ''; + }; + builder = lib.mkOption { + type = lib.types.str; + default = ''mkdir -p "$(dirname "$2")" && cp "$1" "$2"''; + description = '' + the command used to build the file. + + Will be placed inside a bash function, + with $1 as the input file and $2 as the output file + ''; + }; + }; + } + ) + ); + }; + config.drv = lib.mkIf (config.constructFiles != { }) ( + let + files = builtins.attrValues config.constructFiles; + result = + builtins.foldl' + (acc: v: { + attrs = acc.attrs // { + ${v.key} = v.content; + }; + passAsFile = acc.passAsFile ++ [ v.key ]; + }) + { + attrs = { }; + passAsFile = [ ]; + } + files; + in + result.attrs // { inherit (result) passAsFile; } + ); + config.buildCommand.constructFiles = { + before = [ + "makeWrapper" + "symlinkScript" + ]; + data = + let + constructFile = name: path: builder: /* bash */ '' + constructFile() { + ${builder} + } + local sourceDrvVarToConstruct=${lib.escapeShellArg "${name}Path"} + constructFile "''${!sourceDrvVarToConstruct}" ${lib.escapeShellArg path} + ''; + in + '' + # create constructFiles + ${lib.optionalString (config.constructFiles != { }) ( + lib.pipe config.constructFiles [ + builtins.attrValues + (map ( + { + path, + builder, + key, + ... + }: + constructFile key path builder + )) + ( + v: + [ "constructFile(){" ] + ++ v + ++ [ + "}" + "constructFile" + "unset -f constructFile" + ] + ) + (builtins.concatStringsSep "\n") + ] + )} + ''; + }; + config.meta.maintainers = [ wlib.maintainers.birdee ]; + config.meta.description = '' + Adds a `constructFiles` option that allows for easier creation of generated files in which placeholders such as `''${placeholder "out"}` work + + From inside the module, you can + + ```nix + config.constructFiles. = { + content = "some file content"; + relPath = "some/path"; + }; + # you can get the resulting placeholder path with config.constructFiles..path + ``` + + It also provides a read-only config value that allows the placeholder file location to be easily accessible outside of the derivation. + + In addition, on the resulting package, all the values in config are accessible via `passthru.configuration` + + This means you can `yourWrappedPackage.configuration.constructFiles..outPath` to get the final path to it from outside of the wrapper module, + without having to worry about making sure placeholders resolve correctly yourself. + + Note, that will not work inside the module. Inside the module, you will want to use `config.constructFiles..path`. + + Also note that attribute sets with `.outPath` in them can be directly interpolated. + + Outside the module, you can also get the path with `"''${yourWrappedPackage.configuration.constructFiles.}"` + + Imported by `wlib.modules.default` + + --- + ''; +} diff --git a/modules/default/module.nix b/modules/default/module.nix index 8590ccc..4ee8f93 100644 --- a/modules/default/module.nix +++ b/modules/default/module.nix @@ -2,6 +2,7 @@ { imports = [ wlib.modules.symlinkScript + wlib.modules.constructFiles wlib.modules.makeWrapper ]; config.meta.maintainers = [ wlib.maintainers.birdee ]; diff --git a/modules/makeWrapper/module.nix b/modules/makeWrapper/module.nix index 9ed5641..c6ca333 100644 --- a/modules/makeWrapper/module.nix +++ b/modules/makeWrapper/module.nix @@ -690,20 +690,84 @@ in __functor = self: { - wlib, + config, lib, + wlib, + pkgs, + # NOTE: makes sure builderFunction and wrapperFunction get name from _module.args + options, + extendModules, + name ? null, ... - }: + }@args: { _file = self._file or ./module.nix; ${if (self.key or ./module.nix) != null then "key" else null} = self.key or ./module.nix; imports = [ (options_module (self._file or ./module.nix) (self.excluded_options or { }) true) ]; - config.${if self.exclude_wrapper or false then null else "wrapperFunction"} = lib.mkDefault ( - if self.wrapperFunction or null != null then - self.wrapperFunction or wlib.makeWrapper.wrapAll + options.${ + if + builtins.isBool (self.excluded_options.wrapperFunction or null) + && self.excluded_options.wrapperFunction + then + null else - wlib.makeWrapper.wrapAll - ); + "wrapperFunction" + } = + lib.mkOption { + type = lib.types.functionTo lib.types.str; + default = + if self.wrapperFunction or null != null then self.wrapperFunction else wlib.makeWrapper.wrapAll; + description = '' + Arguments: + + This option takes a function receiving the following arguments: + + module arguments + `pkgs.callPackage` + + ``` + { + config, + wlib, + ... # <- anything you can get from pkgs.callPackage + } + ``` + This is the function used to process the wrapper arguments. + + By default, it is `wlib.makeWrapper.wrapAll` + + It will be called with the normal module arguments + `pkgs.callPackage` arguments + + The module calls it, and places the result in `config.buildCommand.makeWrapper` with `lib.mkOptionDefault` priority. + + The relative path to the thing to wrap is `config.wrapperPaths.input` + + This function is to return a string of build commands which create a result at `config.wrapperPaths.placeholder` + ''; + }; + config.${if self.exclude_wrapper or false then null else "buildCommand"}.makeWrapper = { + before = [ "symlinkScript" ]; + data = lib.mkOptionDefault ( + let + res = pkgs.callPackage ( + if + builtins.isBool (self.excluded_options.wrapperFunction or null) + && self.excluded_options.wrapperFunction + then + wlib.makeWrapper.wrapAll + else + config.wrapperFunction + ) args; + in + if builtins.isString res then + res + else + throw '' + Returning something other than a build command string from wrapperFunction is no longer supported. + + To pass other values to `builderFunction`, place them in an option. + '' + ); + }; config.${if self.exclude_meta or false then null else "meta"} = { maintainers = [ wlib.maintainers.birdee ]; description = { @@ -753,7 +817,7 @@ in You may `//` (update) the following values into the set you gain from importing the file: - `exclude_wrapper = true;` to stop it from setting `config.wrapperFunction` + `exclude_wrapper = true;` to stop it from setting `config.buildCommand.makeWrapper` `wrapperFunction = ...;` to override the default `config.wrapperFunction` that it sets instead of excluding it. diff --git a/modules/symlinkScript/module.nix b/modules/symlinkScript/module.nix index 4bc047c..8781545 100644 --- a/modules/symlinkScript/module.nix +++ b/modules/symlinkScript/module.nix @@ -30,111 +30,93 @@ ''; }; }; - config.drv.nativeBuildInputs = lib.mkIf ((config.filesToPatch or [ ]) != [ ]) [ - pkgs.replace - ]; - config.builderFunction = lib.mkDefault ( - { - config, - wlib, - wrapper, - # other args from callPackage - lib, - lndir, - ... - }: - let - inherit (config) - package - aliases - outputName - wrapperPaths - filesToPatch - filesToExclude - binName - outputs - ; - originalOutputs = wlib.getPackageOutputsSet package; - in - "mkdir -p ${placeholder outputName} \n" - + ( - if builtins.isString wrapper then - wrapper - else if wrapper != null then - "${lndir}/bin/lndir -silent \"${toString wrapper}\" ${placeholder outputName}" - else - "" - ) - + '' + config.buildCommand.symlinkScript = { + data = lib.mkOptionDefault ( + let + inherit (config) + package + aliases + outputName + wrapperPaths + filesToPatch + filesToExclude + binName + outputs + ; + lndir = pkgs.lndir; + originalOutputs = wlib.getPackageOutputsSet package; + in + '' + mkdir -p ${placeholder outputName} - # Handle additional outputs by symlinking from the original package's outputs - ${lib.concatMapStringsSep "\n" ( - output: - if originalOutputs ? ${output} && originalOutputs.${output} != null then - '' + # Handle additional outputs by symlinking from the original package's outputs + ${lib.concatMapStringsSep "\n" ( + output: + if originalOutputs ? ${output} && originalOutputs.${output} != null then + '' - if [[ -n "''${${output}:-}" ]]; then - mkdir -p ${placeholder output} - # Only symlink from the original package's corresponding output - ${lndir}/bin/lndir -silent "${originalOutputs.${output}}" ${placeholder output} - fi + if [[ -n "''${${output}:-}" ]]; then + mkdir -p ${placeholder output} + # Only symlink from the original package's corresponding output + ${lndir}/bin/lndir -silent "${originalOutputs.${output}}" ${placeholder output} + fi - # Exclude specified files for ${output} - ${lib.optionalString (filesToExclude != [ ]) '' - echo "Excluding specified files..." - ${lib.concatMapStringsSep "\n" (pattern: '' - for file in ${placeholder output}/${pattern}; do - if [[ -e "$file" ]]; then - echo "Removing $file" - rm -f "$file" - fi - done - '') filesToExclude} - ''} + # Exclude specified files for ${output} + ${lib.optionalString (filesToExclude != [ ]) '' + echo "Excluding specified files..." + ${lib.concatMapStringsSep "\n" (pattern: '' + for file in ${placeholder output}/${pattern}; do + if [[ -e "$file" ]]; then + echo "Removing $file" + rm -f "$file" + fi + done + '') filesToExclude} + ''} - # Patch specified files to replace references to the original package with the wrapped one - ${lib.optionalString (filesToPatch != [ ]) '' - echo "Patching self-references in specified files..." - oldPath="${originalOutputs.${output}}" - newPath="${placeholder output}" + # Patch specified files to replace references to the original package with the wrapped one + ${lib.optionalString (filesToPatch != [ ]) '' + echo "Patching self-references in specified files..." + oldPath="${originalOutputs.${output}}" + newPath="${placeholder output}" - # Process each file pattern - ${lib.concatMapStringsSep "\n" (pattern: '' - for file in ${placeholder output}/${pattern}; do - if [[ -L "$file" ]]; then - # It's a symlink, we need to resolve it - target=$(readlink -f "$file") + # Process each file pattern + ${lib.concatMapStringsSep "\n" (pattern: '' + for file in ${placeholder output}/${pattern}; do + if [[ -L "$file" ]]; then + # It's a symlink, we need to resolve it + target=$(readlink -f "$file") - # Check if the file contains the old path - if grep -qF "$oldPath" "$target" 2>/dev/null; then - echo "Patching $file" - # Remove symlink and create a real file with patched content - rm "$file" - # Use replace-literal which works for both text and binary files - replace-literal "$oldPath" "$newPath" < "$target" > "$file" - # Preserve permissions - chmod --reference="$target" "$file" + # Check if the file contains the old path + if grep -qF "$oldPath" "$target" 2>/dev/null; then + echo "Patching $file" + # Remove symlink and create a real file with patched content + rm "$file" + # Use replace-literal which works for both text and binary files + ${pkgs.replace}/bin/replace-literal "$oldPath" "$newPath" < "$target" > "$file" + # Preserve permissions + chmod --reference="$target" "$file" + fi fi - fi - done - '') filesToPatch} - ''} - - '' - else - "" - ) outputs} + done + '') filesToPatch} + ''} - # Create symlinks for aliases - ${lib.optionalString (aliases != [ ] && binName != "") '' - mkdir -p ${placeholder outputName}/bin - for alias in ${lib.concatStringsSep " " (map lib.escapeShellArg aliases)}; do - ln -sf ${wrapperPaths.placeholder} ${placeholder config.outputName}/bin/$alias - done - ''} + '' + else + "" + ) outputs} - '' - ); + # Create symlinks for aliases + ${lib.optionalString (aliases != [ ] && binName != "") '' + mkdir -p ${placeholder outputName}/bin + for alias in ${lib.escapeShellArgs aliases}; do + ln -sf ${wrapperPaths.placeholder} ${placeholder config.outputName}/bin/$alias + done + ''} + '' + ); + }; config.meta.maintainers = [ wlib.maintainers.birdee ]; config.meta.description = '' Adds extra options compared to the default `builderFunction` option value. diff --git a/wrapperModules/a/aria2/module.nix b/wrapperModules/a/aria2/module.nix index e7accbe..6328f87 100644 --- a/wrapperModules/a/aria2/module.nix +++ b/wrapperModules/a/aria2/module.nix @@ -15,7 +15,6 @@ let in { imports = [ wlib.modules.default ]; - options = { settings = lib.mkOption { type = @@ -34,21 +33,13 @@ in package = pkgs.aria2; binName = "aria2c"; outputs = (config.package.outputs or [ "out" ]) ++ [ "conf" ]; - flags = { - "--conf-path" = "${placeholder "conf"}/${config.binName}-settings.conf"; + flags."--conf-path" = config.constructFiles.renderedSettings.path; + constructFiles.renderedSettings = { + relPath = "${config.binName}-settings.conf"; + output = "conf"; + content = lib.concatStringsSep "\n" (lib.mapAttrsToList formatLine config.settings); }; flagSeparator = "="; - drv = { - renderedSettings = lib.concatStringsSep "\n" (lib.mapAttrsToList formatLine config.settings); - passAsFile = [ "renderedSettings" ]; - - buildPhase = '' - runHook preBuild - mkdir -p $conf - cp $renderedSettingsPath "$conf/${config.binName}-settings.conf" - runHook postBuild - ''; - }; wrapperVariants.aria2c.outputName = "out"; meta.maintainers = [ wlib.maintainers.rachitvrma ]; }; diff --git a/wrapperModules/g/git/module.nix b/wrapperModules/g/git/module.nix index 48423e6..d660a80 100644 --- a/wrapperModules/g/git/module.nix +++ b/wrapperModules/g/git/module.nix @@ -5,9 +5,6 @@ pkgs, ... }: -let - gitconfigPath = "${placeholder config.outputName}/${config.binName}config"; -in { imports = [ wlib.modules.default ]; options = { @@ -19,36 +16,31 @@ in See {manpage}`git-config(1)` for available options. ''; }; - configFile = lib.mkOption { type = wlib.types.file pkgs; - default.path = gitconfigPath; + default.path = config.constructFiles.gitconfig.path; default.content = ""; description = "Generated git configuration file."; }; }; + config = { + env.GIT_CONFIG_GLOBAL = config.configFile.path; + package = lib.mkDefault pkgs.git; + constructFiles.gitconfig = { + relPath = "${config.binName}config"; + content = lib.generators.toGitINI config.settings + "\n" + config.configFile.content; + }; + meta.maintainers = [ wlib.maintainers.birdee ]; + meta.description = '' + Nix uses git for all sorts of things. Including fetching flakes! - config.env.GIT_CONFIG_GLOBAL = config.configFile.path; - config.package = lib.mkDefault pkgs.git; - config.drv = { - gitconfig = lib.generators.toGitINI config.settings + "\n" + config.configFile.content; - passAsFile = [ "gitconfig" ]; - buildPhase = '' - runHook preBuild - cp "$gitconfigPath" ${lib.escapeShellArg gitconfigPath} - runHook postBuild - ''; - }; - config.meta.maintainers = [ wlib.maintainers.birdee ]; - config.meta.description = '' - Nix uses git for all sorts of things. Including fetching flakes! - - So if you put this one in an overlay, name it something other than `pkgs.git`! + So if you put this one in an overlay, name it something other than `pkgs.git`! - Otherwise you will probably get infinite recursion. + Otherwise you will probably get infinite recursion. - The vast majority of other packages do not have this issue. And, - due to the passthrough of `.override` and `.overrideAttrs`, - most other packages are safe to replace with their wrapped counterpart in overlays directly. - ''; + The vast majority of other packages do not have this issue. And, + due to the passthrough of `.override` and `.overrideAttrs`, + most other packages are safe to replace with their wrapped counterpart in overlays directly. + ''; + }; } diff --git a/wrapperModules/h/htop/module.nix b/wrapperModules/h/htop/module.nix index 4381a52..8b64f51 100644 --- a/wrapperModules/h/htop/module.nix +++ b/wrapperModules/h/htop/module.nix @@ -22,7 +22,6 @@ let mkKeyValue = lib.generators.mkKeyValueDefault { inherit mkValueString; } "="; toHtopConf = lib.generators.toKeyValue { inherit mkKeyValue; }; - configPath = "${placeholder config.outputName}/${config.binName}rc"; htopConfig = lib.concatLines [ # header_layout must be the first in file (or at least just above) so column_meter* parameters can work (toHtopConf (lib.filterAttrs (n: _: n == "header_layout") config.settings)) @@ -31,7 +30,6 @@ let in { imports = [ wlib.modules.default ]; - options = { settings = lib.mkOption { type = @@ -56,17 +54,13 @@ in ''; }; }; - - config.package = lib.mkDefault pkgs.htop; - - config.drv.htopConfig = htopConfig; - config.drv.passAsFile = [ "htopConfig" ]; - config.envDefault.HTOPRC = configPath; - config.drv.buildPhase = '' - runHook preBuild - cp "$htopConfigPath" ${configPath} - runHook postBuild - ''; - - meta.maintainers = [ wlib.maintainers.alexlov ]; + config = { + package = lib.mkDefault pkgs.htop; + constructFiles.htopConfig = { + content = htopConfig; + relPath = "${config.binName}rc"; + }; + envDefault.HTOPRC = config.constructFiles.htopConfig.path; + meta.maintainers = [ wlib.maintainers.alexlov ]; + }; } diff --git a/wrapperModules/n/neovim/module.nix b/wrapperModules/n/neovim/module.nix index e106efe..a9b5847 100644 --- a/wrapperModules/n/neovim/module.nix +++ b/wrapperModules/n/neovim/module.nix @@ -38,6 +38,7 @@ let makeWrapper // { excluded_options.wrapperVariants = true; + excluded_options.wrapperFunction = true; exclude_wrapper = true; exclude_meta = true; } diff --git a/wrapperModules/n/neovim/symlinkScript.nix b/wrapperModules/n/neovim/symlinkScript.nix index 9616188..1db55cb 100644 --- a/wrapperModules/n/neovim/symlinkScript.nix +++ b/wrapperModules/n/neovim/symlinkScript.nix @@ -1,7 +1,7 @@ { config, wlib, - wrapper, + buildCommand, # other args from callPackage lib, lndir, @@ -145,7 +145,7 @@ finalDrv echo "propagated dependency cpath for plugins: $LUA_CPATH" '' + "\n" - + wrapper + + buildCommand + "\n" + lib.optionalString (!dont_link) '' diff --git a/wrapperModules/w/wezterm/module.nix b/wrapperModules/w/wezterm/module.nix index d22d4fc..a2c1447 100644 --- a/wrapperModules/w/wezterm/module.nix +++ b/wrapperModules/w/wezterm/module.nix @@ -49,51 +49,41 @@ This will help prevent indexing errors when querying nested values which may not exist. ''; }; - - config.drv.passAsFile = [ "nixLuaInit" ]; - config.drv.nixLuaInit = - let - withPackages = config.lua.withPackages or pkgs.luajit.withPackages; - genLuaCPathAbsStr = - config.lua.pkgs.luaLib.genLuaCPathAbsStr or pkgs.luajit.pkgs.luaLib.genLuaCPathAbsStr; - genLuaPathAbsStr = - config.lua.pkgs.luaLib.genLuaPathAbsStr or pkgs.luajit.pkgs.luaLib.genLuaPathAbsStr; - luaEnv = withPackages config.luaEnv; - in - /* lua */ '' - ${lib.optionalString ((config.luaEnv config.lua.pkgs) != [ ]) /* lua */ '' - package.path = package.path .. ";" .. ${builtins.toJSON (genLuaPathAbsStr luaEnv)} - package.cpath = package.cpath .. ";" .. ${builtins.toJSON (genLuaCPathAbsStr luaEnv)} - ''} - local wezterm = require 'wezterm' - package.preload["nix-info"] = function() - return setmetatable(${lib.generators.toLua { } config.luaInfo}, { - __call = function(self, default, ...) - if select('#', ...) == 0 then return default end - local tbl = self; - for _, key in ipairs({...}) do - if type(tbl) ~= "table" then return default end - tbl = tbl[key] + config.constructFiles.nixLuaInit = { + relPath = "${config.binName}-rc.lua"; + content = + let + withPackages = config.lua.withPackages or pkgs.luajit.withPackages; + genLuaCPathAbsStr = + config.lua.pkgs.luaLib.genLuaCPathAbsStr or pkgs.luajit.pkgs.luaLib.genLuaCPathAbsStr; + genLuaPathAbsStr = + config.lua.pkgs.luaLib.genLuaPathAbsStr or pkgs.luajit.pkgs.luaLib.genLuaPathAbsStr; + luaEnv = withPackages config.luaEnv; + in + /* lua */ '' + ${lib.optionalString ((config.luaEnv config.lua.pkgs) != [ ]) /* lua */ '' + package.path = package.path .. ";" .. ${builtins.toJSON (genLuaPathAbsStr luaEnv)} + package.cpath = package.cpath .. ";" .. ${builtins.toJSON (genLuaCPathAbsStr luaEnv)} + ''} + local wezterm = require 'wezterm' + package.preload["nix-info"] = function() + return setmetatable(${lib.generators.toLua { } config.luaInfo}, { + __call = function(self, default, ...) + if select('#', ...) == 0 then return default end + local tbl = self; + for _, key in ipairs({...}) do + if type(tbl) ~= "table" then return default end + tbl = tbl[key] + end + return tbl end - return tbl - end - }) - end - return dofile(${builtins.toJSON config."wezterm.lua".path}) - ''; - config.drv.buildPhase = '' - runHook preBuild - { [ -e "$nixLuaInitPath" ] && cat "$nixLuaInitPath" || echo "$nixLuaInit"; } > ${lib.escapeShellArg "${placeholder config.outputName}/${config.binName}-rc.lua"} - runHook postBuild - ''; - config.flagSeparator = "="; - config.flags = { - "--config-file" = { - data = "${placeholder config.outputName}/${config.binName}-rc.lua"; - esc-fn = lib.escapeShellArg; - }; + }) + end + return dofile(${builtins.toJSON config."wezterm.lua".path}) + ''; }; - + config.flagSeparator = "="; + config.flags."--config-file" = config.constructFiles.nixLuaInit.path; config.package = lib.mkDefault pkgs.wezterm; config.meta.maintainers = [ wlib.maintainers.birdee ]; diff --git a/wrapperModules/x/xplr/module.nix b/wrapperModules/x/xplr/module.nix index 8abab63..303f010 100644 --- a/wrapperModules/x/xplr/module.nix +++ b/wrapperModules/x/xplr/module.nix @@ -135,104 +135,114 @@ in ''; }; config.package = lib.mkDefault pkgs.xplr; - config.drv.passAsFile = [ - "nixLuaInit" - "nixLuaInfo" - ]; - config.drv.nixLuaInfo = /* lua */ '' - return setmetatable(${lib.generators.toLua { } config.luaInfo}, { - __call = function(self, default, ...) - if select('#', ...) == 0 then return default end - local tbl = self; - for _, key in ipairs({...}) do - if type(tbl) ~= "table" then return default end - tbl = tbl[key] - end - return tbl - end - }) - ''; - config.drv.nixLuaInit = - let - versionstr = - if hasFnl then - "(tset _G :version ${builtins.toJSON config.package.version})" - else - "version = ${builtins.toJSON config.package.version}"; - generatedConfig = lib.pipe initDal [ - (map ( - v: - let - lua = "(function(...) ${v.data} end)(${ - lib.generators.toLua { } v.opts - }, ${builtins.toJSON v.name})"; - fnl = ''((fn [...] ${v.data}) (lua "" ${builtins.toJSON "${lib.generators.toLua { } v.opts}"}) ${builtins.toJSON v.name})''; - in - if hasFnl then if v.type == "fnl" then fnl else ''(lua "" ${builtins.toJSON lua})'' else lua - )) - (builtins.concatStringsSep (if hasFnl then "\n" else ",\n")) - ]; + config.constructFiles = { + nixLuaInfo = { + relPath = "${config.binName}-plugins/${config.infopath}.lua"; + content = /* lua */ '' + return setmetatable(${lib.generators.toLua { } config.luaInfo}, { + __call = function(self, default, ...) + if select('#', ...) == 0 then return default end + local tbl = self; + for _, key in ipairs({...}) do + if type(tbl) ~= "table" then return default end + tbl = tbl[key] + end + return tbl + end + }) + ''; + }; + nixLuaInit = { + relPath = "${config.binName}-rc.lua"; + content = + let + versionstr = + if hasFnl then + "(tset _G :version ${builtins.toJSON config.package.version})" + else + "version = ${builtins.toJSON config.package.version}"; + generatedConfig = lib.pipe initDal [ + (map ( + v: + let + lua = "(function(...) ${v.data} end)(${ + lib.generators.toLua { } v.opts + }, ${builtins.toJSON v.name})"; + fnl = ''((fn [...] ${v.data}) (lua "" ${builtins.toJSON "${lib.generators.toLua { } v.opts}"}) ${builtins.toJSON v.name})''; + in + if hasFnl then if v.type == "fnl" then fnl else ''(lua "" ${builtins.toJSON lua})'' else lua + )) + (builtins.concatStringsSep (if hasFnl then "\n" else ",\n")) + ]; - nixInit = ( - if builtins.isString initDal then - initDal - else if hasFnl then - /* fennel */ '' - ((fn [hooks] - (fn add-hooks [res b] - (each [k vlist (pairs b)] - (local acc (. res k)) - (if (not= (type acc) :table) (tset res k vlist) - (not= (type vlist) :table) - (error (.. "expected a list of hooks at " (tostring k) - ", but got a " (type vlist))) - (let [n (length acc)] - (for [i 1 (length vlist)] (tset acc (+ n i) (. vlist i)))))) - res) + nixInit = ( + if builtins.isString initDal then + initDal + else if hasFnl then + /* fennel */ '' + ((fn [hooks] + (fn add-hooks [res b] + (each [k vlist (pairs b)] + (local acc (. res k)) + (if (not= (type acc) :table) (tset res k vlist) + (not= (type vlist) :table) + (error (.. "expected a list of hooks at " (tostring k) + ", but got a " (type vlist))) + (let [n (length acc)] + (for [i 1 (length vlist)] (tset acc (+ n i) (. vlist i)))))) + res) - (var result {}) - (for [i 1 (select "#" ((or unpack table.unpack) hooks))] - (local h (. hooks i)) - (when (= (type h) :table) (set result (add-hooks result h)))) - result) [ - ${generatedConfig} - ])'' - else - /* lua */ '' - return (function(hooks) - local function add_hooks(res, b) - for k, vlist in pairs(b) do - local acc = res[k] - if type(acc) ~= "table" then - res[k] = vlist - elseif type(vlist) ~= "table" then - error("expected a list of hooks at ".. tostring(k) ..", but got a " .. type(vlist)) - else - local n = #acc - for i = 1, #vlist do - acc[n + i] = vlist[i] + (var result {}) + (for [i 1 (select "#" ((or unpack table.unpack) hooks))] + (local h (. hooks i)) + (when (= (type h) :table) (set result (add-hooks result h)))) + result) [ + ${generatedConfig} + ])'' + else + /* lua */ '' + return (function(hooks) + local function add_hooks(res, b) + for k, vlist in pairs(b) do + local acc = res[k] + if type(acc) ~= "table" then + res[k] = vlist + elseif type(vlist) ~= "table" then + error("expected a list of hooks at ".. tostring(k) ..", but got a " .. type(vlist)) + else + local n = #acc + for i = 1, #vlist do + acc[n + i] = vlist[i] + end + end end + return res end - end - return res - end - local result = {} - for i = 1, select('#', (unpack or table.unpack)(hooks)) do - local h = hooks[i] - if type(h) == "table" then - result = add_hooks(result, h) - end - end - return result - end)({ - ${generatedConfig} - })'' - ); - in - '' - ${versionstr} - ${nixInit} - ''; + local result = {} + for i = 1, select('#', (unpack or table.unpack)(hooks)) do + local h = hooks[i] + if type(h) == "table" then + result = add_hooks(result, h) + end + end + return result + end)({ + ${generatedConfig} + })'' + ); + in + '' + ${versionstr} + ${nixInit} + ''; + builder = '' + mkdir -p "$(dirname "$2")" + { [ -e "$1" ] && cat "$1" || echo "$nixLuaInit"; }${ + if hasFnl then " | ${pkgs.luajitPackages.fennel}/bin/fennel --compile - " else " " + }> "$2" + ''; + }; + }; config.drv.buildPhase = let errORname = @@ -258,11 +268,6 @@ in in /* bash */ '' runHook preBuild - mkdir -p ${lib.escapeShellArg "${basePluginDir}"} - { [ -e "$nixLuaInitPath" ] && cat "$nixLuaInitPath" || echo "$nixLuaInit"; }${ - if hasFnl then " | ${pkgs.luajitPackages.fennel}/bin/fennel --compile - " else " " - }> ${lib.escapeShellArg "${placeholder config.outputName}/${config.binName}-rc.lua"} - { [ -e "$nixLuaInfoPath" ] && cat "$nixLuaInfoPath" || echo "$nixLuaInfo"; } > ${lib.escapeShellArg "${basePluginDir}/${config.infopath}.lua"} ${linkCommands} runHook postBuild ''; @@ -301,7 +306,7 @@ in name = "GENERATED_WRAPPER_LUA"; data = [ "-c" - "${placeholder config.outputName}/${config.binName}-rc.lua" + config.constructFiles.nixLuaInit.path ]; esc-fn = lib.escapeShellArg; } diff --git a/wrapperModules/y/yt-dlp/module.nix b/wrapperModules/y/yt-dlp/module.nix index cd6042b..01561c1 100644 --- a/wrapperModules/y/yt-dlp/module.nix +++ b/wrapperModules/y/yt-dlp/module.nix @@ -58,17 +58,10 @@ in config = { package = pkgs.yt-dlp; - flags = { - "--config-location" = "${placeholder config.outputName}/${config.binName}-settings.conf"; - }; - drv = { - renderedSettings = renderSettings config.settings; - passAsFile = [ "renderedSettings" ]; - buildPhase = '' - runHook preBuild - cp $renderedSettingsPath "${placeholder config.outputName}/${config.binName}-settings.conf" - runHook postBuild - ''; + flags."--config-location" = config.constructFiles.renderedSettings.path; + constructFiles.renderedSettings = { + relPath = "${config.binName}-settings.conf"; + content = renderSettings config.settings; }; meta.maintainers = [ wlib.maintainers.rachitvrma ]; }; diff --git a/wrapperModules/z/zathura/module.nix b/wrapperModules/z/zathura/module.nix index a484940..98cf60a 100644 --- a/wrapperModules/z/zathura/module.nix +++ b/wrapperModules/z/zathura/module.nix @@ -76,19 +76,11 @@ in }; flagSeparator = "="; wrapperVariants.zathura-sandbox = lib.mkIf pkgs.stdenv.hostPlatform.isLinux { }; - drv = { - renderedRc = lib.concatStringsSep "\n" ( - [ ] - ++ lib.mapAttrsToList formatLine config.options - ++ lib.mapAttrsToList formatMapLine config.mappings + constructFiles.renderedRc = { + relPath = "config/${config.binName}rc"; + content = lib.concatStringsSep "\n" ( + lib.mapAttrsToList formatLine config.options ++ lib.mapAttrsToList formatMapLine config.mappings ); - passAsFile = [ "renderedRc" ]; - buildPhase = '' - runHook preBuild - mkdir -p "${placeholder config.outputName}/config" - cp "$renderedRcPath" "${placeholder config.outputName}/config/${config.binName}rc" - runHook postBuild - ''; }; meta.maintainers = [ wlib.maintainers.rachitvrma ]; };