Wrapping same program twice for different purposes
Hey, firstly, thanks for creating this project!
Problem
I want to wrap a program, taskwarrior, with different versions, twice so that I have two executables that point to different configuration and have different software versions. However, the home-manager environment that is created has collisions as the two programs have similar files from the two different versions in PATH.
Example
wm-eval = inputs.wrapper-manager.lib {
pkgs = prev;
modules =
let
mkTaskWrapper =
{
pkg,
dataLocation,
binName,
}:
{
basePackage = pkg;
env.TASKRC.value = prev.writeTextFile {
name = "taskrc";
text = ''
data.location=${dataLocation}
news.version="${pkg.version}";
'';
};
# Same issue whether shell or binary
wrapperType = "shell";
postBuild = ''
# rm -r $out/share/
# rm $out/bin/.task-wrapped
mv $out/bin/task $out/bin/${binName}
'';
};
in
[
{
wrappers = {
taskw =
let
pkg = prev.taskwarrior3;
in
mkTaskWrapper {
inherit pkg;
dataLocation = "/some/location/1";
binName = "taskw";
};
taskh =
let
pkg = prev.taskwarrior2;
in
mkTaskWrapper {
inherit pkg;
dataLocation = "/some/location/2";
binName = "taskh";
};
};
}
];
};
The collision error:
error: builder for '/nix/store/8aaiwyi4fwrzfksshnyvrqcsa2rd7hxg-home-manager-path.drv' failed with exit code 25;
last 5 log lines:
> pkgs.buildEnv error: two given paths contain a conflicting subpath:
> `/nix/store/w87wfaa9lzbxkalpjqvrazgsrmmwzdqp-taskwarrior-3.4.1/bin/.task-wrapped' and
> `/nix/store/wcr8id8sf400p6fwwmxg04ay16m8sl51-taskwarrior-2.6.2/bin/.task-wrapped'
> hint: this may be caused by two different versions of the same package in buildEnv's `paths` parameter
> hint: `pkgs.nix-diff` can be used to compare derivations
For full logs, run:
nix log /nix/store/8aaiwyi4fwrzfksshnyvrqcsa2rd7hxg-home-manager-path.drv
Solution?
I can remove contents of $out/share/ in the postBuild step but how to avoid collision with the .task-wrapped file? I tried to use the programs option provided by wrapper-manager but did not understand how to make it work for this use case or even if it is a solution.
This can seemingly be solved by doing a writeShellApplication wrapper around the other executable and adding that to home.packages:
taskh = pkgs.writeShellApplication {
name = "taskh";
text = ''
${pkgs.taskh}/bin/taskh "$@"
'';
};
Could wrapper-manager support this use case more fluently?
I would say this is a problem that is out of the scope of wrapper-manager: we are trying to merge 2 programs in the same profile/buildEnv, that have collisions for files in $out/share, like manpages or bash completions. What is supposed to happen to those when you install both? Should your shell complete for task2 or task3? This is not well defined, and buildEnv properly crashes with this.
If your answer is "use the $out/share files from taskwarrior 3, and just put taskwarrior 2 in PATH", then you could do something like the following:
let
pkgs = import <nixpkgs> { };
wrapper-manager = import ../wrapper-manager;
wm-eval = wrapper-manager.lib {
inherit pkgs;
modules = [
(
{ config, ... }:
{
wrappers.taskw = {
basePackage = pkgs.taskwarrior3;
postBuild = ''
ln -vsfT ${config.wrappers.taskh.wrapped}/bin/task $out/bin/taskh
mv $out/bin/task $out/bin/taskw
'';
env.FOO.value = "BAR";
};
wrappers.taskh = {
basePackage = pkgs.taskwarrior2;
env.FOO.value = "BAR";
};
}
)
];
};
in
pkgs.buildEnv {
name = "test";
paths = [ wm-eval.config.wrappers.taskw.wrapped ];
}
Thanks for the info! I will have to test your solution.
I believe this use case to be something a user/layman who sees this repo might expect it to support, consequently, do you think some documentation about, e.g., your example could be added somewhere (as an "Advanced" topic)? I would wager that someone else runs into this same conflict and having it documented might help them (me) understand quicker the complexity of the problem.