hylonix/modules/home-manager/gecko-browser/gecko-lib/profiles.nix

190 lines
4.9 KiB
Nix
Raw Normal View History

{
lib,
pkgs,
sLib,
info,
geckoLib,
...
}@args:
let
# (a -> b -> c) -> [a] -> [b] -> [c]
mapProduct =
f: xs: ys:
builtins.concatMap (y: builtins.concatMap (x: f x y) xs) ys;
# (Lib -> Profile -> c) -> ProfileSettings -> [c]
mapLibAndProfile =
f:
sLib.compose [
(mapProduct f allLibs)
builtins.attrValues
];
allLibs = sLib.compose [
builtins.attrValues
(lib.filterAttrs (k: _: k != "profiles"))
] geckoLib;
allLibs' = allLibs ++ [ geckoLib.profiles ];
submodule =
{ config, name, ... }:
{
options = {
id = lib.mkOption {
type = lib.types.ints.unsigned;
default = 0;
description = "Profile ID";
};
name = lib.mkOption {
type = lib.types.str;
default = name;
description = "Profile name";
};
path = lib.mkOption {
type = lib.types.str;
default = name;
description = "Profile path";
};
isDefault = lib.mkOption {
type = lib.types.bool;
default = config.id == 0;
defaultText = "config.id == 0";
description = "Is profile the default?";
};
languagePacks = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [
"en-GB"
"de"
];
description = "The language packs to install.";
};
}
// builtins.foldl' (x: y: x // y.options) { } allLibs;
};
writeProfilesIni = configPath: profileSettings: {
name = "${configPath}/profiles.ini";
value.text = lib.generators.toINI { } (
lib.mapAttrs' (
_: v:
lib.nameValuePair "Profile${builtins.toString v.id}" {
Name = v.name;
Path = v.path;
IsRelative = 1;
Default = if v.isDefault then 1 else 0;
}
) profileSettings
// {
General = {
StartWithLastProfile = 1;
Version = 2;
};
}
);
};
in
{
options = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule submodule);
default = { };
description = "Sets browser settings on a per-profile basis.";
};
getDefaultProfileName =
profileSettings:
sLib.compose [
builtins.head
(builtins.filter (x: profileSettings.${x}.isDefault))
builtins.attrNames
] profileSettings;
process =
{ languagePacks, ... }:
let
extractVersion = sLib.compose [
(x: if x == [ ] then info.base.version else builtins.head x)
(builtins.match "([^-]*)-.*")
] info.base.version;
in
{
policies.ExtensionSettings = sLib.compose [
builtins.listToAttrs
(builtins.map (lang: {
name = "langpack-${lang}@firefox.mozilla.org";
value = {
installation_mode = "force_installed";
install_url = "https://releases.mozilla.org/pub/firefox/releases/${extractVersion}/linux-x86_64/xpi/${lang}.xpi";
};
}))
] languagePacks;
};
assertions = profiles: [
{
assertion = profiles != { };
message = "No profiles are defined.";
}
{
assertion = sLib.compose [
(x: x == 1)
builtins.length
(builtins.filter (x: profiles.${x}.isDefault))
builtins.attrNames
] profiles;
message = "One, and only one, profile must be marked as 'isDefault'. If you have not set this option on any profile, then one and only one profile must have id '0'.";
}
];
warnings = _: [ ];
evaluateAllProfiles =
profiles:
let
processLevel =
level: userConfig:
sLib.compose [
sLib.recursiveMergeAll
(x: [ userConfig ] ++ x)
(builtins.map (myLib: (myLib.${level} or (_: { })) userConfig))
] allLibs';
# Internal libraries can create their own configuration that needs to be merged
# into the user configuration (the user's takes priority). Generate that config.
finalConfig = builtins.mapAttrs (
_:
sLib.compose [
(processLevel "postprocess")
(processLevel "process")
(processLevel "preprocess")
]
) profiles;
in
{
assertions =
mapLibAndProfile (x: x.assertions or (_: [ ])) finalConfig
++ geckoLib.profiles.assertions finalConfig;
warnings =
mapLibAndProfile (x: x.warnings or (_: [ ])) finalConfig ++ geckoLib.profiles.warnings finalConfig;
profiles = lib.mapAttrs (_: v: {
policies = v.policies;
prefs = v.prefs;
files = builtins.concatMap (x: (x.files or (_: [ ])) v) allLibs';
extFiles = builtins.concatMap (x: (x.extFiles or (_: [ ])) v) allLibs';
}) finalConfig;
files = [
(writeProfilesIni info.configPath finalConfig)
]
++ mapLibAndProfile (x: x.files or (_: [ ])) finalConfig;
};
}