llakala / nixos

My NixOS config
3 stars 1 forks source link

Make `nix run` commands allow unfree #47

Closed llakala closed 2 weeks ago

llakala commented 2 weeks ago

Currently, we have all our settings for pkgs declared when we import pkgs and pkgs-unstable via myLib. However, this makes it so nix run uses the version nixpkgs from our inputs, which doesn't have allowUnfree applied to it.

llakala commented 2 weeks ago

I'm splitting this into two issues. There's really two separate problems here: flake registry stuff for nix run, and configuration for use of pkgs and pkgs-unstable within the configuration. That second one will now be at #48. This issue will be limited to finding a workaround for the registry stuff.

llakala commented 2 weeks ago

Thanks to @frontear educating me, I know more about the flake registry. I also now dislike it.

See, nix.registry.nixpkgs.flake = inputs.nixpkgs; won't do anything for actually applying configuration options. It just changes the version of nixpkgs we're referencing -- the path.

So, how do we make the nixpkgs referenced in nix run allow unfree?

Oh, it's simple. We don't.

Well, at least, there's no supported way. But I'm one for workarounds. These include:

That last one sounds simple in theory. Sadly, the execution is a bit more complicated. Time to over-explain, otherwise I'll never be able to remember this:

Fancy magic here

See, the import nixpkgs thing has to know which store path to grab nixpkgs from. So, we'll have to pass that into the file.

Oh, but can't I just pass in inputs? Problem solved.

Well, yes, but no. Apparently, we have to make sure to "resolve inputs beforehand". My understanding of this is:

When writing to the nix store, we have to make sure we don't write down a $REPLACEMEATCOMPILETIME. Instead, it has to be written with the input value.

But, if I can't pass in inputs, what can I do?

Well, the problem isn't passing in inputs. It's making sure that we write to the nix store with the input path replaced before writing it down . With this code snippet:

runCommandLocal "make-nix-thingy" {} 
''
  substituteInPlace @nixpkgs@ ${inputs.nixpkgs}
''

This will apparently work.

Frontear commented 2 weeks ago

Hi 👋

Let me quickly add that last snippet of runCommandLocal is incomplete, but it should work completely fine in theory due to how nix evaluations will handle the runCommandLocal.

If you'd like I can run a test on this type of thing and send you a complete reproducible example of what you're looking for.

llakala commented 2 weeks ago

Hi 👋

Let me quickly add that last snippet of runCommandLocal is incomplete, but it should work completely fine in theory due to how nix evaluations will handle the runCommandLocal.

If you'd like I can run a test on this type of thing and send you a complete reproducible example of what you're looking for.

That'd be awesome! Thanks so much for all your help ♥️

Frontear commented 2 weeks ago

I had a gut feeling I was missing something, and I just discovered it during my testing. Our idea would have been fine (maybe) if nix run and the other nix cli used a default.nix, but they do not! They use a flake.nix, which complicates the matter pretty significantly.

Not to worry though, I figured a very easy solution (it kind of does the same thing as https://github.com/numtide/nixpkgs-unfree but with more granular control).

This code might look wack as FUCK but this will work, I've confirmed it on my own system:

{
  path,
  runCommandLocal,
}:
runCommandLocal "nixpkgs-configured" { src = path; } ''
  mkdir -p $out

  substitute $src/flake.nix $out/flake.nix \
    --replace-fail "{ inherit system; }" "{ inherit system; config.allowUnfree = true; }"

  cp --update=none -Rt $out $src/*
''

Use this in your nixos configuration like this:

# nixpkgs.nix is just the above file copy-pasted
nix.registry.nixpkgs.flake = pkgs.callPackage ./nixpkgs.nix {};

Then when your system is built, go ahead and do nix run nixpkgs#google-chrome or some other unfree package, and boom, it works.

llakala commented 2 weeks ago

I had a gut feeling I was missing something, and I just discovered it during my testing. Our idea would have been fine (maybe) if nix run and the other nix cli used a default.nix, but they do not! They use a flake.nix, which complicates the matter pretty significantly.

Not to worry though, I figured a very easy solution (it kind of does the same thing as numtide/nixpkgs-unfree but with more granular control).

This code might look wack as FUCK but this will work, I've confirmed it on my own system:

{
  path,
  runCommandLocal,
}:
runCommandLocal "nixpkgs-configured" { src = path; } ''
  mkdir -p $out

  substitute $src/flake.nix $out/flake.nix \
    --replace-fail "{ inherit system; }" "{ inherit system; config.allowUnfree = true; }"

  cp --update=none -Rt $out $src/*
''

Use this in your nixos configuration like this:

# nixpkgs.nix is just the above file copy-pasted
nix.registry.nixpkgs.flake = pkgs.callPackage ./nixpkgs.nix {};

Then when your system is built, go ahead and do nix run nixpkgs#google-chrome or some other unfree package, and boom, it works.

Got it working!

I did have to make one small edit:

nix.registry = lib.mkForce
{
  nixpkgs.flake = pkgs.callPackage ./nixpkgs/unfree.nix {}; # Makes `nix run` commands use unfree
};

If I didn't use lib.mkForce, I got this error for conflicting statements:

       error: The option `nix.registry.nixpkgs.to.path' has conflicting definition values:
       - In `/nix/store/m1g5a7agja7si7y9l1lzwhp3capbv7x9-source/nixos/modules/config/nix-flakes.nix': "/nix/store/xhf7lw9yrn6jlwfnvwkkhfzlvap04rjq-nixpkgs-configured"
       - In `/nix/store/m1g5a7agja7si7y9l1lzwhp3capbv7x9-source/nixos/modules/misc/nixpkgs-flake.nix': "/nix/store/m1g5a7agja7si7y9l1lzwhp3capbv7x9-source"
       Use `lib.mkForce value` or `lib.mkDefault value` to change the priority on any of these definitions.
Finished at 09:59:59 after 17s

i thought this would go away when I stopped doing nixpkgs.pkgs = pkgs;, but it was still happening.

One question: is there any way to specify an input to base off, as we'd typically do with nix.registry.nixpkgs.flake? I assume that the current approach is based off whatever version of nixpkgs the registry uses by default: but if I want to have a registry entry for both nixpkgs and nixpkgs-unstable, I'd need to find a way to specify a version from inputs.

Frontear commented 2 weeks ago

The path attribute is a path to the nix store containing the root of the nixpkgs source. You can replace it with any input and itll extrapolate the .outPath of that input.

Say you want to have nixpkgs-unstable, you simply do pkgs.callPackage ./nixpkgs.nix { path = "${inputs.nixpkgs-unstable}"; }

llakala commented 2 weeks ago

The path attribute is a path to the nix store containing the root of the nixpkgs source. You can replace it with any input and itll extrapolate the .outPath of that input.

Say you want to have nixpkgs-unstable, you simply do pkgs.callPackage ./nixpkgs.nix { path = "${inputs.nixpkgs-unstable}"; }

Works perfectly! Thanks so much again, this is exactly what I needed and is super customizable. Someday I'll make a blog post about this and give you all the credit in the world.