--- title: User guide --- = User guide While the link:./project-overview.adoc[project overview] should be enough to get you started, this document contain all of the information you may need to make full use of wrapper-manager. [#what-is-wrapper-manager] == What is wrapper-manager? Simply put, this is a declarative interface built on top of https://nixos.org/manual/nixpkgs/stable/#fun-makeWrapper[`makeWrapper` and company] plus some other integrations as we'll explore in this document. It is comparable to NixOS and home-manager in a way that it compiles into an operating system and a home environment respectively, wrapper-manager compiles the module environment into a package. Speaking of which, wrapper-manager is meant to be composed in larger-scoped environments such as NixOS and home-manager, mainly by including wrapper-manager packages in `environment.systemPackages` and `home.packages` but you could also make them as a standalone package. [#using-wrapper-manager] == Using wrapper-manager The module environment of wrapper-manager is the main interface of the project. In the following code, we'll define two wrappers around github:yt-dlp/yt-dlp[opts=repo]. .A package containing two wrapper scripts for yt-dlp [source, nix] ---- { lib, pkgs, ... }: { wrappers.yt-dlp-audio = { arg0 = lib.getExe' pkgs.yt-dlp "yt-dlp"; prependArgs = [ "--no-overwrite" "--extract-audio" "--format" "bestaudio" "--audio-format" "opus" "--output" "'%(album_artists.0,artists.0)s/%(album,playlist)s/%(track_number,playlist_index)d-%(track,title)s.%(ext)s'" "--download-archive" "archive" "--embed-thumbnail" "--add-metadata" ]; }; # You could also lessen the code above by passing `--config-location` to # yt-dlp and move them into a separate file. This is what wrapper-manager is # made for, after all. wrappers.yt-dlp-video = { arg0 = lib.getExe' pkgs.yt-dlp "yt-dlp"; prependArgs = [ "--config-location" ../../config/yt-dlp/video.conf ]; }; } ---- If we build the configuration, it should result in a derivation containing two executables. [source, shell] ---- $ ls ./result/bin yt-dlp-audio yt-dlp-video ---- By default, these wrappers are compiled with `makeBinaryWrapper`. You could make into a shell-based wrapper by changing `build.variant` value into `shell`. If you want to include the original yt-dlp package as part of the standalone package, just pass the package as part of `basePackages`. [CAUTION] ==== By evaluating the following code, you'll be losing metadata for the `yt-dlp` package (e.g., `version`, `meta`, `src`) since it is linked together through `symlinkJoin`. wrapper-manager also has a way to make overridden packages by passing `basePackages` with a bare package instead of a list of packages (e.g., `basePackages = pkgs.yt-dlp;` instead of `basePackages = [ pkgs.yt-dlp ];`). This method makes it suitable to pass `programs..package` module options typically found from NixOS and home-manager but at the cost of a rebuild and may interfere with the build steps already defined from its package authors. ==== [source, nix] ---- { lib, pkgs, ... }: { # ... basePackages = [ pkgs.yt-dlp ]; } ---- Another thing to keep in mind is wrapper-manager packages have the library set available as `wrapperManagerLib` module argument. This is mainly useful for setting values within the configuration. .Some uses of the wrapper-manager library set [source, nix] ---- { config, lib, pkgs, wrapperManagerLib, ... }: { # It is used for setting values in certain modules options. wrappers.yt-dlp-video = { xdg.dataDirs = wrapperManagerLib.getXdgDataDirs [ pkgs.emacs pkgs.neovim ]; pathAdd = wrapperManagerLib.getBin (with pkgs; [ yt-dlp gallery-dl ]); }; # Another nicety is to create a wraparound wrapper like in the following code # where we wrap tmux to be used with boxxy. wrappers.tmux = wrapperManagerLib.makeWraparound { arg0 = lib.getExe' pkgs.tmux "tmux"; under = lib.getExe' pkgs.boxxy "boxxy"; underFlags = [ "--rule" "~/.tmux.conf:~/.config/tmux/tmux.conf" ]; underSeparator = "--"; }; } ---- [#as-a-standalone-package] === As a standalone package wrapper-manager packages can be compiled as a standalone package to be included as part of the typical Nix operations (e.g., `makeShell`, as part of `packages` flake output, as part of `environment.systemPackages` in NixOS). That part is easy, just build it with wrapper-manager `build` function located at its library set. The following code listing shows an example of it including a wrapper-manager config as part of the devshell. Just remember that wrapper-manager configurations primarily ends as a package. [source, nix] ---- { pkgs ? import { }, wrapperManager ? import { } }: let inherit (pkgs) lib; gems = pkgs.bundlerEnv { name = "wrapper-manager-fds-gem-env"; ruby = pkgs.ruby_3_1; gemdir = ./.; }; asciidoctorWrapped = wrapperManager.lib.build { inherit pkgs; modules = lib.singleton { wrappers.asciidoctor = { arg0 = lib.getExe' gems "asciidoctor"; prependArgs = [ "-r" "asciidoctor-diagram" "-T" ./templates ]; }; }; }; in pkgs.mkShell { packages = with pkgs; [ asciidoctorWrapped treefmt gems gems.wrappedRuby ]; } ---- [#with-nixos-and-home-manager] === With NixOS and home-manager wrapper-manager also comes with integrations for NixOS and home-manager. You'll have to import the respective environment modules for them somewhere in your configuration. Here's an example of importing it into a NixOS and home-manager config with flakes. .Importing wrapper-manager integration modules [source, nix] ---- { # ... inputs.wrapper-manager.url = "github:foo-dogsquared/nix-wrapper-manager"; outputs = inputs: let inherit (inputs.nixpkgs) lib; inherit (lib) nixosSystem; inherit (inputs.home-manager.lib) homeManagerConfiguration; in { nixosConfigurations.desktop = nixosSystem { modules = [ inputs.wrapper-manager.nixosModules.wrapper-manager ]; }; homeConfigurations.user = homeConfigurations { modules = [ inputs.wrapper-manager.homeModules.wrapper-manager ]; }; }; } ---- For the most part, the integration modules are mostly the same. As an example, you can create wrappers through `wrapper-manager.packages` where it is expected to be an attribute set of wrapper-manager configurations. [source, nix] ---- { lib, config, ... }: { wrapper-manager.packages.writing.imports = [ ../configs/wrapper-manager/writing ]; wrapper-manager.packages.music-setup = { wrappers.beets = { arg0 = lib.getExe' pkgs.beets "beet"; prependArgs = [ "--config" ./config/beets/config.yml ]; }; }; wrapper-manager.packages.archive-setup = { lib, pkgs, ... }: { wrappers.gallery-dl = { arg0 = lib.getExe' pkgs.gallery-dl "gallery-dl"; prependArgs = [ ]; }; wrappers.yt-dlp-audio = { arg0 = lib.getExe' pkgs.yt-dlp "yt-dlp"; prependArgs = [ "--config-location" ./configs/yt-dlp/audio.conf ]; }; }; } ---- Aside from an easy way to create wrappers instead of manually invoking the building function from wrapper-manager, there's also another nicety with the integration module. The wrapper-manager configuration will have an additional module argument depending on the environment: `nixosConfig` for NixOS and `hmConfig` for home-manager. This is useful for dynamic and conditional configurations with the wider-scoped environment. [#differences-from-original-wrapper-manager] == Differences from original wrapper-manager Being a reimagining of wrapper-manager, there are some major differences between them. [NOTE] ==== The recorded differences are noted as of github:viperML/wrapper-manager[this commit, rev=c936f9203217e654a6074d206505c16432edbc70, opts=repo]. It may be revised that renders part of the following list to be outdated. Feel free to correct them in the source code repo. ==== The main difference is the way how the final output is built. In the original version, each of the specified wrappers under `wrappers` are individually built. In the reimagined version, these are consolidated into one build step since `makeWrapper` allows us to do so. As a side effect, there's no options that could require to be built individually such as `wrappers..basePackage`, `wrappers..renames`, `wrappers..overrideAttrs`, and `wrappers..extraPackages`. Another difference is the original version also handles some cases of fixing XDG desktop entries in the final output. In wrapper-manager-fds, this case is absent since its maintainer at the time (foo-dogsquared) deemed it "a pain in the ass" to handle especially that... * There are more use cases to handle such as multiple desktop entries for multiple reasons. * Most desktop metadata is pretty much usable even with the custom wrapper without cleaning them. * This need is less emphasized since wrapper-manager-fds also allows you to make XDG desktop entries in the config itself anyways. [NOTE] ==== A possible consideration is to make a build option toggle to handle this but it would involve "cleaning" the `Exec=` desktop entry directive to use the executable name instead of the full path. ==== If you're interested in migrating to this version, here's a quicktable of individual differences that might interest you. [discrete] === How `arg0` is set per-wrapper .In the original version... [source, nix] ---- { lib, pkgs, ... }: { wrappers.hello.basePackage = pkgs.hello; } ---- .And in wrapper-manager-fds. [source, nix] ---- { lib, pkgs, ... }: { wrappers.hello.arg0 = lib.getExe' pkgs.hello "hello"; } ---- [discrete] === Renaming executables per-wrapper .In the original version... [source, nix] ---- { lib, pkgs, ... }: { wrappers.hello.renames.hello = "hello-customized"; } ---- In wrapper-manager-fds, there's no renaming step as we already let the user name the executable. .And in wrapper-manager-fds. [source, nix] ---- { lib, pkgs, ... }: { wrappers.hello.executableName = "hello-customized"; # You could also change the attrname. wrappers.hello-customized.arg0 = "${pkgs.hello}/bin/hello"; } ---- [discrete] === Setting (and unsetting) environment variables per-wrapper .In the original version... [source, nix] ---- { lib, pkgs, ... }: { # The default action is to set the value if not yet set. wrappers.hello.env.CUSTOM_ENV_VAR.value = "HELLO"; # You can force it with the following. wrappers.hello.env.CUSTOM_ENV_VAR.force = true; # You can also unset it by setting the value to null. wrappers.hello.env.CUSTOM_ENV_VAR.value = lib.mkForce null; } ---- .And for wrapper-manager-fds. [source, nix] ---- { lib, pkgs, ... }: { # On the other hand, wrapper-manager-fds forces it by default. wrappers.hello.env.CUSTOM_ENV_VAR.value = "HELLO"; # But you can conditionally set it with... wrappers.hello.env.CUSTOM_ENV_VAR.action = "set-default"; # If you want to unset it, set the following code. wrappers.hello.env.CUSTOM_ENV_VAR.action = lib.mkForce "unset"; } ---- [discrete] === Adding PATH env values .In the original version... [source, nix] ---- { config, lib, pkgs, ... }: { wrappers.hello.pathAdd = with pkgs; [ yt-dlp gallery-dl ]; } ---- .And for wrapper-manager-fds. [source, nix] ---- { config, lib, pkgs, wrapperManagerLib, ... }: { wrappers.hello.pathAdd = wrapperManagerLib.getBin (with pkgs; [ yt-dlp gallery-dl ]); } ----