aboutsummaryrefslogtreecommitdiff
path: root/nix
diff options
context:
space:
mode:
authortilpner2020-06-15 09:53:06 +0200
committertilpner2020-06-15 09:53:06 +0200
commit367b0c114f38d5c332f5ee971ad13dd69e302dec (patch)
treeec0c5ee3e7e1f0a30517599e51bd0c8172635158 /nix
parent2992d92e6ce0d7c96ccded0747d8815d8cfed956 (diff)
downloadfirefox-profiles-367b0c114f38d5c332f5ee971ad13dd69e302dec.tar.gz
firefox-profiles-367b0c114f38d5c332f5ee971ad13dd69e302dec.tar.xz
firefox-profiles-367b0c114f38d5c332f5ee971ad13dd69e302dec.zip
WIP towards module based configuration
Diffstat (limited to 'nix')
-rw-r--r--nix/lib.nix307
-rw-r--r--nix/options.nix66
2 files changed, 234 insertions, 139 deletions
diff --git a/nix/lib.nix b/nix/lib.nix
index 179223b..0ca057d 100644
--- a/nix/lib.nix
+++ b/nix/lib.nix
@@ -1,147 +1,176 @@
{ pkgs, lib }:
with lib;
-rec {
- mozlz4 = pkgs.callPackage ./mozlz4.nix {};
-
- flattenAttrs = set:
- let recurse = k: v:
- if isAttrs v
- then mapAttrsToList (k': recurse "${k}.${k'}") v
- else nameValuePair k v;
- in listToAttrs (flatten (mapAttrsToList recurse set));
-
- mkValueString = v:
- if isInt v then toString v
- else if isString v then "\"${v}\""
- else if true == v then "true"
- else if false == v then "false"
- else abort "unsupported value type: ${builtins.typeOf v}";
-
- mkPrefs = settings: pkgs.writeText "prefs.js"
- ("// dummy line\n" +
- (lib.concatStringsSep "\n"
- (lib.mapAttrsToList (k: v: "pref(\"${k}\", ${mkValueString v}, locked);")
- (flattenAttrs settings))));
-
- toSearchConfig = settings: pkgs.runCommand "search.json.mozlz4" {} ''
- ${mozlz4.compress} < ${pkgs.writeText "search.json" (builtins.toJSON settings)} > $out
- '';
-
- profile = { preferences, search }: pkgs.runCommand "profile" {} ''
- mkdir $out
- ln -s ${toUserPrefs preferences} $out/user.js
- # ln -s ${toSearchConfig search} $out/search.json.mozlz4
- cp ${../search-with-qj.json.mozlz4} $out/search.json.mozlz4
- '';
-
- mkPolicies = policies: pkgs.writeText "policies.json" (builtins.toJSON {
- inherit policies;
- });
-
- mergeProfiles = profiles:
- let
- sanitise = args: {
- policies = args.policies or {};
- preferences = args.preferences or {};
+let
+ importProfiles = dir:
+ mapAttrs'
+ (name: type:
+ let
+ name' = builtins.replaceStrings [".nix"] [""] name;
+ in if type == "regular" then
+ nameValuePair name' (import (dir + ("/" + name)))
+ else if type == "directory" then
+ nameValuePair name' (pkgs.callPackage (dir + ("/" + name)) {})
+ else
+ builtins.throw "Unexpected file type: ${type}")
+ (builtins.readDir dir);
+
+ self = rec {
+ mozlz4 = pkgs.callPackage ./mozlz4.nix {};
+ directory = pkgs.callPackage ./directory.nix {};
+
+ profileList = attrValues (directory.pathDirectory ../profiles);
+
+ flattenAttrs = set:
+ let recurse = k: v:
+ if isAttrs v
+ then mapAttrsToList (k': recurse "${k}.${k'}") v
+ else nameValuePair k v;
+ in listToAttrs (flatten (mapAttrsToList recurse set));
+
+ mkValueString = v:
+ if isInt v then toString v
+ else if isString v then "\"${v}\""
+ else if true == v then "true"
+ else if false == v then "false"
+ else abort "unsupported value type: ${builtins.typeOf v}";
+
+ mkPrefs = settings: pkgs.writeText "prefs.js"
+ ("// dummy line\n" +
+ (lib.concatStringsSep "\n"
+ (lib.mapAttrsToList (k: v: "pref(\"${k}\", ${mkValueString v}, locked);")
+ (flattenAttrs settings))));
+
+ toSearchConfig = settings: pkgs.runCommand "search.json.mozlz4" {} ''
+ ${mozlz4.compress} < ${pkgs.writeText "search.json" (builtins.toJSON settings)} > $out
+ '';
+
+ profile = { preferences, search }: pkgs.runCommand "profile" {} ''
+ mkdir $out
+ ln -s ${toUserPrefs preferences} $out/user.js
+ # ln -s ${toSearchConfig search} $out/search.json.mozlz4
+ cp ${../search-with-qj.json.mozlz4} $out/search.json.mozlz4
+ '';
+
+ mkPolicies = policies: pkgs.writeText "policies.json" (builtins.toJSON {
+ inherit policies;
+ });
+
+ optionsModule = import ./options.nix;
+ eval = root: evalModules {
+ modules = profileList ++ [
+ optionsModule
+ root
+ ];
+
+ specialArgs = {
+ ff = self;
};
- sanitised = map sanitise profiles;
- final = lib.foldl lib.recursiveUpdate {} sanitised;
- in final;
-
- patchOmniJa = src: script: pkgs.runCommand "omni.ja" { } ''
- ${pkgs.unzip}/bin/unzip -q ${src}
-
- ${script}
-
- ${pkgs.zip}/bin/zip -qr9XD $out .
- '';
-
- bundle = { policies ? {}, preferences ? {}, patchOmniJaCommand ? "" }:
- let
- firefox = pkgs.firefox-unwrapped;
- policies' = mkPolicies policies;
- preferences' = mkPrefs preferences;
- patchedOmniJa = patchOmniJa "${firefox}/lib/firefox/browser/omni.ja" patchOmniJaCommand;
- patched = pkgs.runCommand "firefox-bundle" {
- nativeBuildInputs = [ pkgs.nix ];
- disallowedReferences = [ firefox ];
- } ''
- cp -r ${firefox} $out
- chmod -R +w $out
- # correct argv[0], which is used to locate distribution and defaults
- substituteInPlace $out/bin/firefox \
- --replace ${firefox} $out
-
- mkdir $out/lib/firefox/distribution
- cp ${policies'} $out/lib/firefox/distribution/policies.json
- cp ${preferences'} $out/lib/firefox/defaults/pref/99-custom.js
- cp ${patchedOmniJa} $out/lib/firefox/browser/omni.ja
+ };
+
+ docs = options:
+ let
+ optionsDoc = pkgs.nixosOptionsDoc { inherit options; };
+ in pkgs.runCommand "manual.html" { nativeBuildInputs = [ pkgs.asciidoctor ]; } ''
+ asciidoctor \
+ -o $out \
+ ${builtins.toFile "manual.asciidoc" optionsDoc.optionsAsciiDoc}
'';
- wrapped = (pkgs.wrapFirefox patched {
- browserName = "firefox";
- version = "custom";
- }) // { inherit policies preferences; };
- in wrapped;
-
- # This attempts to provide a start for deploying Nix-configured profiles to
- # systems which do not have Nix installed, and where /nix/store is undesired.
- # It does this by bundling all referenced store items into $out, and rewriting
- # references to those store items.
- export = { selfPath, policies ? {}, preferences ? {} }: pkgs.stdenv.mkDerivation rec {
- name = "firefox-profile-export";
- nativeBuildInputs = [ pkgs.jq ];
-
- allowedRequisites = [];
-
- buildCommand =
+
+ patchOmniJa = src: script: pkgs.runCommand "omni.ja" { } ''
+ ${pkgs.unzip}/bin/unzip -q ${src}
+
+ ${script}
+
+ ${pkgs.zip}/bin/zip -qr9XD $out .
+ '';
+
+ bundle = { policies ? {}, preferences ? {}, patchOmniJaCommand ? "" }:
let
- policyFile = mkPolicies policies;
- prefsFile = mkPrefs preferences;
-
- closure = pkgs.closureInfo {
- rootPaths = [
- policyFile prefsFile
- ];
- };
- in ''
- mkdir $out $out/store
-
- storePaths=$(cat ${closure}/store-paths)
- for p in $storePaths; do
- cp -a "$p" $out/store/"$(basename "$p" | sed -e 's|\([a-z0-9]\{32\}\)-||')"
- done
-
- mv $out/store/prefs.js $out/
- jq < $out/store/policies.json > $out/policies.json
-
- find $out -type f -print0 |
- xargs -0I{} -- sed -i -e "s|$NIX_STORE/\\([a-z0-9]\{32\}\\)-|${selfPath}/store/|g" "{}"
+ firefox = pkgs.firefox-unwrapped;
+ policies' = mkPolicies policies;
+ preferences' = mkPrefs preferences;
+ patchedOmniJa = patchOmniJa "${firefox}/lib/firefox/browser/omni.ja" patchOmniJaCommand;
+ patched = pkgs.runCommand "firefox-bundle" {
+ nativeBuildInputs = [ pkgs.nix ];
+ disallowedReferences = [ firefox ];
+ } ''
+ cp -r ${firefox} $out
+ chmod -R +w $out
+ # correct argv[0], which is used to locate distribution and defaults
+ substituteInPlace $out/bin/firefox \
+ --replace ${firefox} $out
+
+ mkdir $out/lib/firefox/distribution
+ cp ${policies'} $out/lib/firefox/distribution/policies.json
+ cp ${preferences'} $out/lib/firefox/defaults/pref/99-custom.js
+ cp ${patchedOmniJa} $out/lib/firefox/browser/omni.ja
+ '';
+ wrapped = (pkgs.wrapFirefox patched {
+ browserName = "firefox";
+ version = "custom";
+ }) // { inherit policies preferences; };
+ in wrapped;
+
+ # This attempts to provide a start for deploying Nix-configured profiles to
+ # systems which do not have Nix installed, and where /nix/store is undesired.
+ # It does this by bundling all referenced store items into $out, and rewriting
+ # references to those store items.
+ export = { selfPath, policies ? {}, preferences ? {} }: pkgs.stdenv.mkDerivation rec {
+ name = "firefox-profile-export";
+ nativeBuildInputs = [ pkgs.jq ];
+
+ allowedRequisites = [];
+
+ buildCommand =
+ let
+ policyFile = mkPolicies policies;
+ prefsFile = mkPrefs preferences;
+
+ closure = pkgs.closureInfo {
+ rootPaths = [
+ policyFile prefsFile
+ ];
+ };
+ in ''
+ mkdir $out $out/store
+
+ storePaths=$(cat ${closure}/store-paths)
+ for p in $storePaths; do
+ cp -a "$p" $out/store/"$(basename "$p" | sed -e 's|\([a-z0-9]\{32\}\)-||')"
+ done
+
+ mv $out/store/prefs.js $out/
+ jq < $out/store/policies.json > $out/policies.json
+
+ find $out -type f -print0 |
+ xargs -0I{} -- sed -i -e "s|$NIX_STORE/\\([a-z0-9]\{32\}\\)-|${selfPath}/store/|g" "{}"
+ '';
+ };
+
+ launcher = firefox: pkgs.writeShellScriptBin "firefox" ''
+ # FF doesn't accept ro profiles, tries to create lockfile
+ TMP_PROFILE="$(mktemp -d)"
+ echo "$TMP_PROFILE"
+
+ function finish() {
+ echo deleting profile
+ # rm -rv "$TMP_PROFILE"
+ }
+ trap finish EXIT
+ # cp -r ''${profile} "$TMP_PROFILE"
+ chmod u+rwx -R "$TMP_PROFILE"
+
+ export MOZ_LOG=nsHttp:1
+ export MOZ_LOG_FILE=ff
+ # Make FF pay attention to services.settings.server
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1598562
+ export XPCSHELL_TEST_PROFILE_DIR=1
+
+ ${firefox}/bin/firefox \
+ --no-remote \
+ --profile "$TMP_PROFILE" \
+ "$@"
'';
};
-
- launcher = firefox: pkgs.writeShellScriptBin "firefox" ''
- # FF doesn't accept ro profiles, tries to create lockfile
- TMP_PROFILE="$(mktemp -d)"
- echo "$TMP_PROFILE"
-
- function finish() {
- echo deleting profile
- # rm -rv "$TMP_PROFILE"
- }
- trap finish EXIT
- # cp -r ''${profile} "$TMP_PROFILE"
- chmod u+rwx -R "$TMP_PROFILE"
-
- export MOZ_LOG=nsHttp:1
- export MOZ_LOG_FILE=ff
- # Make FF pay attention to services.settings.server
- # https://bugzilla.mozilla.org/show_bug.cgi?id=1598562
- export XPCSHELL_TEST_PROFILE_DIR=1
-
- ${firefox}/bin/firefox \
- --no-remote \
- --profile "$TMP_PROFILE" \
- "$@"
- '';
-}
+in self
diff --git a/nix/options.nix b/nix/options.nix
new file mode 100644
index 0000000..cbd21a5
--- /dev/null
+++ b/nix/options.nix
@@ -0,0 +1,66 @@
+{ options, pkgs, lib, ... }:
+
+with lib;
+let
+ # https://github.com/NixOS/nixpkgs/pull/75584
+ json = with lib.types; let
+ valueType = nullOr (oneOf [
+ bool
+ int
+ float
+ str
+ (attrsOf valueType)
+ (listOf valueType)
+ ]) // {
+ description = "Boolean, Integer, Float, String, or lists or attribute sets of these types";
+ };
+ in valueType;
+in {
+ options = {
+ meta.description = mkOption {
+ type = types.lines;
+ default = "";
+ internal = true;
+ };
+
+ preferences = mkOption {
+ type = json;
+ default = {};
+
+ description = ''
+ These nested values are translated directly into Firefox preferences, as can be
+ found in user.js, prefs.js, or about:config.
+ '';
+
+ example = {
+ };
+ };
+
+ policies = mkOption {
+ type = json;
+ default = {};
+
+ description = ''
+ These nested values must follow the pattern of https://github.com/mozilla/policy-templates/,
+ but compliance is not validated immediately.
+ '';
+
+ example = {
+ FirefoxHome = {
+ Pocket = false;
+ Locked = true;
+ };
+ NewTabPage = false;
+ };
+ };
+
+ omnija.browser.patchCommand = mkOption {
+ type = types.lines;
+ default = "";
+
+ description = ''
+ This is a shell script to be executed for patching omni.ja
+ '';
+ };
+ };
+}