-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC] Declarative wrappers #85103
[RFC] Declarative wrappers #85103
Changes from 12 commits
242a7da
30f26fe
112882f
9893944
1e1464e
78cbe77
74a01b3
a18f521
72d6478
d0ed3a5
c0dab18
6283f15
b4d3633
ea9640a
8074b9c
f173b80
dda939a
8999768
2300445
32dd553
277ac54
0ed98f4
270ffc2
aea2b5a
e6f9600
f50caf8
2ca4dc7
8c74d6a
3a8e032
73bc870
2aacb90
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
{ lib | ||
, symlinkJoin | ||
, makeWrapper | ||
, extraPkgsByOverride ? [] | ||
}: | ||
|
||
pkgList: | ||
|
||
let | ||
wrapper = { | ||
extraPkgs ? [], | ||
extraMakeWrapperArgs ? "" | ||
}: | ||
let | ||
# Where we keep general knowledge about known to be used environmental variables | ||
encyclopedia = { | ||
# Here we write the separator string between values of every env var, the | ||
# default is ":" | ||
separators = { | ||
# XDG_DATA_DIRS = ":"; | ||
}; | ||
# If we want the wrapping to also include an environmental variable in | ||
# out, we list here for every env var what path to add to the wrapper's | ||
# args. You can put a list as a value as well. | ||
wrapOut = { | ||
XDG_DATA_DIRS = "$out/share"; | ||
}; | ||
}; | ||
# recursive function that goes deep through the dependency graph of a given | ||
# list of packages and creates a list of all buildInputs they all depend | ||
# on. The 2nd argument pkgsFound is used internally and it's expected to be | ||
# [] at the first call. | ||
getAllInputs = | ||
pkgs: | ||
pkgsFound: | ||
map ( | ||
pkg: | ||
if (builtins.typeOf pkg) == "set" then | ||
if builtins.hasAttr "buildInputs" pkg || builtins.hasAttr "propagatedBuildInputs" pkg then | ||
# builtins.trace "pkg is of type ${builtins.typeOf pkg} and it's ${builtins.toJSON pkg}, with inputs: ${builtins.toJSON (pkg.buildInputs ++ pkg.propagatedBuildInputs)}" (getAllInputs (pkg.buildInputs ++ pkg.propagatedBuildInputs) (pkgsFound ++ [ pkg ])) | ||
(getAllInputs (pkg.buildInputs ++ pkg.propagatedBuildInputs) (pkgsFound ++ [ pkg ])) | ||
else | ||
pkgsFound ++ [ pkg ] | ||
else | ||
# builtins.trace "pkg is not a set but a ${builtins.typeOf pkg} at ${builtins.toJSON pkg}, current pkgsFound is ${builtins.toJSON pkgsFound}" pkgsFound | ||
pkgsFound | ||
) pkgs; | ||
allPkgs = (lib.lists.flatten pkgList) ++ extraPkgsByOverride ++ extraPkgs; | ||
allInputs = lib.lists.unique (lib.lists.flatten (getAllInputs allPkgs [])); | ||
allInputs_ = builtins.trace "${builtins.toJSON allInputs}" allInputs; | ||
# filter out of all the inputs the packages with the propagateEnv attribute | ||
envPkgs = builtins.filter ( | ||
pkg: | ||
(builtins.hasAttr "propagateEnv" pkg) | ||
) allInputs; | ||
# Given a package, it's outputs and an envStr such as found in the values | ||
# of passthru's `propagateEnv`, it replaces all occurences of %<outname>% | ||
# from envStr according to the pkg.outputs | ||
replaceAllOutputs = { | ||
pkg, | ||
envStr, | ||
outputs, | ||
outname ? "out", | ||
}: | ||
let | ||
outname = builtins.elemAt outputs 0; | ||
in | ||
if (builtins.length outputs) == 0 then | ||
envStr | ||
else | ||
replaceAllOutputs { | ||
inherit pkg; | ||
outputs = lib.lists.subtractLists [outname] outputs; | ||
envStr = builtins.replaceStrings | ||
[ "%${outname}%" ] | ||
[ "${pkg.${outname}}" ] | ||
envStr; | ||
} | ||
; | ||
envInfo = map ( | ||
pkg: | ||
(lib.attrsets.mapAttrs ( | ||
name: | ||
value: | ||
replaceAllOutputs { | ||
inherit pkg; | ||
outputs = pkg.outputs; | ||
envStr = value; | ||
} | ||
) pkg.propagateEnv) | ||
) envPkgs; | ||
envInfo_ = builtins.trace "envInfo is ${(builtins.toJSON envInfo)}" envInfo; | ||
envInfoFolded = lib.attrsets.foldAttrs (n: a: [n] ++ a) [] envInfo; | ||
envInfoFolded_ = builtins.trace "envInfoFolded is ${(builtins.toJSON envInfoFolded)}" envInfoFolded; | ||
# Where we add stuff according to encyclopedia.wrapOut | ||
envInfoWithLocal = lib.attrsets.mapAttrs ( | ||
name: | ||
values: | ||
if builtins.hasAttr name encyclopedia.wrapOut then | ||
values ++ (lib.lists.flatten encyclopedia.wrapOut.${name}) | ||
else | ||
values | ||
) envInfoFolded; | ||
envInfoWithLocal_ = builtins.trace "envInfoWithLocal is ${(builtins.toJSON envInfoWithLocal)}" envInfoWithLocal; | ||
makeWrapperArgs = lib.attrsets.mapAttrsToList ( | ||
key: | ||
value: | ||
(let | ||
# TODO: make sure this works with any separator according to encyclopedia.separators | ||
sep = encyclopedia.separators.${key} or ":"; # default separator used for most wrappings | ||
in | ||
"--prefix ${key} ${sep} ${builtins.concatStringsSep sep value}" | ||
) | ||
) envInfoWithLocal; | ||
makeWrapperArgs_ = builtins.trace "makeWrapperArgs is ${(builtins.toJSON makeWrapperArgs)}" makeWrapperArgs; | ||
in | ||
symlinkJoin { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One disadvantage of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right.. Extra commands should be at |
||
name = "runtime-env"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps this should inherit the name of the parent derivation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not always there's a single parent derivation, but certainly for most purposes, this would be nicer. |
||
paths = pkgList; | ||
|
||
buildInputs = [ makeWrapper ]; | ||
postBuild = '' | ||
for i in $out/bin/*; do | ||
wrapProgram "$i" ${(builtins.concatStringsSep " " makeWrapperArgs_)} | ||
done | ||
''; | ||
}; | ||
in | ||
lib.makeOverridable wrapper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if you consider targetting wrappers in-scope? For example,
fwupd
needs to exclude EFI files from being wrapped;gjs
only wants to wrap installed tests…There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Am I to understand you are concerned that
wrapGeneric
can't be instructed to wrap only some executables and not others?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Ideally, it should be able to handle multiple disjoint wrappers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely we need to have that ability and it shouldn't be that hard to implement. I still don't have an idea though as to how this interface should look like. I'll update this PR or the RFC once I'll think about something, suggestions are welcome.