MrOtherGuy/fx-autoconfig

Workaround for Nix(OS)

codenyte opened this issue ยท 23 comments

Please consider creating a package for the Nix package manager/NixOS. Although NixOS is a Linux distribution, it handles many things very differently and unfortunately it's not possible to install fx-autoconfig the traditional way on Nix. This guide explains how to create a Nix package: https://nixos.wiki/wiki/Packaging/Tutorial

Note that this is not a installable package and I purposefully don't provide any kind of "install-script" for it.

The way you you would set up fx-autoconfig is to just copy the files in program directory to wherever your firefox binary is, and the files in profile to wherever your Firefox profile directory is located. Follow the steps in readme for more detailed information, or if there is particular bit that you can't get past of then tell me what it is and maybe we can figure it out.

All packages installed through Nix are located in a read-only directory. When using the Nix package manager on a "normal" distro, you might be able to bypass this with root, but on NixOS there is no real way around it. Packages (like Firefox) can't be modified. I thought packaging fx-autoconfig for Nix would solve that, but then I reallized that a package can't overwrite another package's files either. I'll figure out a solution and let you know. But it would be great if there was some workaround for installing fx-autoconfig on Nix or other immutable distributions.

Right, I doubt I can do anything about that. Firefox' autoconfig feature requires that you can write default pref files to program folder because that's the only place it knows to look for them.

So, I suppose you have to compile Firefox in a way where it looks somewhere else for them. This is probably a long shot, but maybe the package manager already compiles Firefox to make it look for default pref/autoconfiguration files in some different folder?

There actually is a way in Nix to modify system/package files: https://discourse.nixos.org/t/how-to-edit-file-in-nix-store/19261

It's complicated (at least for me) and I'm not very familiar with the Nix language. (I only know how to set up basic stuff). But I will try to figure it out.

If this works and I manage to create a Nix config snippet that installs fx-autoconfig, you could maybe put that in the README.

Sure. It seems quite a task though, that sounds like you would have to compile or at least re-package the whole Firefox with your added patch.

I was wondering the same thing and came up with this workaround for now by using an overlay to symlink the files from my home dir into the nix store:

final: prev: {
  firefox = (prev.firefox).overrideAttrs (oldAttrs: {
    buildCommand = (oldAttrs.buildCommand or "") + ''
      ln -sf /home/${username}/.dotfiles/${path_to_userChromeJS}/config.js $out/lib/firefox/config.js
      ln -sf /home/${username}/.dotfiles/${path_to_userChromeJS}/config-prefs.js $out/lib/firefox/browser/defaults/preferences/config-prefs.js
    '';
  });
}

If using this, replace the config paths with yours
(postInstall isn't called in firefox's case, so I had to append to buildCommand instead)

chrome can be managed manually just fine, I personally symlink it too to my dotfiles:

# Symlink chrome dir
home.file."/home/${username}/.mozilla/firefox/${profile}/chrome".source = config.lib.file.mkOutOfStoreSymlink "/home/${username}/.dotfiles/user/apps/browser/firefox_profile/chrome";
# Symlink user.js
xdg.configFile."/home/${username}/.mozilla/firefox/${profile}/user.js".source = config.lib.file.mkOutOfStoreSymlink "/home/${username}/.dotfiles/user/apps/browser/firefox_profile/user.js";

I don't know if there's a better solution, but for now this seems to work

Okay, so essentially what you are saying is that if you don't have write access to the program directory then you can instead create symlink for <firefox-bin>/defaults/preferences/config-prefs.js and <firefox-bin>/config.js - or did I misunderstand something? (The actual path names and structure can vary between systems).

Sidenote, honestly that feels kinda nonsensical since then you kinda do have write access to that directory after all.

Yes, you understood correctly. I instruct nix to create a symlink during the firefox's package build phase.
There's probably a way to write the files instead, but I'm very new to NixOS and haven't found a way yet.

From what I understand, you have write access only during the package build phase and only within the isolated build environment. You lose write access once the package is built and moved into the nix store. The package's isolated build environment has no access to the system (hence symlink instead of a copy) or Internet (so no fetch from github & move files).

My workaround works as a temporary solution, but I'm positive there should be a proper way to resolve this.

I was wondering the same thing and came up with this workaround for now by using an overlay to symlink the files from my home dir into the nix store:

final: prev: {
  firefox = (prev.firefox).overrideAttrs (oldAttrs: {
    buildCommand = (oldAttrs.buildCommand or "") + ''
      ln -sf /home/${username}/.dotfiles/${path_to_userChromeJS}/config.js $out/lib/firefox/config.js
      ln -sf /home/${username}/.dotfiles/${path_to_userChromeJS}/config-prefs.js $out/lib/firefox/browser/defaults/preferences/config-prefs.js
    '';
  });
}

If using this, replace the config paths with yours (postInstall isn't called in firefox's case, so I had to append to buildCommand instead)

chrome can be managed manually just fine, I personally symlink it too to my dotfiles:

# Symlink chrome dir
home.file."/home/${username}/.mozilla/firefox/${profile}/chrome".source = config.lib.file.mkOutOfStoreSymlink "/home/${username}/.dotfiles/user/apps/browser/firefox_profile/chrome";
# Symlink user.js
xdg.configFile."/home/${username}/.mozilla/firefox/${profile}/user.js".source = config.lib.file.mkOutOfStoreSymlink "/home/${username}/.dotfiles/user/apps/browser/firefox_profile/user.js";

I don't know if there's a better solution, but for now this seems to work

where do I put this stuff?

where do I put this stuff?

I was later told in NixOS Discord that it's better to use it as package directly instead of overlay. You can put this in your configuration.nix/home.nix, or as a separate module if you use flakes:

Minimal flake example
{ pkgs, config, ... }:

let
  userChromeJSPath = "/path/to/user_chrome_js_files"; # (!) Replace with your path
  firefox = (pkgs.firefox).overrideAttrs (oldAttrs: {
    # Add support for https://github.com/MrOtherGuy/fx-autoconfig
    buildCommand = (oldAttrs.buildCommand or "") + ''
      ln -sf ${userChromeJSPath}/config.js $out/lib/firefox/config.js
      ln -sf ${userChromeJSPath}/defaults/pref/config-prefs.js $out/lib/firefox/browser/defaults/preferences/config-prefs.js
    '';
  });
in
{
  programs.firefox = {
    enable = true;
    package = firefox;
  };
}

Note: $out path to config-prefs.js might be different if you are not on Firefox stable.

Sadly, I'm unable to find a way to do this with Firefox Nightly.

{ pkgs, config, ... }:

let
  userChromeJSPath = "/path/to/user_chrome_js_files"; # (!) Replace with your path
  firefox = (pkgs.firefox).overrideAttrs (oldAttrs: {
    # Add support for https://github.com/MrOtherGuy/fx-autoconfig
    buildCommand = (oldAttrs.buildCommand or "") + ''
      ln -sf ${userChromeJSPath}/config.js $out/lib/firefox/config.js
      ln -sf ${userChromeJSPath}/defaults/pref/config-prefs.js $out/lib/firefox/browser/defaults/preferences/config-prefs.js
    '';
  });
in
{
  programs.firefox = {
    enable = true;
    package = firefox;
  };
}

I tried adding this to configuration.nix, but I get unexpected LET error

I tried adding this to configuration.nix, but I get unexpected LET error

Are you sure you added it in the right places? It builds for me, so I believe the syntax is correct
Can you show your configuration.nix?

All I had to do to get this working was

programs.firefox = {
  enable = true;
  autoConfig = builtins.readFile(builtins.fetchurl {  
    url = "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js";
    sha256 = "1mx679fbc4d9x4bnqajqx5a95y1lfasvf90pbqkh9sm3ch945p40";
  });
};

@rohanssrao Your solution is probably the best one, thanks for sharing it

@MrOtherGuy Consider putting this in the README as the official way of installing on Nix(OS)

@rohanssrao
Oh, that's neat!
I can confirm it works with the base firefox package. Sadly, it doesn't with firefox-nightly-bin from nix-community, but I guess that's package's fault.
Might also be worth noting that the programs.firefox.autoConfig option does not exist in home-manager.

One other thing I'm curious about, is it okay to completely ignore defaults/pref/config-prefs.js?

@SoSeDiK

One other thing I'm curious about, is it okay to completely ignore defaults/pref/config-prefs.js?

Yes, this is configured by default in the firefox package definition.

Might also be worth noting that the programs.firefox.autoConfig option does not exist in home-manager.

Nix on non-NixOS systems doesn't support modules (i.e. programs.<name>.<option>) so that is expected.

Looking at the definition, there is an extraPrefsFiles attribute that defines files which get appended to mozilla.cfg so I believe you can put the following in your home.nix to achieve the equivalent:

home.packages = with pkgs; [
  # hello
  # cowsay
  # ...
  (firefox.overrideAttrs {
    extraPrefsFiles = [(builtins.fetchurl {  
      url = "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js";
      sha256 = "1mx679fbc4d9x4bnqajqx5a95y1lfasvf90pbqkh9sm3ch945p40";
    })];
  })
];

I don't use home-manager anymore though so I can't test it. Let me know if it works. If it does, I'll add it to my PR.

Sadly, it doesn't with firefox-nightly-bin from nix-community, but I guess that's package's fault.

You could possibly try something like this to make a new derivation, inheriting the original, that manually puts the files in the correct spot afterward:

environment.systemPackages = with pkgs; [
  # hello
  # cowsay
  # ...
  (stdenv.mkDerivation {
    name = "firefoxWithAutoconfig";
    src = inputs.firefox.packages.${system}.firefox-nightly-bin; # if you specified the package a different way, replace it here
    buildPhase = ''
      mkdir $out
      cp -r * $out/
      echo 'pref("general.config.filename", "mozilla.cfg");' > "$out/lib/firefox/defaults/pref/autoconfig.js"
      echo 'pref("general.config.obscure_value", 0);' >> "$out/lib/firefox/defaults/pref/autoconfig.js"
      cp ${builtins.fetchurl {  
        url = "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js";
        sha256 = "1mx679fbc4d9x4bnqajqx5a95y1lfasvf90pbqkh9sm3ch945p40";
      }} $out/lib/firefox/mozilla.cfg;
    '';
  })
];

This probably won't work as written since I just wrote it in the text editor and haven't tested it, but feel free to mess around with it.

home-manager has some programs.firefox options, but autoConfig is not implemented (yet?).
I've tried using extraPrefsFiles as suggested (only had to wrap builtins.fetchurl in (parentheses)), but while it compiles without errors, there's no fx-autoconfig support.

The issue with firefox-nightly-bin is that it fully consists of symlinks to firefox-nightly-bin-unwrapped, including the launching binary, so any changes to firefox-nightly-bin's nix store are ignored.

I've tried using extraPrefsFiles as suggested (only had to wrap builtins.fetchurl in (parentheses)), but while it compiles without errors, there's no fx-autoconfig support.

Thanks, updated to include parentheses.

This is weird because all that programs.firefox.autoConfig does in the background is override extraPrefsFiles.

If you go to the build output in the /nix/store, does it have the correct file layout and contents needed for fx-autoconfig?

Have you also tried adding pref("general.config.sandbox_enabled", false);, both through Nix and manually through about:config?

If you go to the build output in the /nix/store, does it have the correct file layout and contents needed for fx-autoconfig?

From what I can see, building with nixos (autoConfig) appends fx-autoconfig's config.js contents into mozilla.cfg.
For some reason, it doesn't when built with home-manager (extraPrefsFiles).

This is weird because all that programs.firefox.autoConfig does in the background is override extraPrefsFiles.

I've tried using extraPrefsFiles with nixos:

  environment.systemPackages = with pkgs; [
    (firefox.overrideAttrs {
      extraPrefsFiles = [
        (builtins.fetchurl {
          url = "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js";
          sha256 = "1mx679fbc4d9x4bnqajqx5a95y1lfasvf90pbqkh9sm3ch945p40";
        })
      ];
    })
  ];

But it also doesn't append to mozilla.cfg for some reason?

Try changing overrideAttrs to override.

Using override did the trick, works with home-manager now!

Great, I added it to the PR.

Not sure why I haven't thought of this earlier, but I was finally able to add fx-autoconfig to nightly. I just replaced symlinks to binaries with actual binaries upon building it.
If anyone's interested, I've used nix-community/flake-firefox-nightly with this home-manager flake:

firefox.nix
{ pkgs, config, inputs, ... }:

let
  # Firefox Nightly with https://github.com/MrOtherGuy/fx-autoconfig
  firefox-nightly = (
    (inputs.firefox-nightly.packages.${pkgs.system}.firefox-nightly-bin).override {
      extraPrefsFiles = [
        (builtins.fetchurl {
          url = "https://raw.githubusercontent.com/MrOtherGuy/fx-autoconfig/master/program/config.js";
          sha256 = "1mx679fbc4d9x4bnqajqx5a95y1lfasvf90pbqkh9sm3ch945p40";
        })
      ];
    }
  ).overrideAttrs (oldAttrs: {
    buildCommand = (oldAttrs.buildCommand or "") + ''
      # Find firefox dir
      firefoxDir=$(find "$out/lib/" -type d -name 'firefox*' -print -quit)

      # Function to replace symlink with destination file
      replaceSymlink() {
        local symlink_path="$firefoxDir/$1"
        local target_path=$(readlink -f "$symlink_path")
        rm "$symlink_path"
        cp "$target_path" "$symlink_path"
      }

      # Copy firefox binaries
      replaceSymlink "firefox"
      replaceSymlink "firefox-bin"
    '';
  });
in
{
  programs.firefox = {
    enable = true;
    package = firefox-nightly;
  };
}

For NixOS, just replace that override block with programs.firefox.autoConfig option.