Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NixOS Packaging #204

Closed
IceDBorn opened this issue Aug 24, 2022 · 71 comments
Closed

NixOS Packaging #204

IceDBorn opened this issue Aug 24, 2022 · 71 comments
Labels
enhancement New feature or request

Comments

@IceDBorn
Copy link

IceDBorn commented Aug 24, 2022

I've managed to package the native connector for NixOS, but the extension does not recognize it as installed. I think that it has something to do with how NixOS handles installed apps. NixOS does not place applications in /usr/bin, instead each application has it's own path in the nix store. @filips123 I'm asking for help for making the package recognizable by the extension.

@IceDBorn IceDBorn added the enhancement New feature or request label Aug 24, 2022
@IceDBorn
Copy link
Author

NixOS/nixpkgs#47340

@IceDBorn
Copy link
Author

IceDBorn commented Aug 24, 2022

I managed to fix the issue by copying firefoxpwa.json to ~/.mozilla/native-messaging-hosts/ and specifying the absolute path of firefoxpwa-connector.

@IceDBorn
Copy link
Author

I got this when trying to launch a web app:
Failed to patch the runtime: Path "/usr/share/firefoxpwa/userchrome/runtime" does not exist or you don't have access!

@filips123
Copy link
Owner

Path /usr/share/firefoxpwa/userchrome/ contains files from native/userchrome/ that are required to modify Firefox so it behaves like a web app. I'm not sure how NixOS handles this, but you will need to include that directory inside NixOS package.

In case modifying global /usr/share is not possible on NixOS, you can also include those files in some other directory and set FFPWA_SYSDATA build- or run-time environment variable to the correct path. You will probably also have to set FFPWA_EXECUTABLES to a dir that contains firefoxpwa and firefoxpwa-connector executables to make launching web apps work. You can read more details about FFPWA environment variables here, and checking how Homebrew formula handles paths with environment variables might also be useful.

For native messaging manifest, if there is no automatic way of installing it to the required location, displaying instructions how to create a symlink to the manifest after installing the package (as it's done for Homebrew) is enough.

@spikespaz
Copy link

I made some progress on this.

# <https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=firefox-pwa>
{
  stdenv,
  rustPlatform,
  fetchFromGitHub,
  openssl,
  pkg-config,
  maintainers,
}: let
  version = "2.1.2";
  source = fetchFromGitHub {
    owner = "filips123";
    repo = "PWAsForFirefox";
    rev = "v${version}";
    sha256 = "sha256-zJSrZOLHyvvu+HoHrPkDDISuY9GqpKtwGn/7jKzg5pI=";
  };
in
  rustPlatform.buildRustPackage {
    pname = "firefox-pwa";
    inherit version;

    src = "${source}/native";
    cargoSha256 = "sha256-zLl7WvGzN/ltc7hT5cAsp3ByrlThQmRXrGM5rKbntdY=";

    doCheck = false;

    nativeBuildInputs = [pkg-config];
    buildInputs = [openssl.dev openssl];

    preConfigure = ''
      # replace the version number in the manifest
      sed -i 's;version = "0.0.0";version = "${version}";' Cargo.toml
      # replace the version in the lockfile, otherwise Nix complains
      sed -zi 's;name = "firefoxpwa"\nversion = "0.0.0";name = "firefoxpwa"\nversion = "2.1.2";' Cargo.lock
      # replace the version number in the profile template files
      sed -i $'s;DISTRIBUTION_VERSION = \'0.0.0\';DISTRIBUTION_VERSION = \'${version}\';' userchrome/profile/chrome/pwa/chrome.jsm
    '';

    installPhase = let
      target = "target/${stdenv.targetPlatform.config}/release";
    in ''
      runHook preInstall

      # Executables
      install -Dm755 ${target}/firefoxpwa $out/bin/firefoxpwa
      install -Dm755 ${target}/firefoxpwa-connector $out/lib/firefoxpwa/firefoxpwa-connector

      # Manifest
      install -Dm644 manifests/linux.json $out/lib/mozilla/native-messaging-hosts/firefoxpwa.json
      sed -i "s;/usr/libexec/firefoxpwa-connector;$out/lib/firefoxpwa/firefoxpwa-connector;" $out/lib/mozilla/native-messaging-hosts/firefoxpwa.json

      # Completions
      install -Dm755 ${target}/completions/firefoxpwa.bash $out/share/bash-completion/completions/firefoxpwa
      install -Dm755 ${target}/completions/firefoxpwa.fish $out/share/fish/vendor_completions.d/firefoxpwa.fish
      install -Dm755 ${target}/completions/_firefoxpwa $out/share/zsh/vendor-completions/_firefoxpwa

      # Documentation
      install -Dm644 ${source}/README.md $out/share/doc/firefoxpwa/README.md
      install -Dm644 README.md $out/share/doc/firefoxpwa/README-NATIVE.md
      install -Dm644 ${source}/extension/README.md $out/share/doc/firefoxpwa/README-EXTENSION.md
      install -Dm644 packages/deb/copyright $out/share/doc/firefoxpwa/copyright

      # UserChrome
      mkdir -p $out/share/firefoxpwa/userchrome/
      cp -r userchrome/* $out/share/firefoxpwa/userchrome/

      runHook postInstall
    '';
  }
{self, ...}: {
  config,
  lib,
  pkgs,
  ...
}: let
  inherit (lib) types;
  cfg = config.programs.firefox.pwa;
in {
  options = {
    programs.firefox.pwa = {
      enable = lib.mkEnableOption (lib.mdDoc "enable");
      package = lib.mkOption {
        type = types.package;
        default = pkgs.firefox-pwa;
        description = lib.mdDoc '''';
        example = lib.literalExpression '''';
      };
      executables = lib.mkOption {
        type = types.path;
        readOnly = true;
        default = "${cfg.package}/bin";
        description = lib.mdDoc '''';
        example = lib.literalExpression '''';
      };
      sysData = lib.mkOption {
        type = types.path;
        readOnly = true;
        default = "${cfg.package}/share";
        description = lib.mdDoc '''';
        example = lib.literalExpression '''';
      };
      userData = lib.mkOption {
        type = types.path;
        default = "${config.xdg.dataHome}/firefoxpwa";
        description = lib.mdDoc '''';
        example = lib.literalExpression '''';
      };
    };
  };
  config = lib.mkIf cfg.enable {
    home.sessionVariables = {
      FFPWA_EXECUTABLES = cfg.executables;
      FFPWA_SYSDATA = cfg.sysData;
      FFPWA_USERDATA = cfg.userData;
    };
    home.file.".mozilla/native-messaging-hosts/firefoxpwa.json".source = "${cfg.package}/lib/mozilla/native-messaging-hosts/firefoxpwa.json";
    home.packages = [
      (cfg.package.overrideAttrs (_: {
        postInstall = ''
          ln -s $out/lib/firefoxpwa/firefoxpwa-connector $out/bin;
        '';
      }))
    ];
  };
}

Now, the extension recognizes the binaries and the native messaging description. I can create profiles and add PWAs from the extension popup.

I face an issue where the extension assumes the path of /usr/bin, when I start for example Google Messages, I see:

Failed to patch the runtime: Path "/usr/share/firefoxpwa/userchrome/runtime" does not exist or you don't have access!

When I launch from the .desktop file using Rofi I see:

Failed to execute: '/usr/bin/firefoxpwa site launch 01GJF401WT97CK1Q5NFTFNQSTS --protocol' Error: 'Failed to execute child process "/usr/bin/firefoxpwa" (No such file or directory)

@spikespaz
Copy link

spikespaz commented Nov 23, 2022

Showing recent changes:

Home Manager module:

    programs.firefox.package = cfg.firefoxPackage.overrideAttrs (old: {
      nativeBuildInputs = old.nativeBuildInputs ++ [pkgs.makeWrapper];
      postFixup = ''
        wrapProgram ${lib.getExe cfg.firefoxPackage} \
          --set FFPWA_EXECUTABLES '${cfg.executables}' \
          --set FFPWA_SYSDATA '${cfg.sysData}' \
          --set FFPWA_USERDATA '${cfg.userData}'
      '';
    });

Debugging:

$ firefoxpwa runtime install
07:34:24 [WARN] This will download the unmodified Mozilla Firefox and locally modify it
07:34:24 [WARN] Firefox is licensed under the Mozilla Public License 2.0
07:34:24 [WARN] Firefox is a trademark of the Mozilla Foundation in the U.S. and other countries
07:34:24 [WARN] This project is not affiliated with the Mozilla Foundation in any way
07:34:24 [WARN] By using this project you also agree to the Firefox Privacy Notice: https://www.mozilla.org/privacy/firefox/
07:34:24 [WARN] Check the Firefox website for more details: https://www.mozilla.org/firefox/
07:34:24 [INFO] Downloading the runtime archive
07:54:28 [INFO] Extracting the runtime archive
07:54:37 [INFO] Copying the runtime
07:54:37 [INFO] Runtime installed!
$ firefoxpwa site launch 01GJF97WY5Q6P74R5J2JRZARFV
07:54:55 [INFO] Patching the runtime
07:54:55 [INFO] Runtime patched!
07:54:55 [INFO] Patching the profile
07:54:55 [INFO] Profile patched!
07:54:55 [INFO] Launching the web app
07:54:55 [ERROR] No such file or directory (os error 2)

What exactly is not found?

$ echo $FFPWA_EXECUTABLES && ls $FFPWA_EXECUTABLES
/nix/store/zf1mqcdpcb4d2ga54wjpv8mygzxfw03p-firefox-pwa-2.1.2/bin
firefoxpwa firefoxpwa-connector
$ echo $FFPWA_SYSDATA && ls $FFPWA_SYSDATA
/nix/store/zf1mqcdpcb4d2ga54wjpv8mygzxfw03p-firefox-pwa-2.1.2/share/firefoxpwa
userchrome
$ echo $FFPWA_USERDATA && ls $FFPWA_USERDATA
/home/jacob/.local/share/firefoxpwa
config.json firefoxpwa.log profiles runtime

Also, in previous messages the code shown does not include firefoxpwa-connector in the bin or in $FFPWA_EXECUTABLES as should be. This is fixed.

@filips123
Copy link
Owner

filips123 commented Nov 26, 2022

It looks like the site launch failed when trying to launch firefox (somewhere after here, which calls site.launch and then runtime.run). The only way I see how this could happen is if the firefox executable from the runtime was not found. However, I don't know how the program went so far as launching it, as it should fail earlier with "Runtime not installed".

@pasqui23
Copy link

Here is my attempt: https://github.com/pasqui23/nixpkgs/blob/firefox-pwa/pkgs/tools/networking/firefox-pwa/default.nix

However if I try to open a PWA I get the error:

Failed to patch the runtime: Path "/home/me/.local/state/firefox-pwa/userchrome/runtime" does not exist or you don't have access!

@spikespaz
Copy link

spikespaz commented Feb 10, 2023

@pasqui23 It's a bad idea to use ~ in package derivations, I don't even think Nixpkgs would accept it. Could be wrong.

Why did you use postInstall rather than installPhase? In this case, the behavior is 100% custom and therefore should override the default from buildRustPackage, unless I'm mistaken and we still need that default phase.

After line 47, where wrapArgs is defined; are you sure you don't want to use ${wrapArgs[@]} in usages?

@pasqui23
Copy link

pasqui23 commented Feb 10, 2023 via email

@filips123
Copy link
Owner

However if I try to open a PWA I get the error:

This error is probably caused because UserChrome stuff hasn't been copied to the correct location. I think the problem is that you have set FFPWA_SYSDATA to ~/.local/state/firefox-pwa, while you copy UserChrome to $out/share/firefoxpwa/userchrome.

PWAsForFirefox expects userchrome to be located inside a directory set in FFPWA_SYSDATA, so you should probably set it to $out/share/firefoxpwa (but I'm not familiar with Nix and don't know what that $out is). Also, although I don't know how Nix handles "global" directories for packages, I think that you shouldn't use ~ for FFPWA_SYSDATA, as that directory is meant for static global data that are not specific for each user. It also does not need write permission (only FFPWA_USERDATA needs it).

and found that FFPWA_SYSDATA is read at build time, not runtime.

It should be read both at build and runtime.

@IceDBorn
Copy link
Author

@filips123 $out is the folder created for the package on /nix/store, it should only contain files that you won't modify. /nix/store is read-only too.

@spikespaz
Copy link

@filips123

It should be read both at build and runtime.

That is incredibly useful to know. Will try exposing the var at build time and getting back to people @ here.

@spikespaz
Copy link

@filips123 How I make use of this information depends on:
Does compiling the binary hard-code the value of FFPWA_SYSDATA, or does it simply read file contents at the path provided at FFPWA_SYSDATA?

@spikespaz
Copy link

Looks like it is either-or.

/// Can be overwritten by a `FFPWA_SYSDATA` build- or run-time environment variable.

@spikespaz
Copy link

What does "on windows" mean? Is it firefoxpwa-connector only required on Windows? Or because you expect the binary to be in libexec on Linux?

/// launches web apps. On Windows, also contains the `firefoxpwa-connector` executable

@filips123
Copy link
Owner

filips123 commented Feb 11, 2023

What does "on windows" mean? Is it firefoxpwa-connector only required on Windows? Or because you expect the binary to be in libexec on Linux?

It's because firefoxpwa-connector is in libexec on Linux. I will probably improve that comment at some point so this is more clear.

Does compiling the binary hard-code the value of FFPWA_SYSDATA, or does it simply read file contents at the path provided at FFPWA_SYSDATA?

It just sets the location of the system data directory to the value of FFPWA_SYSDATA, and reads that directory when needed at runtime. (Also, even if you set FFPWA_SYSDATA at buld time, it can still be overwritten at run time, but I think that shouldn't really matter.)

Basically, directories are set in this way:

  1. If there is no environment variable: Use default value (/usr/share/firefoxpwa/ on normal Linux).
  2. If there is build-time environment variable: Set directory to that instead.
  3. If there is run-time environment variable: Set directory to that instead.
  4. When needed at run-time: Access directory contents, etc.

$out is the folder created for the package on /nix/store, it should only contain files that you won't modify. /nix/store is read-only too.

Then I think FFPWA_SYSDATA should point to somewhere in that directory, as it only contains read-only data.


Here is a rough overview of how I think the package should be set up to work:

  • $XDG_DATA_HOME/firefoxpwa/:

    This is FFPWA_USERDATA. This should be stored per user and must have write permission. Unless Nix requires some specific directory for user data, I don't think much work is needed here as PWAsForFirefox will already automatically detect XDG data directory.

  • $NIX_PACKAGE_ROOT/bin/:

    This is FFPWA_EXECUTABLES and should be stored globally. It needs to contain firefoxpwa binary, and should probably be added to PATH (or what Nix uses for binaries), so users can easily execute it.
    Additionally, this needs to be some unversioned path (i.e., it must not contain any version or other stuff that changes between package updates in the directory name), as otherwise, web apps would break on every update (like they did on Homebrew when I forgot to use unversioned paths PWAs fail to launch after upgrading #55).

  • $NIX_PACKAGE_ROOT/libexec/:

    This is where firefoxpwa-connector needs to be stored. It does not need to be added to PATH, but outside programs (Firefox) still need to be able to launch it. It should also be in an unversioned path, if possible (but I think here it's not necessary, as long as the manifest gets updated every time). Edit: It can be versioned, but then the manifest needs to be updated every time the path changes to point to the correct one.

  • $NIX_PACKAGE_ROOT/share/:

    This is FFPWA_SYSDATA, should be stored globally and only needs read permission. It needs to contain userchrome directory. It should also be in an unversioned path, if possible. Edit: It can be versioned without any additional requirements.

  • /usr/lib/mozilla/native-messaging-hosts/firefoxpwa.json and /usr/lib64/mozilla/native-messaging-hosts/firefoxpwa.json:

    Should be in the root Linux filesystem, without any Nix stuff, so Firefox can detect them properly. Or, if Nix does not allow such global files, the manifest should be stored per user in ~/.mozilla/native-messaging-hosts/firefoxpwa.json.
    The path in the manifest should point to the correct firefoxpwa-connector location.

  • Shell completions:

    I don't know how Nix handles this, but shell completions should be stored in appropriate locations so shells can automatically load them.

@IceDBorn
Copy link
Author

@filips123 I don't think that you can have unversioned paths for the executables, because everytime nix builds a package it stores it with a hash in the path. Would links work? Because it is possible to do something like environment.etc."firefoxpwa".source = "${(pkgs.callPackage self-built/firefoxpwa.nix {})}/";, which links the package's auto-generated path to /etc/firefoxpwa/

@filips123
Copy link
Owner

Links should probably work. The reason why it needs unversioned paths or something similar is that generated .desktop entries for installed web apps simply call {exe} site launch {id} when launched. On classic Linux (and Windows), this is not a problem, because the path will always remain the same (/usr/bin/firefoxpwa), but on Nix (and Homebrew), it can cause the entries to point to invalid executable path from the previous version. Homebrew has opt_bin which is not versioned and probably uses links, so I think links should also work here.

firefoxpwa-connector can versioned if that is easier, but the package needs to make sure that the manifest always points to the correct version.

Also, after checking some thing a bit, share/FFPWA_SYSDATA can also be versioned. I think that shouldn't cause any problems, because it is only used internally to copy some files from it.

@pasqui23
Copy link

  • $NIX_PACKAGE_ROOT/share/:
    This is FFPWA_SYSDATA, should be stored globally and only needs read permission. It needs to contain userchrome directory. It should also be in an unversioned path, if possible.

Again I've already tried to do FFPWA_SYSDATA="$out/share" at build time but the error remain the same, only referencing the nix store path instead.
So what is firefoxpwa really trying to do? Why does it says "Path does not exist or you don't have access!"? When I copy the path I'm given it effectively does not exist, even when i tried to point FFPWA_SYSDATA to inside the nix store.

@spikespaz
Copy link

Not worried about any of that, already got all of the paths set up how you've described. I only asked for clarification because of the wording of one of @filips123's comments and quickly resolved by looking at directories.rs. I thought the documentation there was clear enough, it was foolish of me to ask here first.

@filips123 Would it be possible for you to publish your two (or three?) Git-vendored crates on crates.io? They are quite difficult to get working with Nix because something something hashing something something.

@filips123
Copy link
Owner

@pasqui23 I think the problem is that I've said $NIX_PACKAGE_ROOT/share/ instead of $NIX_PACKAGE_ROOT/share/firefoxpwa/. It should be FFPWA_SYSDATA="$out/share/firefoxpwa". This probably makes more sense as there is also other stuff in share (like completions) that is not really sysdata.

@spikespaz Well, data-url and mime are just forks of already existing crates, but with some changes that are not yet merged to the upstream (and unfortunately probably won't be anytime soon as they are not actively developed anymore). web_app_manifest is my own crate that I would like to publish eventually, but it depends on my fork of mime and I think you can't publish crates that depend on git crates to crates.io. I could probably publish them under different names than original, but I don't know what crates.io policies/recommendations are about publishing more or less temporary forks of existing crates.

@spikespaz
Copy link

@filips123 Mind making them submodules? I totally understand if you don't want to, I get that submodules aren't always the easiest for you, and you've gotta keep them up to date before the lock file. Probably really annoying.

@filips123
Copy link
Owner

filips123 commented Feb 11, 2023

Yeah, submodules can be quite annoying... Is there some other way of creating Nix packages with crates from Git? I don't know how useful that is, but you can still obtain commit hashes for Git dependencies in Cargo.lock.

@spikespaz
Copy link

@filips123 Nix is dumb strict about hashes for everything. It isn't satisfied by commit hashes. I've argued about it before. I'll look deeper tomorrow, I don't even want you to deal with submodules. I'll find some sort of hack, or maybe extract one of the release .deb packages. Won't be able to get this into nixpkgs that way, but at least it's something. I have a feeling your project is in high demand among NixOS users.

@IceDBorn IceDBorn changed the title NixOS Packagement NixOS Packaging Feb 11, 2023
@filips123
Copy link
Owner

Thanks! I think it would still be nice if the package can get into nixpkgs, so if you cannot find any other way that is accepted, I can still publish data-url and mime under different names, and then web_app_manifest. It seems that although it's generally not recommended to publish forks, it's still fine to publish them with the username as a prefix and appropriate description, if that's really needed.

@pasqui23
Copy link

The reason why it needs unversioned paths or something similar is that generated .desktop entries for installed web apps simply call {exe} site launch {id} when launched.

Note that the {exe} can and should be a bare command, not an absolute path.For example nixpkgs' firefox.desktop has just Exec=firefox %U.

@LennyPenny
Copy link

Someone's actually on it @theLockesmith, you can follow the packaging effort here: NixOS/nixpkgs#263404

@spikespaz
Copy link

Three of us, perhaps more, have tried. Why don't we just modify the project itself to allow for vendored Firefox to be provided, and disable the downloading feature?

@filips123
Copy link
Owner

Well, it already allows using Firefox without downloading. It just needs to be copied/symlinked into the correct location, which is $XDG_DATA_HOME/firefoxpwa/runtime/, $HOME/.local/share/firefoxpwa/runtime/ or $FFPWA_USERDATA/runtime/.

@spikespaz
Copy link

Is the output of nix build 'nixpkgs#firefox' suitable to be linked to that location?

@spikespaz
Copy link

And perhaps, a feature gate which disables downloading altogether, and instead showing an error when it decides that something should be downloaded and isn't already present.

@pasqui23
Copy link

pasqui23 commented Dec 11, 2023 via email

@filips123
Copy link
Owner

Actually, I think symlink to system files won't work, because some files in that directory need to be modified/added (specifically, defaults/pref/autoconfig.js and _autoconfig.cfg), and with symlink, this could either just fail because of lack of permissions, or succeed but then actually affect the distro-provided Firefox.

Other options instead of symlinking the whole directory could be symlinking just specific files (#403) or using FUSE OverlayFS (#67, #214), but none of these options are quite ready yet... In any case, the target directory should have the same structure as the one from official Firefox tarballs. Additionally, it should be possible for user to switch that default provided Firefox with another Firefox version/fork.

Adding an option to disable downloading at compile time is also possible.

However, I don't really know why downloading Firefox like it's currently done is a problem... Is it the problem that the downloaded Firefox won't work correctly because it needs some NixOS-specific configuration, or something else?

@spikespaz
Copy link

The problem is that almost every program needs to be patched, in some way, for some reason, with us NixOS users.

Your follow-up has confirmed my skepticism, and validated my memory as to why I stopped working on this.

What could work is doing the patching (all of it, yours and ours) at build time. Is there a way to run your tool on a given directory that contains Firefox files? If we can call a program to do these patches for FFPWA we could just link that instead after building all of the binaries.

@filips123
Copy link
Owner

Is there a way to run your tool on a given directory that contains Firefox files?

So, the program would apply all FFPWA changes to Firefox in a given directory? This is currently not possible, but I think it should be possible to add a command that does something like this (something like firefoxpwa runtime patch).

I'm not that familiar with NixOS, so I have a few more questions.

Currently, the runtime is stored along with user data in a user-specific directory, which means the runtime needs to be duplicated for each user. I don't know how NixOS handles users, so is this fine? Otherwise, I think it should also be possible to create a build-time option to change the runtime directory to a global location.

How will updates to Firefox and FFPWA be handled in this case? When Firefox is updated, the latest Firefox version needs to be copied into that directory and FFPWA patches need to be applied. Similarly, when FFPWA is updated, the new patches also need to be applied.

@pasqui23
Copy link

NixOS' big problem is that it doesn't install anything in /, so when the firefox downloaded by firefoxpwa attempts to load libraries even as foundational as libc it will fail because it is trying and failing to look for it in /lib where, again, nothing is installed.

Firefox as packaged by nixpkgs instead will load the necessary libraries each from their specific directories in /nix/store. It is how nix can allow to have several version of the same library installed: different version of firefox will refer to separate version of the library with completely different paths. Another wrinkle is that /nix/store is readonly and all the libraries refer to their dependencies by full path inside the nix store.

Firefoxpwa as packaged in nixpkgs work around this by being started in a user namespace where libc is present in /lib and firefox will then be started by firefoxpwa and inherit said namespace with all the libraries in the "right" place.

@spikespaz
Copy link

@filips123

firefoxpwa runtime patch

This would be perfect. If we can give it a path to a Firefox distribution, for example /nix/store/yvw828jjkwiyj5070k9v94r6wklqvf7p-firefox-120.0.1/ (contains bin, lib, share), and have it mutate that, then bingo, we have a solution. The solution would look something like this:

{
  programs.firefpx-pwa.firefoxPackage = pkgs.firefox;
  programs.firefox-pwa.firefoxPackagePatched = let
    super = config.programs.firefox-pwa.firefoxPackage;
  in
    pkgs.symlinkJoin {
      pname = super.pname + "-ffpwa-patched";
      inherit (super) version meta;
      paths = [ super ];
      nativeBuildInputs = [ config.programs.firefox-pwa.package ];
      postInstall = ''
        firefoxpwa runtime patch .
      '';
    };
}

This code (untested, typed in GitHub) should just take the existing Firefox package (set by config.programs.firefox-pwa.firefoxPackage which is most-likely pkgs.firefox-bin), make a copy, and then patch it by running the appropriate command. The output config.programs.firefox-pwa.firefoxPackagePatched.outPath should be useful for FFPWA_RUNTIME_DIR or whatever.


How will updates to Firefox and FFPWA be handled in this case?

I know this might seem wrong, but we would disable automatic updates. This isn't something I like as a NixOS user. Everything will update when I tell it to, by running nix flake update and then re-building the entire system. There won't be any services downloading things on a schedule.

I think the best way to do this would be to have a Cargo feature, immutable-runtime.


Currently, the runtime is stored along with user data in a user-specific directory, which means the runtime needs to be duplicated for each user. I don't know how NixOS handles users, so is this fine? Otherwise, I think it should also be possible to create a build-time option to change the runtime directory to a global location.

If I recall, this is FFPWA_USERDATA_DIR? If so, where is the default? Because we can set that to something like ${config.xdg.dataHome}/firefox-pwa (expands to, by default, $HOME/.local/share/firefox-pwa).

Is there anything inside of FFPWA_RUNTIME_DIR that needs to be mutable to write user data? The profile? Is that included in the runtime dir, or can it be moved out with the variable above? It would be preferable to have the runtime be immutable, but if needed, we can symlink recursively so that specific new files can be created (I have to do the same thing for steam Proton) but that would make it slow, as it creates hundreds, maybe thousands, of links.

@filips123
Copy link
Owner

I know this might seem wrong, but we would disable automatic updates. This isn't something I like as a NixOS user. Everything will update when I tell it to, by running nix flake update and then re-building the entire system. There won't be any services downloading things on a schedule.

I meant if the user only updates the Firefox package but not PWAsForFirefox, is it possible to automatically re-apply PWAsForFirefox modifications to that new Firefox version (and opposite if the user only updates PWAsForFirefox package but not Firefox package).

(I don't know if updating only specific packages is possible on Nix.)

I think the best way to do this would be to have a Cargo feature, immutable-runtime.

Yeah, this should be possible.

If I recall, this is FFPWA_USERDATA_DIR? If so, where is the default? Because we can set that to something like ${config.xdg.dataHome}/firefox-pwa (expands to, by default, $HOME/.local/share/firefox-pwa).

It uses $XDG_DATA_HOME/firefoxpwa/ or, if XDG data home is not set, $HOME/.local/share/firefoxpwa/.

Is there anything inside of FFPWA_RUNTIME_DIR that needs to be mutable to write user data? The profile? Is that included in the runtime dir, or can it be moved out with the variable above? It would be preferable to have the runtime be immutable, but if needed, we can symlink recursively so that specific new files can be created (I have to do the same thing for steam Proton) but that would make it slow, as it creates hundreds, maybe thousands, of links.

Currently, runtime is stored in FFPWA_USERDATA/runtime, profiles are stored in FFPWA_USERDATA/profiles, config is stored in FFPWA_USERDATA/config.json, and that directory also contains a few other files (logs, etc.). So, FFPWA_USERDATA needs to be writable.

However, I can also add another environment variable like FFPWA_RUNTIME so that the runtime can be moved to a global immutable directory, outside of FFPWA_USERDATA. I think that once the runtime is patched, it can be immutable.


Also, what is that user namespace that @pasqui23 mentioned?

@pasqui23
Copy link

Also, what is that user namespace that @pasqui23 mentioned?

I was sightly mistaken, firefoxpwa as packaged by @camillemndn uses LD_LIBRARY_PATH and GTK_PATH directly to find the correct libraries, no user namespaces needed. Otherwise, nixpkgs includes a framework to use bubblewrap to run a binary in a root directory mirroring a standard LFS root.

@filips123
Copy link
Owner

So, what's the difference between using NixOS-provided immutable runtime and using LD_LIBRARY_PATH and GTK_PATH or user namespaces with "normal" downloaded runtime? I guess immutable runtime is the "intended" way of doing things, but are there other differences? Do these two different options affect performance, usability, etc.?

@pasqui23
Copy link

pasqui23 commented Dec 23, 2023 via email

@tukanoidd
Copy link

tukanoidd commented Dec 29, 2023

https://github.com/Rutherther/nur-pkgs/tree/master/pkgs/firefoxpwa found it packaged by someone in NUR, but outdated (2.7.3), would it be possible to get it working based on this? I managed to get it installed and was able to get through connector recognition phase and even runtime installation, but wasn't able to actually run a PWA that I successfully installed according to the extension, just wasn't starting up (microsoft teams in my case), but I'm not sure if it's because it's outdated or because something else there is broken

Here's minimal working config (using HM):

home.packages = with pkgs; [
	nur.repos.rutherther.firefoxpwa
];
programs.firefox = {
	enable = true;
    package = pkgs.firefox.override {
      	nativeMessagingHosts = with pkgs; [
        	nur.repos.rutherther.firefoxpwa-unwrapped
		];
	};
};

I really like firefox (or floorp, override also works there btw, started using it recently, cuz after using Vivaldi, can't live without sidebar, but I really prefer firefox with it's performance and degree of additional customizability I can get with extensions) and the only thing that keeps me from using it 100% of the time is the lack of PWA support, which this extension could remedy.

EDIT: PWA launches only if run through CLI, but not browser UI, although I'm getting this:

[GFX1-]: glxtest: libpci missing
[GFX1-]: vaapitest: ERROR
[GFX1-]: vaapitest: VA-API test failed: libva-drm.so.2 is missing.

But I'm assuming it's not as big of a deal since it still worked?

@camillemndn
Copy link
Contributor

Hi all, please review this PR NixOS/nixpkgs#263404. For me it works on all my NixOS machines, so maybe we can finally close this issue. ☺️

filips123 added a commit that referenced this issue Jan 20, 2024
This prevents installing and uninstalling the runtime using commands, and also stops patching the runtime when launching web apps. The runtime can still be patched manually from the extension settings or the patch command if the user has sufficient write permissions to do so.

This is meant for immutable systems like Guix or Nix where runtime might be provided by the package manager and pre-patched. See #204 for more.
@filips123
Copy link
Owner

I've added a command option firefoxpwa runtime patch in 8851dbd that patches the runtime directory with PWAsForFirefox runtime modifications.

I've also added a Cargo feature immutable-runtime in d167262 that, when enabled, disables commands firefoxpwa runtime install and firefoxpwa runtime uninstall and stops patching the runtime when launching web apps. The runtime can still be patched manually using firefoxpwa runtime patch or from the extension settings.

These features will be available in the next release.

I'm not sure how far the attempts to use LD_LIBRARY_PATH and GTK_PATH environment variables or user namespaces with the normal runtime downloaded with firefoxpwa runtime install have gone. If it's too hard to finish them, this immutable-runtime feature can now be used instead. I also think that someone previously said that Guix does not support user namespaces (or something like this), so this feature can probably also be used there to package PWAsForFirefox.

Also, I previously said that the runtime can only be installed in $FFPWA_USERDATA_DIR/runtime. However, it can actually also be installed inside $FFPWA_SYSDATA_DIR/runtime, which is global for all users. When the immutable-runtime feature is enabled, it can be non-writable for normal users, so i think a separate $FFPWA_RUNTIME variable isn't needed. The user can also still manually install a different runtime into $FFPWA_USERDATA_DIR/runtime.

So, in case you decide to use the immutable-runtime option when packaging PWAsForFirefox, I think the workflow should look something like this:

  1. Copy the distro-provided Firefox into $FFPWA_SYSDATA_DIR/runtime (which is global directory).
  2. With sufficient write rights, run firefoxpwa runtime patch, which will copy runtime patches from $FFPWA_SYSDATA_DIR/userchrome to $FFPWA_SYSDATA_DIR/runtime.
  3. Make sure firefoxpwa runtime patch is ran again when Firefox or PWAsForFirefox packages are updated.

Please let me know if there are any other things related to Nix (and Guix) that I could do to make packaging easier.

@camillemndn
Copy link
Contributor

camillemndn commented Jan 23, 2024

Hi, the packaging I suggested works flawlessly (no error/warning at Firefox launch, all the libraries are found using the native NixOS wrapping tools). I even wrote a NixOS test to prove that FirefoxPWA on NixOS works.

Just to understand this discussion, we are talking about a refinement to avoid downloading the Firefox client on NixOS? But we agree that FirefoxPWA on NixOS is already perfectly functional as is?

However, when it is released, I can add this new feature in the NixOS packaging process, I agree that it would be even cleaner to patch Firefox once and for all in the Nix Store.

Thank you @filips123 for your help!

@filips123
Copy link
Owner

Just to understand this discussion, we are talking about a refinement to avoid downloading the Firefox client on NixOS? But we agree that FirefoxPWA on NixOS is already perfectly functional as is? However, when it is released, I can add this new feature in the NixOS packaging process, I agree that it would be even cleaner to patch Firefox once and for all in the Nix Store.

If it works fine without the immutable runtime (which prevents downloading normal Firefox from Mozilla), that's great!

If that additional featue to use the immutable runtime is added, I think it would be good if it's optional (so, that user decides whether to use it when installing the package, if that's possible), as users might still want to download Firefox automatically or use other compatible Firefox-based browsers.

@camillemndn
Copy link
Contributor

Ok! I think we gare nearly ready! Thanks again for your changes. Now my web apps use the /nix/store/*/share/firefoxpwa/runtime version of Firefox. This is way cleaner. If you can review my PR so that we can move to merging.

@filips123
Copy link
Owner

I've added some basic installation instructions for NixOS in the extension:

screenshot

Also, as the nixpkgs PR has been merged, I'm closing this issue. Please let me know if you have problems with Nix packaging.

@pwall2222
Copy link

I've added some basic installation instructions for NixOS in the extension:

screenshot

Also, as the nixpkgs PR has been merged, I'm closing this issue. Please let me know if you have problems with Nix packaging.

When I tried this there was something that I failed to realize, that you need to have
programs.firefox.enable set to true, so maybe you could add that as a note!

@tiecia
Copy link

tiecia commented Apr 7, 2024

Thank you all for the work getting this added to nixpkgs.

I just went through the steps to install the firefoxpwa package and was able to get the extension to detect the connector and runtime, and install a PWA. However, when I try to launch the PWA it quickly appears on screen and crashes immediately and I am unsure where logs would be located.

Also, I agree with the previous comment that something should be added to docs that say programs.firefox.enable should be set to true. I spent a good amount of time trying to get the connector to be detected before I realized that needed to be set.

Here is my configuration:

environment.systemPackages = with pkgs; [
  firefoxpwa
];

programs.firefox = {
  enable = true;
  nativeMessagingHosts.packages = [pkgs.firefoxpwa];
};

If you would like me to open a new issue for this please let me know.

@Thatoo
Copy link

Thatoo commented Apr 7, 2024

I followed instruction and installed firefoxpwa.
I could install a pwa but I first needed to be sure this folder exists : ~/.local/share/icons/hicolor/

and now i face this error when I try to launch the webapp : No such file or directory (os error 2)

@filips123 : I opened an issue here : NixOS/nixpkgs#302431 but maybe you prefer I open a new issue here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.