Added a module to configure browser based on the gecko engine, such as Firefox.
This module should provide similar functionality to the firefox module in home-manager. Some notable differences between the two include: * home-manager configures a single browser. This means that any configuration that cannot be done on a per-profile basis is shared between all profiles. This module configures a new copy of the browser for every profile, ensuring that *all* configuration can be on a per-profile basis. This might be seen as insanity in a regular distro, but in NixOS this is trivial to do and requires no extra storage space. * home-manager modifies files in the user's directory to configure things such as extensions and search engines. This module avoids that when possible by pushing configuration into policies and preferences at a browser level. This is much nicer for impermanence-based systems.
This commit is contained in:
parent
977595f7e8
commit
0f0c4c7727
10 changed files with 962 additions and 1 deletions
175
modules/home-manager/gecko-browser/gecko-lib/profiles.nix
Normal file
175
modules/home-manager/gecko-browser/gecko-lib/profiles.nix
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
{
|
||||
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: x: mapProduct f allLibs <| builtins.attrValues <| x;
|
||||
|
||||
allLibs = 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:
|
||||
builtins.head
|
||||
<| builtins.filter (x: profileSettings.${x}.isDefault)
|
||||
<| builtins.attrNames
|
||||
<| profileSettings;
|
||||
|
||||
process =
|
||||
{ languagePacks, ... }:
|
||||
let
|
||||
extractVersion =
|
||||
(x: if x == [ ] then info.base.version else builtins.head x)
|
||||
<| builtins.match "([^-]*)-.*"
|
||||
<| info.base.version;
|
||||
in
|
||||
{
|
||||
policies.ExtensionSettings =
|
||||
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 =
|
||||
(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.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 (
|
||||
_: v: processLevel "postprocess" <| processLevel "process" <| processLevel "preprocess" <| v
|
||||
) 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;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue