It's a first draft and considered incomplete. We're just committing this to save the effort.
12 KiB
title: User guide --- = User guide
While the 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?
Simply put, this is a declarative interface built on top of 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
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].
{ 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.
$ 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 wrapper-manager also has a way to make overridden packages by passing |
{ 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.
{ 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
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.
{ pkgs ? import <nixpkgs> { }, wrapperManager ? import <wrapper-manager-fds> { } }:
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
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.
{
# ...
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.
{ 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
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.<name>.basePackage
, wrappers.<name>.renames
, wrappers.<name>.overrideAttrs
, and wrappers.<name>.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 |
If you’re interested in migrating to this version, here’s a quicktable of individual differences that might interest you.
How arg0
is set per-wrapper
{ lib, pkgs, ... }:
{
wrappers.hello.basePackage = pkgs.hello;
}
{ lib, pkgs, ... }:
{
wrappers.hello.arg0 = lib.getExe' pkgs.hello "hello";
}
Renaming executables per-wrapper
{ 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.
{ lib, pkgs, ... }:
{
wrappers.hello.executableName = "hello-customized";
# You could also change the attrname.
wrappers.hello-customized.arg0 = "${pkgs.hello}/bin/hello";
}
Setting (and unsetting) environment variables per-wrapper
{ 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;
}
{ 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";
}
Adding PATH env values
{ config, lib, pkgs, ... }:
{
wrappers.hello.pathAdd = with pkgs; [
yt-dlp
gallery-dl
];
}
{ config, lib, pkgs, wrapperManagerLib, ... }:
{
wrappers.hello.pathAdd = wrapperManagerLib.getBin (with pkgs; [
yt-dlp
gallery-dl
]);
}