Proper way of applying patch to system managed via flake

nix-channel is not relevant for flakes.

Can you please update your flake and try again?

nix build nixpkgs/nixos-unstable\#raft-canonical works for me and fetches from the cache.

I disagree. You just make an overlay that applies the patch and uses a fixed output derivation.

An overlay is not “patching” as meant in this discussion.

Here “patching” means applying a patchfile to downloaded sources.

Oh thank you for explanation again, I’m very new to nixos and actually never did update the flake lock, so haven’t even thought about it. Now it downloads enormous amounts of updates and hopefully would work afterwards.

Right and I literally mean an overlay that adds patches like the example OP had issues with for raft-canonical isn’t the wrong approach for flakes.

Out of these options:

Modifying a packages patches with an overlay would be the best/easiest approach imo.

indeed nix flake update fixed the issue for me

Could you elaborate on why you hold that opinion?

Grabbing a rev from master is just like taking a nix flake update from the future. The only difference between doing this and not using the computer for a week and then updating is that some packages may not yet be built on hydra, but as long as the delta is small that should be a very minor concern.

On the other hand, making a patch means you have to rewrite the patch by hand. Or in the case of modules, do a significantly more complex operation to shove the updated module into the module system while replacing the old one. Unless there is a really good reason to, why would you go through that effort?

Modifying a packages patches with an overlay would be the best/easiest approach imo.

It’s easy, but not “someone has already done the work for me” easy.

Sure, I’d be glad to!

For me updating nixpkgs to master can mean recompiling 2-3 ghc versions since I use Haskell.nix, recompiling mongo, or in some cases I’ve noticed it meant recompiling webkit! Those all take on the order of hours to a day in webkit’s case.

Additionally updating to nixpkgs master typically breaks a lot of my packages in my admittedly huge flake system configuration. A workaround is using a different nixpkgs just for specific packages, but that can cause problems as well such as breaking the vscode terminal if nixpkgs mismatches.

I’m not sure what your experience is, but here’s a recent one of mine:

  • Emacs package org-ql has a bug
  • I debug the issue find the pull request fixing it
  • I lookup how to do a patch since I haven’t done one before

I put this in my overlays:

final: prev: {
    org-ql = epkgsPrev.org-ql.overrideAttrs (oldAttrs: rec {
      patches = [
        
        (prev.pkgs.fetchpatch {
          url = "https://patch-diff.githubusercontent.com/raw/alphapapa/org-ql/pull/237.patch";
          sha256 = "1j28plzxv8wp90gv6vv3sk7gybdy2js3vknyvx0kpwqim93yndn5";
        })
      ];
    });
}

So in my experience I didn’t need to create the patch. Even if I did though, it’s pretty simple to do with git or especially with magit (emacs git porcelain) and simply add the file to my flake.

I think you might agree that my example:

  • Had someone else already “do the work” by using the PR’s patch url
  • Affects less surface area and is less likely to break ones current configuration
  • Will be much faster than waiting for a full nixpkgs update

Hope this helps, but look forward to any more comments or questions!

1 Like

There is a difference between patching nixpkgs and patching a “packages” source. You did the latter. TLater says the former is between hard and impossible.

And even though I know it has been done already, with flakes and without, the resulting code to make use of it is ugly, and I think is IFD as well, though I don’t want to put my hand fire for that.

2 Likes

Here’s how I patch my flake nixpkgs:

outputs = {
    self,
    nixpkgs,
  }: let
    config = {
      allowUnfree = true;
    };
    patches = [
       # patches like fetchpatch here.
    ];
    pkgsBoot = import nixpkgs {
      system = "x86_64-linux";
      inherit config;
    };
    nixpkgsPatched = pkgsBoot.applyPatches {
      src = pkgsBoot.path;
      inherit patches;
    };
    pkgs =
      if builtins.length patches == 0
      then pkgsBoot
      else
        import nixpkgsPatched {
          system = "x86_64-linux";
          inherit config;
        };
4 Likes

Can use nixpkgs.legacyPackages.${system}.applyPatches rather than having two imports for it (just outsourcing the extra import to the nixpkgs flake, not avoiding it. Feels cleaner but not important.)

To include an entire PR’s patch rather than just one commit, you can use a URL like https://github.com/NixOS/nixpkgs/compare/d536e0a0eb54ea51c676869991fe5a1681cc6302.patch (can also do nixos-unstable…hash.patch at the end iirc or staging…hash if need a different base)

Can be useful to add an outPath for the final pkgs with // { outPath = "${nixpkgsPatched}"; };

There is a relevant issue to make it simpler/built-in: Support flake references to patches · Issue #3920 · NixOS/nix · GitHub

Last time I had trouble getting something like what ryantm suggests working, although this looks simpler than the examples in the issue.
So I forked nixpkgs, created a branch with my current locked revision + the PR commits applied on top, then changed my nixpkgs input to point to that.

With flake-utils-plus, this is as easy as:

utils.lib.mkFlake {
  ...
  channels = {
    unstable = {
      patches = [ ./patches/PR.patch ];
    };
  };

You can then download a PR patch from https://github.com/NixOS/nixpkgs/pull/<num>.patch and refer to it in the channel’s patches, and it’ll get automatically applied.

3 Likes

That requires FU+, and there are a lot of people arguing against usage of those frameworks. Even regular flake utils.

4 Likes

If I read this correctly, thats IFD?

I would be happy if there was a blessed and officially supported way to apply patches to any flake inputs that would not cause IFD.

Of course I understand that this would require an additional evaluation phase if patches have been used.

Still I think flakes would improve overall if thats supported

2 Likes

Yes, pretty sure it is IFD. I only do this on my flake for my NixOS systems.

1 Like

I wonder if that could actually be a nix builtin, some kind of syntax around inputs. “I want to patch my input” is a generic problem, even if nixpkgs’ size makes it more frequent, and nix needs git support to pull the inputs already, so why not have it patch the input before evaluation?

2 Likes

edolstra already has a WIP PR which makes this a builtin, although it’s slightly more limited as you have to have the patch files in the flake rather than fetching.

https://github.com/NixOS/nix/pull/6530

3 Likes

ryantm’s approach only patches pkgs, which doesn’t work if the patch contains fix for nixosmodule for example.

Here’s attempt version to patch the whole nixpkgs for use:

      system = "x86_64-linux";

      pkgs-init = import inputs.nixpkgs { inherit system; };

      patches = [
        (pkgs-boot.fetchpatch {
          url = "https://patch-diff.githubusercontent.com/raw/NixOS/nixpkgs/pull/207758.patch";
          hash = "sha256-1bxn+U0NslCTElG+EhJe43FRf+5tIgMh7gvPKAyGe0U=";
        })
      ];

      nixpkgs-patched =
        pkgs-boot.applyPatches {
          name = "nixpkgs-patched";
          src = inputs.nixpkgs;
          inherit patches;
        };

      pkgs = import nixpkgs-patched {
        inherit system;

        config.allowUnfree = true;

        overlays = [
          emacs-overlay.overlays.default
          .....
        ];
      };

      nixpkgs = (import "${nixpkgs-patched}/flake.nix").outputs { self = inputs.self; };

The trick is the last line of the import, which would expose back a patched nixpkgs which has lib and nixosModules, so you can use the same old nixpkgs.lib.nixosSystem for example. The patched nixpkgs is a bit different than the original inputs.nixpkgs, but that’s as good as I can get it to work.

Somebody did the similar thing for darwin as well. Support flake references to patches · Issue #3920 · NixOS/nix · GitHub

2 Likes

The results of builtins.fetchTree is not a derivation, and therefore, can be used to avoid IFD in this situation, at least until the new patch builtin is finally merged.