From d6b1a1a80e0683c6ce434a1278057a0f0077350f Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Thu, 19 Jun 2025 12:24:51 +0200
Subject: [PATCH 1/8] v2 API
---
.github/workflows/doc.yaml | 12 +-
default.nix | 45 +++--
docs/api.md | 7 +-
flake.lock | 22 +--
flake.nix | 94 +----------
modules/base.nix | 337 -------------------------------------
modules/build.nix | 43 -----
modules/common-wrapper.nix | 82 +++++++++
modules/default.nix | 8 -
modules/env-type.nix | 60 ++++++-
modules/many-wrappers.nix | 29 ++++
modules/wrapper-impl.nix | 183 ++++++++++++++++++++
modules/wrapper.nix | 58 +++++++
tests/gitconfig | 2 -
tests/multi.nix | 64 +++++++
tests/standalone.nix | 12 ++
tests/test-module.nix | 85 ----------
17 files changed, 529 insertions(+), 614 deletions(-)
delete mode 100644 modules/base.nix
delete mode 100644 modules/build.nix
create mode 100644 modules/common-wrapper.nix
delete mode 100644 modules/default.nix
create mode 100644 modules/many-wrappers.nix
create mode 100644 modules/wrapper-impl.nix
create mode 100644 modules/wrapper.nix
delete mode 100644 tests/gitconfig
create mode 100644 tests/multi.nix
create mode 100644 tests/standalone.nix
delete mode 100644 tests/test-module.nix
diff --git a/.github/workflows/doc.yaml b/.github/workflows/doc.yaml
index 66debfe..29ff7df 100644
--- a/.github/workflows/doc.yaml
+++ b/.github/workflows/doc.yaml
@@ -7,6 +7,10 @@ on:
paths:
- 'docs/**'
- 'modules/**'
+ pull_request:
+ paths:
+ - 'docs/**'
+ - 'modules/**'
workflow_dispatch:
permissions:
@@ -27,10 +31,10 @@ jobs:
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
extra_nix_config: |
- extra-experimental-features = nix-command flakes pipe-operators
+ extra-experimental-features = nix-command flakes
- name: 🏗️ Build
- run: nix build github:${{ github.repository }}#docs -L
+ run: nix build github:${{ github.repository }}/${{ github.sha }}#docs -L
- name: 📤 Upload artifacts
id: deployment
@@ -40,7 +44,7 @@ jobs:
deploy:
environment:
- name: github-pages
+ name: ${{ github.event_name == 'pull_request' && format('github-pages-pr-{0}', github.event.pull_request.number) || 'github-pages' }}
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
@@ -48,3 +52,5 @@ jobs:
- name: 🚀 Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+ with:
+ preview: ${{ github.event_name == 'pull_request' }}
diff --git a/default.nix b/default.nix
index e8d3720..87e9530 100644
--- a/default.nix
+++ b/default.nix
@@ -1,21 +1,36 @@
-{lib}: let
- eval = {
- pkgs,
- modules ? [],
- specialArgs ? {},
- }:
+let
+ eval =
+ {
+ pkgs,
+ lib ? pkgs.lib,
+ modules ? [ ],
+ specialArgs ? { },
+ }:
lib.evalModules {
- modules =
- [
- ./modules
- ]
- ++ modules;
- specialArgs = {inherit pkgs;} // specialArgs;
+ modules = [
+ ./modules/many-wrappers.nix
+ ] ++ modules;
+ specialArgs = {
+ inherit pkgs;
+ } // specialArgs;
};
-in {
- lib = {
+in
+{
+ lib = builtins.abort "wrapper-manager.lib is deprecated, please upgrade to the .v2 api: https://github.com/viperML/wrapper-manager/pull/26";
+
+ v2 = {
inherit eval;
__functor = _: eval;
- build = args: (eval args).config.build.toplevel;
+ wrapWith =
+ pkgs: module:
+ (pkgs.lib.evalModules {
+ modules = [
+ ./modules/wrapper.nix
+ module
+ ];
+ specialArgs = {
+ inherit pkgs;
+ };
+ }).config.wrapped;
};
}
diff --git a/docs/api.md b/docs/api.md
index fd3a92a..b1f982b 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -12,8 +12,13 @@ import { data } from "./wm.data.js";
import { RenderDocs } from "easy-nix-documentation";
+## Main API
-
+
+
+## Program configuration
+
+
## Outputs
diff --git a/flake.lock b/flake.lock
index 41abcde..5999137 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,26 +1,6 @@
{
"nodes": {
- "nixpkgs": {
- "locked": {
- "lastModified": 1743964447,
- "narHash": "sha256-nEo1t3Q0F+0jQ36HJfbJtiRU4OI+/0jX/iITURKe3EE=",
- "owner": "NixOS",
- "repo": "nixpkgs",
- "rev": "063dece00c5a77e4a0ea24e5e5a5bd75232806f8",
- "type": "github"
- },
- "original": {
- "owner": "NixOS",
- "ref": "nixos-unstable",
- "repo": "nixpkgs",
- "type": "github"
- }
- },
- "root": {
- "inputs": {
- "nixpkgs": "nixpkgs"
- }
- }
+ "root": {}
},
"root": "root",
"version": 7
diff --git a/flake.nix b/flake.nix
index d1f4618..31d093e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,95 +1,3 @@
{
- inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- };
-
- outputs =
- {
- self,
- nixpkgs,
- }:
- let
- forAllSystems =
- function:
- nixpkgs.lib.genAttrs
- [
- "x86_64-linux"
- "aarch64-linux"
- ]
- (
- system:
- function (
- import nixpkgs {
- inherit system;
- config.allowUnfree = true;
- }
- )
- );
- in
- (import ./default.nix {
- inherit (nixpkgs) lib;
- })
- // {
- formatter = forAllSystems (pkgs: pkgs.alejandra);
-
- devShells = forAllSystems (pkgs: {
- default = pkgs.mkShell {
- packages = [
- pkgs.nodejs
- ];
- };
- });
-
- packages = forAllSystems (pkgs: {
- optionsJSON =
- (pkgs.nixosOptionsDoc {
- options =
- (self.lib {
- inherit pkgs;
- modules = [ ];
- }).options;
- }).optionsJSON;
-
- docs =
- with pkgs;
- buildNpmPackage {
- name = "docs";
- src = ./docs;
- npmDeps = importNpmLock {
- npmRoot = ./docs;
- };
-
- inherit (importNpmLock) npmConfigHook;
- env.WRAPPER_MANAGER_OPTIONS_JSON = self.packages.${pkgs.system}.optionsJSON;
-
- buildPhase = ''
- runHook preBuild
-
- # Vitepress hangs when printing normally
- npm run build -- --base=/wrapper-manager/ 2>&1 | cat
-
- runHook postBuild
- '';
-
- installPhase = ''
- runHook preInstall
-
- mv .vitepress/dist $out
-
- runHook postInstall
- '';
- };
- });
-
- checks = forAllSystems (
- pkgs:
- (self.lib {
- inherit pkgs;
- modules = [ ./tests/test-module.nix ];
- specialArgs = {
- some-special-arg = "foo";
- };
- }).config.build.packages
- );
- };
+ outputs = _: import ./.;
}
diff --git a/modules/base.nix b/modules/base.nix
deleted file mode 100644
index c442110..0000000
--- a/modules/base.nix
+++ /dev/null
@@ -1,337 +0,0 @@
-{
- lib,
- pkgs,
- ...
-}:
-let
- inherit (lib)
- mkOption
- types
- ;
-
- envToWrapperArg =
- _:
- {
- name,
- force,
- value,
- }:
- let
- unsetArg =
- if !force then
- (lib.warn ''
- ${
- lib.showOption [
- "env"
- name
- "value"
- ]
- } is null (indicating unsetting the variable), but ${
- lib.showOption [
- "env"
- name
- "force"
- ]
- } is false. This option will have no effect
- '' [ ])
- else
- [
- "--unset"
- name
- ];
- setArg =
- let
- arg = if force then "--set" else "--set-default";
- in
- [
- arg
- name
- value
- ];
- in
- if value == null then unsetArg else setArg;
-
- wrapperOpts =
- { config, ... }:
- {
- imports = [
- (lib.mkAliasOptionModuleMD [ "flags" ] [ "prependFlags" ])
- ];
-
- options = {
- basePackage = mkOption {
- type = with types; package;
- description = ''
- Program to be wrapped.
- '';
- example = lib.literalExpression "pkgs.nix";
- };
-
- extraPackages = mkOption {
- type = with types; listOf package;
- description = ''
- Extra packages to also wrap.
- '';
- example = lib.literalExpression "[ pkgs.git-extras pkgs.delta ]";
- default = [ ];
- };
-
- env = mkOption {
- # This is a hack to display a helpful error message to the user about the changed api.
- # Should be changed to just `attrsOf submodule` at some point.
- type =
- let
- inherit (lib) any isStringLike showOption;
- actualType = types.submodule ./env-type.nix;
- forgedType = actualType // {
- # There's special handling if this value is present which makes merging treat this type as any other submodule type,
- # so we lie about there being no sub-modules so that our `check` and `merge` get called.
- getSubModules = null;
- check = v: isStringLike v || actualType.check v;
- merge =
- loc: defs:
- if any (def: isStringLike def.value) defs then
- throw ''
- ${showOption loc} has been changed to an attribute set.
- Instead of assigning value directly, use ${showOption (loc ++ [ "value" ])} = ;
- ''
- else
- (actualType.merge loc defs);
- };
- in
- types.attrsOf forgedType;
- description = ''
- Structured environment variables.
- '';
- default = { };
- example = {
- NIX_CONFIG.value = "allow-import-from-derivation = false";
- };
- };
-
- prependFlags = mkOption {
- type = with types; listOf (coercedTo anything (x: "${x}") str);
- description = ''
- Prepend a flag to the invocation of the program, **before** any arguments passed to the wrapped executable.
- '';
- default = [ ];
- example = lib.literalExpression ''
- [
- "--config" ./config.sh
- "--ascii" ./ascii
- ]
- '';
- };
-
- appendFlags = mkOption {
- type = with types; listOf (coercedTo anything (x: "${x}") str);
- description = ''
- Append a flag to the invocation of the program, **after** any arguments passed to the wrapped executable.
- '';
- default = [ ];
- example = lib.literalExpression ''
- [
- "--config" ./config.sh
- "--ascii" ./ascii
- ]
- '';
- };
-
- pathAdd = mkOption {
- type = with types; listOf package;
- description = ''
- Packages to append to PATH.
- '';
- default = [ ];
- example = lib.literalExpression "[ pkgs.starship ]";
- };
-
- extraWrapperFlags = mkOption {
- type = with types; separatedString " ";
- description = ''
- Raw flags passed to makeWrapper.
-
- See upstream documentation for make-wrapper.sh : https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
- '';
- default = "";
- example = "--argv0 foo --set BAR value";
- };
-
- wrapped = mkOption {
- type = with types; package;
- readOnly = true;
- description = ''
- (Output) Final wrapped package.
- '';
- };
-
- renames = mkOption {
- type = with types; attrsOf str;
- description = ''
- Map of renames FROM = TO. Renames every binary /bin/FROM to /bin/TO, adjusting other
- necessary files.
- '';
- default = { };
- example = {
- "nvim" = "custom-nvim";
- };
- };
-
- overrideAttrs = mkOption {
- type = with types; functionTo attrs;
- description = ''
- Function to override attributes from the final package.
- '';
- default = lib.id;
- example = ''
- old: {
- pname = "''${old.pname}-wrapped";
- }
- '';
- };
-
- postBuild = mkOption {
- type = with types; str;
- description = ''
- Extra fragment of bash to be run after the main wrapper-manager code.
- '';
- default = "";
- example = ''
- $out/bin/nvim -l ''${./check.lua}
- '';
- };
- };
-
- config = {
- wrapped =
- let
- mkWrapper =
- basePackage:
- let
- hasMan = builtins.any (builtins.hasAttr "man") ([ basePackage ] ++ config.extraPackages);
- in
- (
- (
- (pkgs.symlinkJoin {
- inherit (basePackage) name;
- paths = [ basePackage ] ++ config.extraPackages;
- nativeBuildInputs = [ pkgs.makeWrapper ];
- postBuild =
- let
- envArgs = lib.mapAttrsToList envToWrapperArg config.env;
- # Yes, the arguments are escaped later, yes, this is intended to "double escape",
- # so that they are escaped for wrapProgram and for the final binary too.
- prependFlagArgs = map (args: [
- "--add-flags"
- (lib.escapeShellArg args)
- ]) config.prependFlags;
- appendFlagArgs = map (args: [
- "--append-flags"
- (lib.escapeShellArg args)
- ]) config.appendFlags;
- pathArgs = map (p: [
- "--prefix"
- "PATH"
- ":"
- "${p}/bin"
- ]) config.pathAdd;
- allArgs = lib.flatten (envArgs ++ prependFlagArgs ++ appendFlagArgs ++ pathArgs);
- in
- ''
- for file in $out/bin/*; do
- echo "Wrapping $file"
- wrapProgram \
- $file \
- ${lib.escapeShellArgs allArgs} \
- ${config.extraWrapperFlags}
- done
-
- # Some derivations have nested symlinks here
- if [[ -d $out/share/applications && ! -w $out/share/applications ]]; then
- echo "Detected nested symlink, fixing"
- temp=$(mktemp -d)
- cp -v $out/share/applications/* $temp
- rm -vf $out/share/applications
- mkdir -pv $out/share/applications
- cp -v $temp/* $out/share/applications
- fi
-
- cd $out/bin
- for exe in *; do
-
- if false; then
- exit 2
- ${lib.concatStringsSep "\n" (
- lib.mapAttrsToList (name: value: ''
- elif [[ $exe == ${lib.escapeShellArg name} ]]; then
- newexe=${lib.escapeShellArg value}
- mv -vf $exe $newexe
- '') config.renames
- )}
- else
- newexe=$exe
- fi
-
- # Fix .desktop files
- # This list of fixes might not be exhaustive
- for file in $out/share/applications/*; do
- echo "Fixing file=$file for exe=$exe"
- set -x
- trap "set +x" ERR
- sed -i "s#/nix/store/.*/bin/$exe #$out/bin/$newexe #" "$file"
- sed -i -E "s#Exec=$exe([[:space:]]*)#Exec=$out/bin/$newexe\1#g" "$file"
- sed -i -E "s#TryExec=$exe([[:space:]]*)#TryExec=$out/bin/$newexe\1#g" "$file"
- set +x
- done
- done
-
- ${lib.optionalString hasMan ''
- mkdir -p ''${!outputMan}
- ${lib.concatMapStringsSep "\n" (
- # p: if lib.hasAttr "man" p then "${pkgs.xorg.lndir}/bin/lndir -silent ${p.man} $out" else "#"
- p:
- if p ? "man" then
- "${lib.getExe pkgs.xorg.lndir} -silent ${p.man} \${!outputMan}"
- else
- "echo \"No man output for ${lib.getName p}\""
- ) ([ basePackage ] ++ config.extraPackages)}
- ''}
-
- ${config.postBuild}
- '';
- passthru = (basePackage.passthru or { }) // {
- unwrapped = basePackage;
- };
- outputs = [
- "out"
- ] ++ (lib.optional hasMan "man");
- meta = basePackage.meta // {
- outputsToInstall = [
- "out"
- ] ++ (lib.optional hasMan "man");
- };
- })
- // {
- override = newAttrs: mkWrapper (basePackage.override newAttrs);
- }
- )
- );
- in
- mkWrapper config.basePackage;
- };
- };
-in
-{
- options = {
- wrappers = mkOption {
- type = with types; attrsOf (submodule wrapperOpts);
- default = { };
- description = ''
- Wrapper configuration. See the suboptions for configuration.
- '';
- };
- };
-
- config = {
- };
-}
diff --git a/modules/build.nix b/modules/build.nix
deleted file mode 100644
index e79fa12..0000000
--- a/modules/build.nix
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- lib,
- pkgs,
- config,
- ...
-}: let
- inherit
- (lib)
- mkOption
- types
- ;
-in {
- options = {
- build = {
- toplevel = mkOption {
- type = with types; package;
- readOnly = true;
- description = ''
- (Output) Derivation that merges all the wrappers into a single package.
- '';
- };
-
- packages = mkOption {
- type = with types; attrsOf package;
- readOnly = true;
- description = ''
- (Output) Attribute set of name=pkg. Useful for adding them to a flake's packages output.
- '';
- };
- };
- };
-
- config = {
- build = {
- toplevel = pkgs.buildEnv {
- name = "wrapper-manager";
- paths = builtins.attrValues config.build.packages;
- };
-
- packages = builtins.mapAttrs (_: value: value.wrapped) config.wrappers;
- };
- };
-}
diff --git a/modules/common-wrapper.nix b/modules/common-wrapper.nix
new file mode 100644
index 0000000..8df9f36
--- /dev/null
+++ b/modules/common-wrapper.nix
@@ -0,0 +1,82 @@
+{
+ lib,
+ config,
+ ...
+}:
+let
+ inherit (lib) mkOption types flatten;
+ inherit (builtins) attrValues;
+ flagsType = with types; listOf (coercedTo anything (x: "${x}") str);
+in
+{
+ options = {
+ wrapFlags = mkOption {
+ type = flagsType;
+ default = [ ];
+ description = "Flags passed to makeWrapper.";
+ };
+ appendFlags = mkOption {
+ type = flagsType;
+ default = [ ];
+ description = "Flags passed after any arguments to the wrapped program.";
+ };
+ prependFlags = mkOption {
+ type = flagsType;
+ default = [ ];
+ description = "Flags passed before any arguments to the wrapped program.";
+ };
+ env = mkOption {
+ type = with types; attrsOf (submodule ./env-type.nix);
+ default = { };
+ description = "FIXME env";
+ };
+ extraWrapperFlags = mkOption {
+ type = with types; separatedString " ";
+ description = ''
+ Raw flags passed to makeWrapper.
+
+ See upstream documentation for make-wrapper.sh : https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
+ '';
+ default = "";
+ example = "--argv0 foo --set BAR value";
+ };
+ pathAdd = mkOption {
+ type = with types; listOf package;
+ description = ''
+ Packages to append to PATH.
+ '';
+ default = [ ];
+ example = lib.literalExpression "[ pkgs.starship ]";
+ };
+ wrapperType = mkOption {
+ type = types.enum [
+ "shell"
+ "binary"
+ ];
+ default = "binary";
+ };
+ };
+
+ config = {
+ wrapFlags =
+ (flatten (
+ map (f: [
+ "--add-flag"
+ f
+ ]) config.prependFlags
+ ))
+ ++ (flatten (
+ map (f: [
+ "--append-flag"
+ f
+ ]) config.appendFlags
+ ))
+ ++ (lib.optionals (config.pathAdd != [ ]) [
+ "--prefix"
+ "PATH"
+ ":"
+ (lib.makeBinPath config.pathAdd)
+ ])
+ ++ (flatten (map (e: e.asFlags) (attrValues config.env)));
+ };
+}
diff --git a/modules/default.nix b/modules/default.nix
deleted file mode 100644
index c58d5a6..0000000
--- a/modules/default.nix
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- imports = [
- ./base.nix
- ./build.nix
-
- # ./git.nix
- ];
-}
diff --git a/modules/env-type.nix b/modules/env-type.nix
index 81eeaca..4d410ae 100644
--- a/modules/env-type.nix
+++ b/modules/env-type.nix
@@ -3,9 +3,11 @@
lib,
name,
...
-}: let
+}:
+let
inherit (lib) mkOption types;
-in {
+in
+{
options = {
name = mkOption {
type = types.str;
@@ -16,10 +18,16 @@ in {
};
value = mkOption {
- type = let
- inherit (types) coercedTo anything str nullOr;
- strLike = coercedTo anything (x: "${x}") str;
- in
+ type =
+ let
+ inherit (types)
+ coercedTo
+ anything
+ str
+ nullOr
+ ;
+ strLike = coercedTo anything (x: "${x}") str;
+ in
nullOr strLike;
description = ''
Value of the variable to be set.
@@ -43,5 +51,45 @@ in {
default = config.value == null;
defaultText = lib.literalMD "true if `value` is null, otherwise false";
};
+
+ asFlags = mkOption {
+ type = with types; listOf str;
+ internal = true;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ asFlags =
+ let
+ unsetArgs =
+ if !config.force then
+ (lib.warn ''
+ ${
+ lib.showOption [
+ "env"
+ config.name
+ "value"
+ ]
+ } is null (indicating unsetting the variable), but ${
+ lib.showOption [
+ "env"
+ config.name
+ "force"
+ ]
+ } is false. This option will have no effect
+ '' [ ])
+ else
+ [
+ "--unset"
+ config.name
+ ];
+ setArgs = [
+ (if config.force then "--set" else "--set-default")
+ config.name
+ config.value
+ ];
+ in
+ (if config.value == null then unsetArgs else setArgs);
};
}
diff --git a/modules/many-wrappers.nix b/modules/many-wrappers.nix
new file mode 100644
index 0000000..9da2f0e
--- /dev/null
+++ b/modules/many-wrappers.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+let
+ inherit (lib) mkOption types;
+in
+{
+ options = {
+ wrapperType = mkOption {
+ type = types.enum ["shell" "binary"];
+ default = "binary";
+ };
+
+ wrappers = mkOption {
+ type = types.attrsOf (
+ types.submoduleWith {
+ modules = [
+ ./wrapper.nix
+ {
+ wrapperType = lib.mkDefault config.wrapperType;
+ }
+ ];
+ specialArgs = {
+ inherit pkgs;
+ };
+ }
+ );
+ description = "Wrappers to create";
+ };
+ };
+}
diff --git a/modules/wrapper-impl.nix b/modules/wrapper-impl.nix
new file mode 100644
index 0000000..df3812d
--- /dev/null
+++ b/modules/wrapper-impl.nix
@@ -0,0 +1,183 @@
+{
+ lib,
+ pkgs,
+ config,
+ ...
+}:
+let
+ inherit (lib) mkOption types;
+ inherit (builtins) attrValues;
+
+ printAndRun = cmd: ''
+ echo ":: ${cmd}"
+ eval "${cmd}"
+ '';
+
+ hasMan = builtins.any (builtins.hasAttr "man") ([ config.basePackage ] ++ config.extraPackages);
+in
+{
+ options = {
+ wrapped = mkOption {
+ type = types.package;
+ readOnly = true;
+ description = "The wrapped package";
+ };
+
+ overrideAttrs = mkOption {
+ type = with types; functionTo attrs;
+ description = ''
+ Function to override attributes from the final package.
+ '';
+ default = lib.id;
+ defaultText = lib.literalExpression "lib.id";
+ example = lib.literalExpression ''
+ old: {
+ pname = "''${old.pname}-wrapped";
+ }
+ '';
+ };
+
+ postBuild = mkOption {
+ type = types.str;
+ default = "";
+ };
+ };
+
+ config = {
+ wrapped =
+ (
+ (pkgs.symlinkJoin {
+ # inherit (config.basePackage) name;
+ pname = lib.getName config.basePackage;
+ version = lib.getVersion config.basePackage;
+ __intentionallyOverridingVersion = true;
+ paths = [ config.basePackage ] ++ config.extraPackages;
+ nativeBuildInputs = [
+ pkgs.makeBinaryWrapper
+ pkgs.makeWrapper
+ ];
+ passthru = (config.basePackage.passthru or { }) // {
+ unwrapped = config.basePackage;
+ };
+ outputs = [
+ "out"
+ ] ++ (lib.optional hasMan "man");
+ meta = (config.basePackage.meta or { }) // {
+ outputsToInstall = [
+ "out"
+ ] ++ (lib.optional hasMan "man");
+ };
+ postBuild = ''
+ pushd "$out/bin" > /dev/null
+
+ echo "::: Wrapping explicit .programs ..."
+ already_wrapped=()
+ ${lib.concatMapStringsSep "\n" (
+ program:
+ let
+ name = program.name;
+ target = if program.target == null then "" else program.target;
+ wrapProgram = if program.wrapperType == "shell" then "wrapProgramShell" else "wrapProgramBinary";
+ makeWrapper = if program.wrapperType == "shell" then "makeShellWrapper" else "makeBinaryWrapper";
+ in
+ # bash
+ ''
+ already_wrapped+="${program.name}"
+
+ # If target is empty, use makeWrapper
+ # If target is not empty, but the same as name, use makeWrapper
+ # If target is not empty, is different from name, and doesn't exist, use wrapProgram
+ # If target is not empty, is different from name, and exists, error out
+
+ cmd=()
+ if [[ -z "${target}" ]]; then
+ cmd=(${wrapProgram} '${name}')
+ elif [[ -e "$out/bin/${name}" ]]; then
+ echo ":: Error: Target '${name}' already exists"
+ exit 1
+ else
+ cmd=(${makeWrapper} "$out/bin/${target}" '${name}')
+ fi
+
+ ${
+ if program.wrapFlags == [ ] && program.extraWrapperFlags == "" then
+ "echo ':: (${name} skipped: no wrapper configuration)'"
+ else
+ printAndRun "\${cmd[@]} ${lib.escapeShellArgs program.wrapFlags} ${program.extraWrapperFlags}"
+ }
+ ''
+ ) (attrValues config.programs)}
+
+ echo "::: Wrapping packages in out/bin ..."
+
+ for file in "$out/bin/"*; do
+ # check if $file is in $already_wrapped
+ prog="$(basename "$file")"
+ if [[ " ''${already_wrapped[@]} " =~ " $prog " ]]; then
+ continue
+ fi
+
+ ${
+ if config.wrapFlags == [ ] && config.extraWrapperFlags == "" then
+ "echo \":: ($prog skipped: no wrapper configuration)\""
+ else
+ printAndRun (
+ let
+ wrapProgram = if config.wrapperType == "shell" then "wrapProgramShell" else "wrapProgramBinary";
+ in
+ ''${wrapProgram} "$file" ${lib.escapeShellArgs config.wrapFlags} ${config.extraWrapperFlags}''
+ )
+ }
+ done
+ popd > /dev/null
+
+ ## Fix desktop files
+
+ # Some derivations have nested symlinks here
+ if [[ -d $out/share/applications && ! -w $out/share/applications ]]; then
+ echo "Detected nested symlink, fixing"
+ temp=$(mktemp -d)
+ cp -v $out/share/applications/* $temp
+ rm -vf $out/share/applications
+ mkdir -pv $out/share/applications
+ cp -v $temp/* $out/share/applications
+ fi
+
+ pushd "$out/bin" > /dev/null
+ for exe in *; do
+ # Fix .desktop files
+ # This list of fixes might not be exhaustive
+ for file in $out/share/applications/*; do
+ trap "set +x" ERR
+ set -x
+ sed -i "s#/nix/store/.*/bin/$exe #$out/bin/$exe #" "$file"
+ sed -i -E "s#Exec=$exe([[:space:]]*)#Exec=$out/bin/$exe\1#g" "$file"
+ sed -i -E "s#TryExec=$exe([[:space:]]*)#TryExec=$out/bin/$exe\1#g" "$file"
+ set +x
+ done
+ done
+ popd > /dev/null
+
+ ${lib.optionalString hasMan ''
+ mkdir -p ''${!outputMan}
+ ${lib.concatMapStringsSep "\n" (
+ p:
+ if p ? "man" then
+ "${lib.getExe pkgs.xorg.lndir} -silent ${p.man} \${!outputMan}"
+ else
+ "echo \"No man output for ${lib.getName p}\""
+ ) ([ config.basePackage ] ++ config.extraPackages)}
+ ''}
+
+ ${config.postBuild}
+ '';
+ }).overrideAttrs
+ (
+ final: prev: {
+ name = "${final.pname}-${final.version}";
+ }
+ )
+ ).overrideAttrs
+ config.overrideAttrs;
+ };
+}
diff --git a/modules/wrapper.nix b/modules/wrapper.nix
new file mode 100644
index 0000000..cc386cf
--- /dev/null
+++ b/modules/wrapper.nix
@@ -0,0 +1,58 @@
+{ pkgs, lib, config, ... }:
+let
+ inherit (lib) mkOption types;
+
+in
+{
+ imports = [
+ ./common-wrapper.nix
+ ./wrapper-impl.nix
+ ];
+
+ options = {
+ basePackage = mkOption {
+ type = with types; package;
+ description = "Program to be wrapped";
+ };
+
+ extraPackages = mkOption {
+ type = with types; listOf package;
+ default = [ ];
+ description = "Optional extra packages to also wrap";
+ };
+
+ programs = mkOption {
+ default = { };
+ description = "Programs to wrap";
+ type = types.attrsOf (
+ types.submoduleWith {
+ modules = [
+ ./common-wrapper.nix
+ (
+ { name, ... }:
+ {
+ options = {
+ name = mkOption {
+ type = types.str;
+ default = name;
+ description = "Name of the program";
+ };
+
+ target = mkOption {
+ type = with types; nullOr str;
+ default = null;
+ description = "Target of the program";
+ };
+ };
+
+ config = {
+ wrapperType = lib.mkDefault config.wrapperType;
+ };
+ }
+ )
+ ];
+ }
+ );
+ };
+ };
+}
diff --git a/tests/gitconfig b/tests/gitconfig
deleted file mode 100644
index df68d0a..0000000
--- a/tests/gitconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-[core]
- pager=delta
\ No newline at end of file
diff --git a/tests/multi.nix b/tests/multi.nix
new file mode 100644
index 0000000..f799429
--- /dev/null
+++ b/tests/multi.nix
@@ -0,0 +1,64 @@
+let
+ pkgs = import {
+ config.allowUnfree = true;
+ };
+ wrapper-manager = import ../.;
+in
+wrapper-manager.v2 {
+ inherit pkgs;
+ modules = [
+ {
+ wrapperType = "shell";
+
+ wrappers.discord = {
+ basePackage = pkgs.discord;
+
+ env.NIXOS_OZONE_WL.value = "1";
+ };
+
+ wrappers.hello = {
+ basePackage = pkgs.hello;
+ postBuild = "echo goodbye";
+ overrideAttrs = old: {
+ pname = "goodbye";
+ };
+ programs.hello = {
+ appendFlags = [
+ "-g"
+ "Goodbye World"
+ ];
+ };
+ };
+
+ wrappers.zellij = {
+ # Checks for __intentionallyOverridingVersion
+ basePackage = pkgs.zellij;
+ };
+
+ wrappers.hello-bad = {
+ basePackage = pkgs.hello;
+ flags = [
+ "-g"
+ "g"
+ ];
+ };
+
+ wrappers.neofetch = {
+ basePackage = pkgs.neofetch.override { x11Support = false; };
+ programs.guixfetch = {
+ target = "neofetch";
+ prependFlags = [
+ "--ascii_distro"
+ "guix"
+ ];
+ };
+ };
+
+ wrappers.git = {
+ basePackage = pkgs.git;
+ env.FOO.value = "BAR";
+ programs.scalar = { };
+ };
+ }
+ ];
+}
diff --git a/tests/standalone.nix b/tests/standalone.nix
new file mode 100644
index 0000000..af7d186
--- /dev/null
+++ b/tests/standalone.nix
@@ -0,0 +1,12 @@
+let
+ pkgs = import { };
+ wrapper-manager = import ../.;
+ wrap = wrapper-manager.v2.wrapWith pkgs;
+in
+wrap {
+ basePackage = pkgs.hello;
+ prependFlags = [
+ "-g"
+ "Goodbye"
+ ];
+}
diff --git a/tests/test-module.nix b/tests/test-module.nix
deleted file mode 100644
index db77f06..0000000
--- a/tests/test-module.nix
+++ /dev/null
@@ -1,85 +0,0 @@
-{
- pkgs,
- lib,
- some-special-arg,
- config,
- ...
-}:
-{
- wrappers.hello = {
- env.FOO.value = "foo";
- env.BAR.value = "bar";
- basePackage = pkgs.hello;
- flags = [
- "-g"
- some-special-arg
- ];
- };
-
- wrappers.neofetch = {
- basePackage = pkgs.neofetch.override { x11Support = false; };
- flags = [
- "--ascii_distro"
- "guix"
- ];
- renames = {
- "neofetch" = "neofetch2";
- };
- };
-
- wrappers.git = {
- basePackage = pkgs.git;
- extraPackages = [ pkgs.git-extras ];
- env.GIT_CONFIG_GLOBAL.value = pkgs.writeText "gitconfig" (lib.fileContents ./gitconfig);
- };
-
- wrappers.nushell = {
- basePackage = pkgs.nushell;
- pathAdd = [ pkgs.starship ];
- };
-
- wrappers.wezterm = {
- basePackage = pkgs.wezterm;
- renames = {
- "wezterm" = "wezterm2";
- };
- };
-
- wrappers.neovim = {
- basePackage = pkgs.neovim;
- renames = {
- "nvim" = "nvim2";
- };
- };
-
- wrappers.discord = {
- basePackage = pkgs.discord;
- flags = [
- "--disable-gpu"
- ];
- };
-
- wrappers.hello-wrapped = {
- basePackage = pkgs.hello;
- overrideAttrs = old: {
- name = "hello-wrapped";
- pname = "hello-wrapped-bad";
- };
- };
-
- wrappers.git-minimal-custom = {
- basePackage = config.wrappers.git.wrapped.override {
- # Same as gitMinimal
- withManual = false;
- osxkeychainSupport = false;
- pythonSupport = false;
- perlSupport = false;
- withpcre2 = false;
- };
- };
-
- # Test for meta.outputsToInstall
- wrappers.pkg-config = {
- basePackage = pkgs.pkg-config;
- };
-}
From 1d29cc21aab142dc4092167c7056578f87ff1f1c Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Thu, 19 Jun 2025 13:11:35 +0200
Subject: [PATCH 2/8] Refactor docs
---
.envrc | 1 -
.github/workflows/ci.yaml | 30 --------------------
.github/workflows/doc.yaml | 56 --------------------------------------
docs/.envrc | 1 +
docs/package.nix | 46 +++++++++++++++++++++++++++++++
docs/readme.md | 13 +++++----
docs/shell.nix | 10 +++++++
docs/wm.data.js | 23 +++++++---------
flake.nix | 9 +++++-
9 files changed, 83 insertions(+), 106 deletions(-)
delete mode 100644 .envrc
delete mode 100644 .github/workflows/ci.yaml
delete mode 100644 .github/workflows/doc.yaml
create mode 100644 docs/.envrc
create mode 100644 docs/package.nix
create mode 100644 docs/shell.nix
diff --git a/.envrc b/.envrc
deleted file mode 100644
index 3550a30..0000000
--- a/.envrc
+++ /dev/null
@@ -1 +0,0 @@
-use flake
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
deleted file mode 100644
index 01fd49d..0000000
--- a/.github/workflows/ci.yaml
+++ /dev/null
@@ -1,30 +0,0 @@
-name: ci
-
-on:
- push:
- pull_request:
- workflow_dispatch:
-
-jobs:
- deploy:
- runs-on: ubuntu-latest
-
- permissions:
- pages: write
- id-token: write
-
- steps:
- - name: Checkout
- uses: actions/checkout@v3
-
- - name: Install Nix
- uses: DeterminateSystems/nix-installer-action@main
-
- - name: Install Magic Nix Cache
- uses: DeterminateSystems/magic-nix-cache-action@main
-
- - name: Check
- run: nix flake check -L
-
- - name: Show
- run: nix flake show
diff --git a/.github/workflows/doc.yaml b/.github/workflows/doc.yaml
deleted file mode 100644
index 29ff7df..0000000
--- a/.github/workflows/doc.yaml
+++ /dev/null
@@ -1,56 +0,0 @@
-name: doc
-
-on:
- push:
- branches:
- - master
- paths:
- - 'docs/**'
- - 'modules/**'
- pull_request:
- paths:
- - 'docs/**'
- - 'modules/**'
- workflow_dispatch:
-
-permissions:
- id-token: write
- pages: write
- contents: write
-
-jobs:
- build:
- runs-on: ubuntu-latest
-
- environment:
- name: github-pages
-
- steps:
- - name: 📦 Install Nix
- uses: cachix/install-nix-action@master
- with:
- github_access_token: ${{ secrets.GITHUB_TOKEN }}
- extra_nix_config: |
- extra-experimental-features = nix-command flakes
-
- - name: 🏗️ Build
- run: nix build github:${{ github.repository }}/${{ github.sha }}#docs -L
-
- - name: 📤 Upload artifacts
- id: deployment
- uses: actions/upload-pages-artifact@v3
- with:
- path: ./result
-
- deploy:
- environment:
- name: ${{ github.event_name == 'pull_request' && format('github-pages-pr-{0}', github.event.pull_request.number) || 'github-pages' }}
- url: ${{ steps.deployment.outputs.page_url }}
- runs-on: ubuntu-latest
- needs: build
- steps:
- - name: 🚀 Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v4
- with:
- preview: ${{ github.event_name == 'pull_request' }}
diff --git a/docs/.envrc b/docs/.envrc
new file mode 100644
index 0000000..65326bb
--- /dev/null
+++ b/docs/.envrc
@@ -0,0 +1 @@
+use nix
\ No newline at end of file
diff --git a/docs/package.nix b/docs/package.nix
new file mode 100644
index 0000000..2c305d0
--- /dev/null
+++ b/docs/package.nix
@@ -0,0 +1,46 @@
+{
+ buildNpmPackage,
+ importNpmLock,
+ nixosOptionsDoc,
+ lib,
+ pkgs,
+}:
+let
+ options_json =
+ (nixosOptionsDoc {
+ options =
+ ((import ../.).v2 {
+ inherit pkgs;
+ modules = [ ];
+ }).options;
+ }).optionsJSON;
+in
+buildNpmPackage {
+ name = "wrapper-manager-docs";
+ src = lib.cleanSource ./.;
+ npmDeps = importNpmLock {
+ npmRoot = lib.cleanSource ./.;
+ };
+
+ inherit (importNpmLock) npmConfigHook;
+
+ env.WRAPPER_MANAGER_OPTIONS_JSON = options_json;
+ passthru = {inherit options_json;};
+
+ buildPhase = ''
+ runHook preBuild
+
+ # Vitepress hangs when printing normally
+ npm run build -- --base=/wrapper-manager/ 2>&1 | cat
+
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mv .vitepress/dist $out
+
+ runHook postInstall
+ '';
+}
diff --git a/docs/readme.md b/docs/readme.md
index 2b6f5d2..492cab7 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -14,11 +14,6 @@
-
```nix
{pkgs, ...}: {
@@ -228,3 +223,11 @@ https://github.com/viperML/wrapper-manager/issues
- 2023-08-12
- Added wrappers.name.renames option.
+
+
+
+
\ No newline at end of file
diff --git a/docs/shell.nix b/docs/shell.nix
new file mode 100644
index 0000000..b754185
--- /dev/null
+++ b/docs/shell.nix
@@ -0,0 +1,10 @@
+with import { };
+let
+ pkg = callPackage ./package.nix { };
+in
+mkShell {
+ packages = [
+ nodejs
+ ];
+ env.WRAPPER_MANAGER_OPTIONS_JSON = pkg.options_json;
+}
diff --git a/docs/wm.data.js b/docs/wm.data.js
index 9167367..2adfecd 100644
--- a/docs/wm.data.js
+++ b/docs/wm.data.js
@@ -2,25 +2,22 @@
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { loadOptions, stripNixStore } from "easy-nix-documentation/loader";
-import { env } from "node:process";
-
-const var_name = "WRAPPER_MANAGER_OPTIONS_JSON";
+import { env, exit } from "node:process";
export default {
async load() {
- const built = env[var_name];
- const settings = {
+ const options_json = env["WRAPPER_MANAGER_OPTIONS_JSON"];
+
+ if (options_json === undefined) {
+ console.error("WRAPPER_MANAGER_OPTIONS_JSON not set");
+ exit(1);
+ }
+
+ return await loadOptions(options_json, {
mapDeclarations: (declaration) => {
const relDecl = stripNixStore(declaration);
return `<wrapper-manager/${relDecl}>`;
},
- };
- if (built === undefined) {
- console.log(var_name, "not set, falling back with nix build");
- const __dirname = dirname(fileURLToPath(import.meta.url));
- return await loadOptions(`${__dirname}#optionsJSON`, settings);
- } else {
- return await loadOptions(built, settings);
- }
+ });
},
};
diff --git a/flake.nix b/flake.nix
index 31d093e..2e6ff1c 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,3 +1,10 @@
{
- outputs = _: import ./.;
+ outputs =
+ _:
+ let
+ toplevel = import ./default.nix;
+ in
+ {
+ lib = toplevel.v2;
+ };
}
From 70dd2efc7b021089a4d97e195cc3fa25e117035a Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Thu, 19 Jun 2025 14:22:29 +0200
Subject: [PATCH 3/8] Fix documentation
---
docs/default.nix | 1 +
modules/common-wrapper.nix | 22 +++++++++++----
modules/env-type.nix | 3 ++
modules/many-wrappers.nix | 57 ++++++++++++++++++++++++++++++++++++--
modules/wrapper-impl.nix | 9 ++++--
tests/multi.nix | 14 +++++-----
6 files changed, 88 insertions(+), 18 deletions(-)
create mode 100644 docs/default.nix
diff --git a/docs/default.nix b/docs/default.nix
new file mode 100644
index 0000000..c78dc4c
--- /dev/null
+++ b/docs/default.nix
@@ -0,0 +1 @@
+(import { }).callPackage ./package.nix { }
diff --git a/modules/common-wrapper.nix b/modules/common-wrapper.nix
index 8df9f36..391bd92 100644
--- a/modules/common-wrapper.nix
+++ b/modules/common-wrapper.nix
@@ -13,29 +13,37 @@ in
wrapFlags = mkOption {
type = flagsType;
default = [ ];
- description = "Flags passed to makeWrapper.";
+ description = "Structured flags passed to makeWrapper.";
+ example = [
+ "--argv0"
+ "myprog"
+ ];
};
appendFlags = mkOption {
type = flagsType;
default = [ ];
- description = "Flags passed after any arguments to the wrapped program.";
+ description = "Flags passed after any arguments to the wrapped program. Usually you want to use prependFlags instead.";
+ example = lib.literalExpression ''
+ ["--config-file" ./config.toml]
+ '';
};
prependFlags = mkOption {
type = flagsType;
default = [ ];
description = "Flags passed before any arguments to the wrapped program.";
+ example = lib.literalExpression ''
+ ["--config-file" ./config.toml]
+ '';
};
env = mkOption {
type = with types; attrsOf (submodule ./env-type.nix);
default = { };
- description = "FIXME env";
+ description = "Structured configuration for environment variables.";
};
extraWrapperFlags = mkOption {
type = with types; separatedString " ";
description = ''
- Raw flags passed to makeWrapper.
-
- See upstream documentation for make-wrapper.sh : https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/setup-hooks/make-wrapper.sh
+ Raw flags passed to makeWrapper. You may want to use wrapFlags instead.
'';
default = "";
example = "--argv0 foo --set BAR value";
@@ -49,11 +57,13 @@ in
example = lib.literalExpression "[ pkgs.starship ]";
};
wrapperType = mkOption {
+ description = "Whether to use a binary or a shell wrapper.";
type = types.enum [
"shell"
"binary"
];
default = "binary";
+ example = "shell";
};
};
diff --git a/modules/env-type.nix b/modules/env-type.nix
index 4d410ae..85954ab 100644
--- a/modules/env-type.nix
+++ b/modules/env-type.nix
@@ -15,6 +15,7 @@ in
Name of the variable.
'';
default = name;
+ example = "GIT_CONFIG";
};
value = mkOption {
@@ -36,6 +37,7 @@ in
Note that any environment variable will be escaped. For example, `value = "$HOME"`
will be converted to the literal `$HOME`, with its dollar sign.
'';
+ example = lib.literalExpression "./gitconfig";
};
force = mkOption {
@@ -50,6 +52,7 @@ in
'';
default = config.value == null;
defaultText = lib.literalMD "true if `value` is null, otherwise false";
+ example = true;
};
asFlags = mkOption {
diff --git a/modules/many-wrappers.nix b/modules/many-wrappers.nix
index 9da2f0e..1d04beb 100644
--- a/modules/many-wrappers.nix
+++ b/modules/many-wrappers.nix
@@ -1,12 +1,22 @@
-{ config, lib, pkgs, ... }:
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
let
inherit (lib) mkOption types;
in
{
options = {
wrapperType = mkOption {
- type = types.enum ["shell" "binary"];
+ description = "Which wrapper type to use by default for all wrappers.";
+ type = types.enum [
+ "shell"
+ "binary"
+ ];
default = "binary";
+ example = "shell";
};
wrappers = mkOption {
@@ -23,7 +33,48 @@ in
};
}
);
- description = "Wrappers to create";
+ description = "Wrappers to create.";
+ example = lib.literalExpression ''
+ {
+ hello = {
+ basePackage = pkgs.hello;
+ prependFlags = [
+ "-g"
+ "Hi"
+ ];
+ };
+ }
+ '';
+ };
+
+ build = {
+ toplevel = mkOption {
+ type = types.package;
+ readOnly = true;
+ description = ''
+ (Read-only) Package that merges all the wrappers into a single derivation.
+ You may want to use build.packages instead.
+ '';
+ };
+
+ packages = mkOption {
+ type = with types; attrsOf package;
+ readOnly = true;
+ description = ''
+ (Read-only) Attribute set of name=pkg, for every wrapper.
+ '';
+ };
+ };
+ };
+
+ config = {
+ build = {
+ toplevel = pkgs.buildEnv {
+ name = "wrapper-manager-bundle";
+ paths = builtins.attrValues config.build.packages;
+ };
+
+ packages = builtins.mapAttrs (_: value: value.wrapped) config.wrappers;
};
};
}
diff --git a/modules/wrapper-impl.nix b/modules/wrapper-impl.nix
index df3812d..0917271 100644
--- a/modules/wrapper-impl.nix
+++ b/modules/wrapper-impl.nix
@@ -20,7 +20,7 @@ in
wrapped = mkOption {
type = types.package;
readOnly = true;
- description = "The wrapped package";
+ description = "(Read-only) The final wrapped package";
};
overrideAttrs = mkOption {
@@ -32,7 +32,7 @@ in
defaultText = lib.literalExpression "lib.id";
example = lib.literalExpression ''
old: {
- pname = "''${old.pname}-wrapped";
+ pname = "''${pname}-with-settings";
}
'';
};
@@ -40,6 +40,11 @@ in
postBuild = mkOption {
type = types.str;
default = "";
+ description = "Raw commands to execute after the wrapping process has finished";
+ example = ''
+ echo "Running sanity check"
+ $out/bin/nvim '+q'
+ '';
};
};
diff --git a/tests/multi.nix b/tests/multi.nix
index f799429..162d4c7 100644
--- a/tests/multi.nix
+++ b/tests/multi.nix
@@ -35,13 +35,13 @@ wrapper-manager.v2 {
basePackage = pkgs.zellij;
};
- wrappers.hello-bad = {
- basePackage = pkgs.hello;
- flags = [
- "-g"
- "g"
- ];
- };
+ # wrappers.hello-bad = {
+ # basePackage = pkgs.hello;
+ # flags = [
+ # "-g"
+ # "g"
+ # ];
+ # };
wrappers.neofetch = {
basePackage = pkgs.neofetch.override { x11Support = false; };
From 351ed418ac618416e0f092bd75ca74548d21f83e Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Thu, 19 Jun 2025 14:25:19 +0200
Subject: [PATCH 4/8] Add ci workflow back
---
.github/workflows/ci.yaml | 46 +++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
create mode 100644 .github/workflows/ci.yaml
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 0000000..650cf4a
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,46 @@
+name: ci
+
+on:
+ push:
+ branches:
+ - master
+ workflow_dispatch:
+
+permissions:
+ id-token: write
+ pages: write
+ contents: write
+
+jobs:
+ docs-build:
+ runs-on: ubuntu-latest
+
+ environment:
+ name: github-pages
+
+ steps:
+ - name: 📦 Install Nix
+ uses: cachix/install-nix-action@master
+ with:
+ github_access_token: ${{ secrets.GITHUB_TOKEN }}
+ nix_path: nixpkgs=channel:nixos-unstable
+
+ - name: 🏗️ Build
+ run: nix build -f ./docs -L
+
+ - name: 📤 Upload artifacts
+ id: deployment
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: ./result
+
+ docs-deploy:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ needs: docs-build
+ steps:
+ - name: 🚀 Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
From 548aa2079e442e52d39423268deac7ab2304b9b3 Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Thu, 19 Jun 2025 15:39:58 +0200
Subject: [PATCH 5/8] Move back to .lib entrypoint
---
default.nix | 4 +-
docs/package.nix | 2 +-
docs/readme.md | 161 ++++++++++++++++++-------------------------
flake.nix | 9 +--
tests/multi.nix | 2 +-
tests/standalone.nix | 2 +-
6 files changed, 72 insertions(+), 108 deletions(-)
diff --git a/default.nix b/default.nix
index 87e9530..2f9e050 100644
--- a/default.nix
+++ b/default.nix
@@ -16,9 +16,7 @@ let
};
in
{
- lib = builtins.abort "wrapper-manager.lib is deprecated, please upgrade to the .v2 api: https://github.com/viperML/wrapper-manager/pull/26";
-
- v2 = {
+ lib = {
inherit eval;
__functor = _: eval;
wrapWith =
diff --git a/docs/package.nix b/docs/package.nix
index 2c305d0..1a1eef2 100644
--- a/docs/package.nix
+++ b/docs/package.nix
@@ -9,7 +9,7 @@ let
options_json =
(nixosOptionsDoc {
options =
- ((import ../.).v2 {
+ ((import ../.).lib {
inherit pkgs;
modules = [ ];
}).options;
diff --git a/docs/readme.md b/docs/readme.md
index 492cab7..af05e9f 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -22,7 +22,7 @@
# ~/.config/nushell is not neeeded!
wrappers.nushell = {
basePackage = pkgs.nushell;
- flags = [
+ prependFlags = [
"--env-config"
./env.nu
"--config"
@@ -74,117 +74,88 @@ around your applications, providing an easy-to use interface, and also getting
around some of their shortcomings.
-## **Module documentation**
+## **Documentation**
-https://viperml.github.io/wrapper-manager/docs/module
+https://viperml.github.io/wrapper-manager
-## **Installation/usage**
+## **Installation and usage**
-First, you need to instantiate wrapper-manager's lib. This can be done by pulling the WM flake, or by pulling the repo tarball directly.
-
-### Flake
+Wrapper-manager is a library for creating wrappers. What you do with the wrappers is up to you,
+you can use them to be installed with `nix-env -i`, add them to your NixOS config, to a devshell,
+etc.
```nix
-# flake.nix
-{
- inputs = {
- nixpkgs.url = "...";
-
- # Add the wrapper-manager flake
- wrapper-manager = {
- url = "github:viperML/wrapper-manager";
- # WM's nixpkgs is only used for tests, you can safely drop this if needed.
- inputs.nixpkgs.follows = "nixpkgs";
- };
+let
+ # Evaluate the module system
+
+ wm-eval = wrapper-manager.lib {
+ inherit pkgs;
+ modules = [
+ ./other-module.nix
+ {
+ wrappers.hello = {
+ basePackage = pkgs.hello;
+ prependFlags = ["-g" "Hi"];
+ };
+ }
+ ];
};
- outputs = {self, nixpkgs, wrapper-manager}: { ... };
-}
-```
+ # Extract one of the wrapped packages
+ myHello = wm-eval.config.wrappers.hello.wrapped;
+ #=> «derivation /nix/store/...»
-### Classic
+ # Extract all wrapped packages
+ allWrappers = wm-eval.config.build.packages;
+ #=> { hello = «derivation /nix/store/...»; }
-Wrapper-manager can be pulled in a classic (non-flake) setup for a dev-shell or NixOS configuration, like so:
+ # Add all the wrappers to systemPackages:
+ environment.systemPackages = [ ] ++ (builtins.attrValues wm-eval-config.build.packages);
+ # or using the bundle:
+ environment.systemPackages = [ wm-eval.config.build.toplevel ];
-```nix
-# shell.nix
-let
- pkgs = import {};
- # optionally, pin a commit instead of using master
- wrapper-manager = import (builtins.fetchTarball "https://github.com/viperML/wrapper-manager/archive/refs/heads/master.tar.gz") {
- inherit (pkgs) lib;
+
+ # Wrap a singular package
+ myGit = wrapper-manager.lib.wrapWith pkgs {
+ basePackage = pkgs.git;
+ env.GIT_CONFIG.value = ./gitconfig;
};
+ #=> «derivation /nix/store/...»
in
- mkShell { ..... }
+ ...
```
-```nix
-# configuration.nix
-{ config, pkgs, lib, ... }: let
- # optionally, pin a commit instead of using master
- wrapper-manager = import (builtins.fetchTarball "https://github.com/viperML/wrapper-manager/archive/refs/heads/master.tar.gz") {
- inherit (pkgs) lib;
- };
-in {
- .....
-}
-```
+### How do I get `wrapper-manager.lib` ?
+The main entrypoint is `wrapper-manager.lib`. To get it:
-### Evaluating
+### Flakes
-Now that you already have `wrapper-manager` in scope, you need to evaluate `wrapper-manager.lib`. The argument is an attrset with following elements:
+```nix
+{
+ inputs.wrapper-manager.url = "github.com:viperML/wrapper-manager";
-- `pkgs`: your nixpkgs instance used to bring `symlinkJoin` and `makeWrapper`, as well as passing it through the modules for convenience.
-- `modules`: a list of wrapper-manager modules. As with NixOS, a module can be passed as a path to a module or directly. A proper module is either an attrset, or a function to attrset.
-- `specialArgs` (optional): extra arguments passed to the module system.
+ outputs = {self, wrapper-manager}: let
+ # wrapper-manager.lib { ... }
+ in {};
+}
+```
-A convenience shorthand for `(wrapper-manager.lib {...}).config.build.toplevel` is available through: `wrapper-manager.lib.build {}`, which is probably what you want in 99% of the cases.
+### Npins
-```nix
-# This expression outputs a package, which collects all wrappers.
-# You can add it to:
-# - environment.systemPackages
-# - home.packages
-# - mkShell { packages = [...]; }
-# - etc
-
-(wrapper-manager.lib.build {
- inherit pkgs;
- modules = [
- ./my-module.nix
- {
- wrappers.foo = { ... };
- }
- ];
-})
-# => «derivation /nix/store/...»
+```
+$ npins add github viperML wrapper-manager
```
-For example, if you want to use wrapper-manager in the context of a dev-shell, you can instantiate it directly like so:
```nix
-# pkgs and wrapper-manager in scope, see previous steps
-# ...
-mkShell {
- packages = [
-
- (wrapper-manager.lib.build {
- inherit pkgs;
- modules = [{
- wrappers.stack = {
- basePackage = pkgs.stack;
- flags = [
- "--resolver"
- "lts"
- ];
- env.NO_COLOR.value = "1";
- };
- }];
- })
+let
+ sources = import ./npins;
+ wrapper-manager = import sources.wrapper-manager;
- ];
-}
+ # wrapper-manager.lib { ... }
+in
+ ...
```
@@ -201,6 +172,10 @@ https://github.com/viperML/wrapper-manager/issues
## Changelog
+- 2025-06-19
+ - Full rewrite
+ - `flags` has been removed in favor of `prependFlags`
+
- 2024-08-24
- Added `postBuild` option
@@ -224,10 +199,8 @@ https://github.com/viperML/wrapper-manager/issues
- 2023-08-12
- Added wrappers.name.renames option.
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/flake.nix b/flake.nix
index 2e6ff1c..31d093e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -1,10 +1,3 @@
{
- outputs =
- _:
- let
- toplevel = import ./default.nix;
- in
- {
- lib = toplevel.v2;
- };
+ outputs = _: import ./.;
}
diff --git a/tests/multi.nix b/tests/multi.nix
index 162d4c7..f8ea11d 100644
--- a/tests/multi.nix
+++ b/tests/multi.nix
@@ -4,7 +4,7 @@ let
};
wrapper-manager = import ../.;
in
-wrapper-manager.v2 {
+wrapper-manager.lib {
inherit pkgs;
modules = [
{
diff --git a/tests/standalone.nix b/tests/standalone.nix
index af7d186..a0e1f66 100644
--- a/tests/standalone.nix
+++ b/tests/standalone.nix
@@ -1,7 +1,7 @@
let
pkgs = import { };
wrapper-manager = import ../.;
- wrap = wrapper-manager.v2.wrapWith pkgs;
+ wrap = wrapper-manager.lib.wrapWith pkgs;
in
wrap {
basePackage = pkgs.hello;
From 4010339b5ca556737d2e5fdcbd6f8b19fdce2fba Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Thu, 19 Jun 2025 15:49:46 +0200
Subject: [PATCH 6/8] Add more examples
---
modules/common-wrapper.nix | 5 +++++
modules/wrapper.nix | 16 +++++++++++++++-
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/modules/common-wrapper.nix b/modules/common-wrapper.nix
index 391bd92..309accf 100644
--- a/modules/common-wrapper.nix
+++ b/modules/common-wrapper.nix
@@ -39,6 +39,11 @@ in
type = with types; attrsOf (submodule ./env-type.nix);
default = { };
description = "Structured configuration for environment variables.";
+ example = lib.literalExpression ''
+ {
+ GIT_CONFIG.value = ./gitconfig;
+ }
+ '';
};
extraWrapperFlags = mkOption {
type = with types; separatedString " ";
diff --git a/modules/wrapper.nix b/modules/wrapper.nix
index cc386cf..a5d5852 100644
--- a/modules/wrapper.nix
+++ b/modules/wrapper.nix
@@ -23,7 +23,21 @@ in
programs = mkOption {
default = { };
- description = "Programs to wrap";
+ description = "Wrap specific binaries with specific options. You may use it to skip wrapping some program.";
+ example = lib.literalExpression ''
+ {
+ supervim = {
+ target = "neovim";
+ };
+
+ git = {
+ env.GIT_CONFIG.value = ./gitconfig;
+ };
+
+ # Don't wrap scalar
+ scalar = {};
+ }
+ '';
type = types.attrsOf (
types.submoduleWith {
modules = [
From 3da75e331e1b9f03b1507d522b79c799d3561ba0 Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Fri, 20 Jun 2025 12:59:14 +0200
Subject: [PATCH 7/8] Deprecate .flags
---
modules/common-wrapper.nix | 20 +++++++++++++++++++-
tests/multi.nix | 1 +
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/modules/common-wrapper.nix b/modules/common-wrapper.nix
index 309accf..c16a6e0 100644
--- a/modules/common-wrapper.nix
+++ b/modules/common-wrapper.nix
@@ -1,6 +1,7 @@
{
lib,
config,
+ options,
...
}:
let
@@ -27,6 +28,16 @@ in
["--config-file" ./config.toml]
'';
};
+ # Poor's man mkRemovedOptionModule
+ # As we don't have assertions
+ flags = mkOption {
+ type = flagsType;
+ default = [ ];
+ description = "(Deprecated) Flags passed before any arguments to the wrapped program. Use prependFlags instead";
+ apply = throw "The option `${lib.showOption [ "flags" ]}' used in ${lib.showFiles options.flags.files} is deprecated. Use `${
+ lib.showOption [ "prependFlags" ]
+ }' instead.";
+ };
prependFlags = mkOption {
type = flagsType;
default = [ ];
@@ -39,7 +50,7 @@ in
type = with types; attrsOf (submodule ./env-type.nix);
default = { };
description = "Structured configuration for environment variables.";
- example = lib.literalExpression ''
+ example = lib.literalExpression ''
{
GIT_CONFIG.value = ./gitconfig;
}
@@ -80,6 +91,13 @@ in
f
]) config.prependFlags
))
+ # Force the eval of config.flags to trigger throw
+ ++ (flatten (
+ map (f: [
+ "--add-flag"
+ f
+ ]) config.flags
+ ))
++ (flatten (
map (f: [
"--append-flag"
diff --git a/tests/multi.nix b/tests/multi.nix
index f8ea11d..9e94d03 100644
--- a/tests/multi.nix
+++ b/tests/multi.nix
@@ -8,6 +8,7 @@ wrapper-manager.lib {
inherit pkgs;
modules = [
{
+ _file = ./multi.nix;
wrapperType = "shell";
wrappers.discord = {
From bb57881fb6fce082afd035d63d5441f31acacd10 Mon Sep 17 00:00:00 2001
From: Fernando Ayats
Date: Fri, 20 Jun 2025 13:02:53 +0200
Subject: [PATCH 8/8] Fix .flags deprecation
---
modules/common-wrapper.nix | 11 ++++++++---
tests/multi.nix | 17 ++++++++++-------
2 files changed, 18 insertions(+), 10 deletions(-)
diff --git a/modules/common-wrapper.nix b/modules/common-wrapper.nix
index c16a6e0..529b243 100644
--- a/modules/common-wrapper.nix
+++ b/modules/common-wrapper.nix
@@ -34,9 +34,14 @@ in
type = flagsType;
default = [ ];
description = "(Deprecated) Flags passed before any arguments to the wrapped program. Use prependFlags instead";
- apply = throw "The option `${lib.showOption [ "flags" ]}' used in ${lib.showFiles options.flags.files} is deprecated. Use `${
- lib.showOption [ "prependFlags" ]
- }' instead.";
+ apply =
+ flags:
+ if flags == [ ] then
+ [ ]
+ else
+ throw "The option `${lib.showOption [ "flags" ]}' used in ${lib.showFiles options.flags.files} is deprecated. Use `${
+ lib.showOption [ "prependFlags" ]
+ }' instead.";
};
prependFlags = mkOption {
type = flagsType;
diff --git a/tests/multi.nix b/tests/multi.nix
index 9e94d03..ec4d2c0 100644
--- a/tests/multi.nix
+++ b/tests/multi.nix
@@ -15,6 +15,9 @@ wrapper-manager.lib {
basePackage = pkgs.discord;
env.NIXOS_OZONE_WL.value = "1";
+ prependFlags = [
+ "--disable-gpu"
+ ];
};
wrappers.hello = {
@@ -36,13 +39,13 @@ wrapper-manager.lib {
basePackage = pkgs.zellij;
};
- # wrappers.hello-bad = {
- # basePackage = pkgs.hello;
- # flags = [
- # "-g"
- # "g"
- # ];
- # };
+ wrappers.hello-bad = {
+ basePackage = pkgs.hello;
+ flags = [
+ "-g"
+ "g"
+ ];
+ };
wrappers.neofetch = {
basePackage = pkgs.neofetch.override { x11Support = false; };