wrapper-manager-fds: init

It's a prototype for now, yeah. It'll be improved.
This commit is contained in:
Gabriel Arazas 2024-07-01 15:14:48 +08:00
commit a994a0cbac
13 changed files with 491 additions and 0 deletions

18
default.nix Normal file
View File

@ -0,0 +1,18 @@
# We just keep this attribute set for forward compatability in case it became
# required for users to pass something like the nixpkgs instance.
{ }:
{
nixosModules = rec {
default = wrapper-manager;
wrapper-manager = ./modules/env/nixos;
};
homeModules = rec {
default = wrapper-manager;
wrapper-manager = ./modules/env/home-manager;
};
wrapperManagerModules.default = ./modules/wrapper-manager;
wrapperManagerLib = ./lib;
}

60
lib/build-support.nix Normal file
View File

@ -0,0 +1,60 @@
# Unless you're a third-party module author wanting to integrate
# wrapper-manager to whatever bespoke configuration environment, there is
# almost no reason to use the following functions, really.
{ pkgs, lib, self }:
{
/* The build function for making simple and single executable
wrappers similar to nixpkgs builders for various ecosystems (for example,
`buildGoPackage` and `buildRustPackage`).
*/
mkWrapper = {
arg0,
executableName ? arg0,
makeWrapperArgs ? [ ],
nativeBuildInputs ? [ ],
passthru ? { },
}@args:
pkgs.runCommand "wrapper-manager-script-${arg0}" (
(builtins.removeAttrs args [ "executableName" "arg0" ])
// {
inherit makeWrapperArgs;
nativeBuildInputs = nativeBuildInputs ++ [ pkgs.makeWrapper ];
passthru = passthru // {
wrapperScript = { inherit arg0 executableName; };
};
}
) ''
mkdir -p $out/bin
makeWrapper ${arg0} "$out/bin/${executableName}" ''${makeWrapperArgs[@]}
'';
mkWrappedPackage = {
package,
executableName ? package.meta.mainProgram or package.pname,
postBuild ? "",
nativeBuildInputs ? [ ],
makeWrapperArgs ? [ ],
passthru ? { },
}@args:
pkgs.symlinkJoin (
(builtins.removeAttrs args [ "package" "executableName" ])
// {
name = "wrapper-manager-wrapped-package-${package.pname}";
paths = [ package ];
inherit makeWrapperArgs;
nativeBuildInputs = nativeBuildInputs ++ [ pkgs.makeWrapper ];
passthru = passthru // {
wrapperScript = { inherit executableName package; };
};
postBuild = ''
${postBuild}
wrapProgram "${lib.getExe' package executableName}" ''${makeWrapperArgs[@]}
'';
});
}

26
lib/default.nix Normal file
View File

@ -0,0 +1,26 @@
# The wrapper-manager library set. It should only require a nixpkgs instance to
# make initializing this set easier. This what makes it possible to be used as
# part of the module environments and as a standalone library.
#
# Since this library set is typically modularly set in nixpkgs module
# environments, we'll have to make sure it doesn't contain any functions that
# should return a nixpkgs module or anything of the sort. Basically, this
# should remain as a utility function that is usable outside of the nixpkgs
# module.
{ pkgs }:
pkgs.lib.makeExtensible
(self:
let
callLibs = file: import file { inherit (pkgs) lib; inherit pkgs self; };
in
{
build-support = callLibs ./build-support.nix;
env = callLibs ./env.nix;
utils = callLibs ./utils.nix;
inherit (self.build-support) mkWrapper mkWrappedPackage;
inherit (self.env) build eval;
inherit (self.utils) getBin getLibexec;
})

22
lib/env.nix Normal file
View File

@ -0,0 +1,22 @@
{ pkgs, lib, self }:
rec {
/* Given the attrset for evaluating a wrapper-manager module, return a
derivation containing the wrapper.
*/
build = args:
(eval args).config.build.toplevel;
/* Evaluate a wrapper-manager configuration. */
eval = {
pkgs,
modules ? [ ],
specialArgs ? { },
}:
pkgs.lib.evalModules {
modules = [ ../modules/wrapper-manager ] ++ modules;
specialArgs = specialArgs // {
modulesPath = builtins.toString ../modules/wrapper-manager;
};
};
}

15
lib/utils.nix Normal file
View File

@ -0,0 +1,15 @@
{ pkgs, lib, self }:
rec {
/*
Given a list of derivations, return a list of the store path with the `bin`
output (or at least with "/bin" in each of the paths).
*/
getBin = drvs:
builtins.map (v: lib.getBin v) drvs;
/*
*/
getLibexec = drvs:
builtins.map (v: "${v}/libexec") drvs;
}

View File

@ -0,0 +1,5 @@
= wrapper-manager modules
:toc:
This is the module set of the wrapper-manager module environment.
Just take note that we're following the runtime shell of nixpkgs which is GNU Bash as of 2024-06-30.

View File

@ -0,0 +1,112 @@
{ config, lib, ... }:
let
flagType = with lib.types; listOf (coercedTo anything (x: builtins.toString x) str);
in
{
options = {
prependArgs = lib.mkOption {
type = flagType;
description = ''
A list of arguments to be prepended to the user-given argument for the
wrapper script.
'';
default = [ ];
example = lib.literalExpression ''
[
"--config" ./config.conf
]
'';
};
appendArgs = lib.mkOption {
type = flagType;
description = ''
A list of arguments to be appended to the user-given argument for the
wrapper script.
'';
default = [ ];
example = lib.literalExpression ''
[
"--name" "doggo"
"--location" "Your mom's home"
]
'';
};
arg0 = lib.mkOption {
type = lib.types.str;
description = ''
The first argument of the wrapper script. This option is used when the
{option}`build.variant` is `executable`.
'';
example = lib.literalExpression "lib.getExe' pkgs.neofetch \"neofetch\"";
};
package = lib.mkOption {
type = lib.types.package;
description = ''
The package to be wrapped. This is used only when the
{option}`build.variant` is set to `package.`
'';
example = lib.literalExpression "pkgs.hello";
};
env = lib.mkOption {
type = with lib.types; attrsOf str;
description = ''
A set of environment variables to be declared in the wrapper script.
'';
default = { };
example = {
"FOO_TYPE" = "custom";
"FOO_LOG_STYLE" = "systemd";
};
};
executableName = lib.mkOption {
type = lib.types.nonEmptyStr;
description = ''
The name of the executable of the wrapper script.
This option behaves differently depending on {option}`build.variant`.
- When the build variant option is `executable`, it sets the name of the
wrapper script.
- When the build variant option is `package`, it depends on the name on
one of the executables from the given package.
'';
default =
if config.build.variant == "executable" then
lib.tail (lib.path.subpath.components config.arg0)
else
config.package.meta.mainProgram or config.package.pname;
example = "custom-name";
};
pathAdd = lib.mkOption {
type = with lib.types; listOf path;
description = ''
A list of paths to be added as part of the `PATH` environment variable.
'';
default = [ ];
example = lib.literalExpression ''
wrapperManagerLib.getBin (with pkgs; [
yt-dlp
gallery-dl
])
'';
};
preScript = lib.mkOption {
type = lib.types.lines;
description = ''
Script to run before the main executable.
'';
default = "";
example = lib.literalExpression ''
echo "HELLO WORLD!"
'';
};
};
}

View File

@ -0,0 +1,76 @@
{ config, lib, pkgs, wrapperManagerLib, ... }:
{
options.build = {
variant = lib.mkOption {
type = lib.types.enum [ "executable" "package" ];
description = ''
Tells how should wrapper-manager wrap the executable. The toplevel
derivation resulting from the module environment will vary depending on
the value.
- With `executable`, the wrapper is a lone executable wrapper script in
`$OUT/bin` subdirectory in the output.
- With `package`, wrapper-manager creates a wrapped package with all of
the output contents intact.
'';
default = "executable";
example = "package";
};
extraWrapperArgs = lib.mkOption {
type = with lib.types; listOf str;
description = ''
A list of extra arguments to be passed to the `makeWrapper` nixpkgs
setup hook function.
'';
example = [ "--inherit-argv0" ];
};
extraArgs = lib.mkOption {
type = with lib.types; attrsOf anything;
description = ''
A attrset of extra arguments to be passed to the
`wrapperManagerLib.mkWrapper` function. This will also be passed as
part of the derivation attribute into the resulting script from
{option}`preScript`.
'';
};
toplevel = lib.mkOption {
type = lib.types.package;
readOnly = true;
internal = true;
description = "A derivation containing the wrapper script.";
};
};
config.build = {
extraWrapperArgs = [
"--argv0" (config.executableName or config.arg0)
"--add-flags" config.prependFlags
"--append-flags" config.appendFlags
]
++ (lib.mapAttrsToList (n: v: "--set ${lib.escapeShellArg n} ${lib.escapeShellArg v}") config.env)
++ (builtins.map (v: "--prefix 'PATH' ':' ${lib.escapeShellArg v}") config.pathAdd)
++ (lib.optionals (config.preScript != "") (
let
preScript =
pkgs.runCommand "wrapper-script-prescript-${config.executableName}" config.build.extraArgs config.preScript;
in
"--run" preScript));
toplevel =
if config.build.variant == "executable" then
wrapperManagerLib.mkWrapper (config.build.extraArgs // {
inherit (config) arg0 executableName;
makeWrapperArgs = config.build.extraWrapperArgs;
})
else
wrapperManagerLib.mkWrappedPackage (config.build.extraArgs // {
inherit (config) package executableName;
makeWrapperArgs = config.build.extraWrapperArgs;
});
};
}

View File

@ -0,0 +1,7 @@
{
imports = [
./base.nix
./build.nix
./extra-args.nix
];
}

View File

@ -0,0 +1,7 @@
{ pkgs, ... }:
{
_module.args = {
wrapperManagerLib = import ../../lib { inherit pkgs; };
};
}

80
npins/default.nix Normal file
View File

@ -0,0 +1,80 @@
# Generated by npins. Do not modify; will be overwritten regularly
let
data = builtins.fromJSON (builtins.readFile ./sources.json);
version = data.version;
mkSource =
spec:
assert spec ? type;
let
path =
if spec.type == "Git" then
mkGitSource spec
else if spec.type == "GitRelease" then
mkGitSource spec
else if spec.type == "PyPi" then
mkPyPiSource spec
else if spec.type == "Channel" then
mkChannelSource spec
else
builtins.throw "Unknown source type ${spec.type}";
in
spec // { outPath = path; };
mkGitSource =
{
repository,
revision,
url ? null,
hash,
branch ? null,
...
}:
assert repository ? type;
# At the moment, either it is a plain git repository (which has an url), or it is a GitHub/GitLab repository
# In the latter case, there we will always be an url to the tarball
if url != null then
(builtins.fetchTarball {
inherit url;
sha256 = hash; # FIXME: check nix version & use SRI hashes
})
else
assert repository.type == "Git";
let
urlToName =
url: rev:
let
matched = builtins.match "^.*/([^/]*)(\\.git)?$" repository.url;
short = builtins.substring 0 7 rev;
appendShort = if (builtins.match "[a-f0-9]*" rev) != null then "-${short}" else "";
in
"${if matched == null then "source" else builtins.head matched}${appendShort}";
name = urlToName repository.url revision;
in
builtins.fetchGit {
url = repository.url;
rev = revision;
inherit name;
# hash = hash;
};
mkPyPiSource =
{ url, hash, ... }:
builtins.fetchurl {
inherit url;
sha256 = hash;
};
mkChannelSource =
{ url, hash, ... }:
builtins.fetchTarball {
inherit url;
sha256 = hash;
};
in
if version == 3 then
builtins.mapAttrs (_: mkSource) data.pins
else
throw "Unsupported format version ${toString version} in sources.json. Try running `npins upgrade`"

53
npins/sources.json Normal file
View File

@ -0,0 +1,53 @@
{
"pins": {
"home-manager-stable": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "nix-community",
"repo": "home-manager"
},
"branch": "release-24.05",
"revision": "a1fddf0967c33754271761d91a3d921772b30d0e",
"url": "https://github.com/nix-community/home-manager/archive/a1fddf0967c33754271761d91a3d921772b30d0e.tar.gz",
"hash": "1vvrrk14vrhb6drj3fy8snly0sf24x3402ykb9q5j1gy99vvqqq6"
},
"home-manager-unstable": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "nix-community",
"repo": "home-manager"
},
"branch": "master",
"revision": "36317d4d38887f7629876b0e43c8d9593c5cc48d",
"url": "https://github.com/nix-community/home-manager/archive/36317d4d38887f7629876b0e43c8d9593c5cc48d.tar.gz",
"hash": "1wrz1s78fhd8fvqsxkn10rzig7w8pxfbf1xff2rlxl7zr1k5dvx8"
},
"nixos-stable": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "NixOS",
"repo": "nixpkgs"
},
"branch": "nixos-24.05",
"revision": "89c49874fb15f4124bf71ca5f42a04f2ee5825fd",
"url": "https://github.com/NixOS/nixpkgs/archive/89c49874fb15f4124bf71ca5f42a04f2ee5825fd.tar.gz",
"hash": "07mr5xmdba3i5qw68kvxs0w1l70pv6pg636dqqxi6s91hiazv4n8"
},
"nixos-unstable": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "NixOS",
"repo": "nixpkgs"
},
"branch": "nixos-unstable",
"revision": "b2852eb9365c6de48ffb0dc2c9562591f652242a",
"url": "https://github.com/NixOS/nixpkgs/archive/b2852eb9365c6de48ffb0dc2c9562591f652242a.tar.gz",
"hash": "0zrl64ndfkkc4zhykrnc03b9ymp793zzmjqy3jfi9ckkni5vviqb"
}
},
"version": 3
}

10
shell.nix Normal file
View File

@ -0,0 +1,10 @@
{ pkgs ? import <nixpkgs> { } }:
pkgs.mkShell {
inputsFrom = with pkgs; [ nix ];
packages = with pkgs; [
npins
treefmt
nixpkgs-fmt
];
}