NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.03k stars 14.04k forks source link

Possible to exclude some package from environment.systemPackages? #32405

Open MrSorcus opened 6 years ago

MrSorcus commented 6 years ago

Issue description

How to exclude package from environment.systemPackages without patching nixpkgs source tree? For example i want to remove cifs-utils from custom ISO, but i don't know how.

rnhmjoj commented 6 years ago

Am I missing something? cifs-utils shouldn't be present by default, can't you just not add it?

MrSorcus commented 6 years ago
[root@nixos_iso:~]# ls -lha /nix/store/ | grep "cifs"
dr-xr-xr-x 1 root root     77 Jan  1  1970 dwf5l21li4cq9kr6sb2mp0wnbxwz08k5-cifs-utils-6.6

After build ISO with this nix config - https://gist.github.com/MrSorcus/bd445af65cb055fa7699ace40a541247

rnhmjoj commented 6 years ago

That doesn't necessarily mean it's installed: it may have been pulled in as a dependence of any other derivation that referenced it somehow. You can do nix-store -q --referrers /nix/store/dwf5l21li4cq9kr6sb2mp0wnbxwz08k5-cifs-utils-6.6 to found out which one[s].

MrSorcus commented 6 years ago
[root@nixos_iso:~]# nix-store -q --referrers /nix/store/dwf5l21li4cq9kr6sb2mp0wnbxwz08k5-cifs-utils-6.6
/nix/store/jrzvdn6jb478i5yg2r2lyvndlnaby8i6-system-path

[root@nixos_iso:~]# nix-store -q --referrers /nix/store/jrzvdn6jb478i5yg2r2lyvndlnaby8i6-system-path
/nix/store/0ajgk8fmnmcqn8bzyd2mpv5x9fx0rr9v-unit-systemd-fsck-.service
/nix/store/9yzhdd5zllcpz7fack8h4w8qwsz19q9c-unit-polkit.service
/nix/store/q9plx3bdvghxixy7vrjyhx2vbrw8493v-dbus-1
/nix/store/dszlldx4a82fv5d1p9amnnmkhi12d0c4-etc
/nix/store/jxg1cd1ywnccpl0r5nda2nirg3r3yxy1-nixos-system-nixos_iso-18.03.git.4c1cd74
[root@nixos_iso:~]# ls -lha /nix/store | grep "python"
dr-xr-xr-x 1 root root     96 Jan  1  1970 9n2npaz7xy8b4q0a8k28nr3sjzfy625i-python-2.7.14

[root@nixos_iso:~]# nix-store -q --referrers /nix/store/9n2npaz7xy8b4q0a8k28nr3sjzfy625i-python-2.7.14/
/nix/store/9n2npaz7xy8b4q0a8k28nr3sjzfy625i-python-2.7.14
/nix/store/vzhpw0jxm2ys8zg61bbi8d0qgfrrgr80-talloc-2.1.8

[root@nixos_iso:~]# nix-store -q --referrers /nix/store/vzhpw0jxm2ys8zg61bbi8d0qgfrrgr80-talloc-2.1.8
/nix/store/vzhpw0jxm2ys8zg61bbi8d0qgfrrgr80-talloc-2.1.8
/nix/store/dwf5l21li4cq9kr6sb2mp0wnbxwz08k5-cifs-utils-6.6

[root@nixos_iso:~]# nix-store -q --referrers /nix/store/dwf5l21li4cq9kr6sb2mp0wnbxwz08k5-cifs-utils-6.6
/nix/store/jrzvdn6jb478i5yg2r2lyvndlnaby8i6-system-path

I found that python 2.7.14 used only by talloc, that used by cifs-utils, but i can't found options for disabling them.

MrSorcus commented 6 years ago

https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/config/system-path.nix Here nothing about cifs-utils...

rnhmjoj commented 6 years ago

I built a vm with your config and I couldn't find cifs-utils in the nix store. It probably means it's a dependency of something related to the live CD configuration.

MrSorcus commented 6 years ago

I build ISO image only. Not VM. Steps:

git clone https://github.com/NixOS/nixpkgs.git
cd nixpkgs/nixos
nix-build -A config.system.build.isoImage -I nixos-config=../../nixos_cd_iso.nix default.nix

I found some info about cifs here - https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/tasks/filesystems/cifs.nix Maybe something calling all nix files from nixpkgs/nixos/modules/tasks/filesystems directory?

rnhmjoj commented 6 years ago

Yes, that's it. installation-cd-base.nix imports profiles/base.nix which defines

 boot.supportedFilesystems = [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" "cifs" ];

filesystems/cifs.nix then adds cifs-utils to the system.fsPackages.

rnhmjoj commented 6 years ago

You could set

boot.supportedFilesystems = lib.mkForce [ "btrfs" "reiserfs" "vfat" "f2fs" "xfs" "ntfs" ];

Or don't use installation-cd-base.nix at all and define your base configuration.

MrSorcus commented 6 years ago

You right, it's working. But still no answer about excluding packages from predefined systemPackages. cifs-utils was just an example. But this not the only one package, that i want to remove/replace in ISO.

rnhmjoj commented 6 years ago

I don't think there is a way besides using lib.mkForce [...]. Why do you care so much? Are you trying to make a stripped down image?

MrSorcus commented 6 years ago

Just interesting. Interesting in features provided by NixOS NixOS is a wonderful project, but it is very unfinished. Too many places where instead of simplification you get complications. NixOS looks simple only at the beginning of the path. And the nix syntax only complicates everything. I have a lot of free time and I could contribute in nixpkgs, but nix does not dispose of this. NixOS obviously needs serious refactoring.

lukateras commented 6 years ago

@rnhmjoj It'd be great to be able to do that, actually. The defining feature of NixOS is exactly that: not every artifact in Nix store is pulled into system environment.

In other words, NixOS has a concept of end user dependencies, while most other distros don't.

Another use case: services.xserver.desktopManager.xfce is rather bloated, and there is no excludePackages option that is sometimes present in such case (I should really get to that). It would be neat to be able to exclude some package that is pulled into system environment, say, mousepad:

{ config, lib, pkgs, ... }:

{
  environment.systemPackages =
    lib.mkForce (lib.subtractLists [ pkgs.xfce.mousepad ] config.environment.systemPackages);
}

The problem is here is that there is no way that I know of to self-reference a module option without triggering infinite recursion. If you know, do tell me!

I think it should not be semantically ambiguous to at least be able to reference an option value with lower priority, but that would probably require a change in the way overrides are stored (and called).

rnhmjoj commented 6 years ago

The problem is here is that there is no way that I know of to self-reference a module option without triggering infinite recursion. If you know, do tell me!

It doesn't seem possible without changing either they way Nix works or the sources in nixpkgs. @Infinisil noted that the apply argument of mkOption can be used to implement this filter but still one need to change the expression in nixpkgs.

Another use case: services.xserver.desktopManager.xfce is rather bloated

In this case one or more options could be implemented to control the set of packages. Actually there are a few already.

I'm afraid there is no other way to go beside tracking where the package came from and disabling it if possible.

stale[bot] commented 4 years ago

Thank you for your contributions.

This has been automatically marked as stale because it has had no activity for 180 days.

If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity.

Here are suggestions that might help resolve this more quickly:

  1. Search for maintainers and people that previously touched the related code and @ mention them in a comment.
  2. Ask on the NixOS Discourse.
  3. Ask on the #nixos channel on irc.freenode.net.
infinisil commented 4 years ago

This is still relevant. I think I have a good idea for how to solve it: Instead of environment.systemPackages being a list, we make it an attribute set, let's call it environment.systemPackageAttrs to not be confusing. This would be defined like

{
  options.environment.systemPackageAttrs = mkOption {
    type = attrsOf (nullOr package);
    default = {};
  };

  config.environment.systemPackages =
    attrValues (filterAttrs (n: v: v != null)
    config.environment.systemPackageAttrs);
}

With this you can add packages with

{
  environment.systemPackageAttrs = {
    inherit (pkgs)
      foo
      bar
      baz;
  };
}

You can also remove packages with

{
  environment.systemPackageAttrs.foo = mkForce null;
}
davidak commented 4 years ago

My goal was to create a minimal NixOS image, since a LXC image with nginx was about 600 MB!

I asked where the default packages are defined: https://discourse.nixos.org/t/where-are-default-programs-defined/7757/4

Answer: https://github.com/NixOS/nixpkgs/blob/e0ece5aebe886d11c9e14f054e0af3cec3a60636/nixos/modules/config/system-path.nix#L10-L45

And how to overwrite that with an empty list. There seem to be no solution right now, but this issue seem related.

My idea is to add a new option environment.defaultPackages with packages a user would expect from a minimal linux. But they can just overwrite it environment.defaultPackages = [];. But that needs to be tested and should not break the system!

I guess in best case requiredPackages would not exist, since it defines dependencies implicitly. At least it should not contain packages that are actually not required. So defaultPackages is needed. environment.systemPackages can just be empty then.

I removed 3 items from requiredPackages and it turned out that some packages had implicit dependencies on them. https://github.com/NixOS/nixpkgs/pull/91213

@Infinisil your proposed overwriting mechanic seems very complicated and not userfriendly. Something named systemPackageAttrs is not self explaining to new NixOS users. I would prefer that we have a list like defaultPackages and remove items from the list. That should be intuitive to anyone.

I would add such changes for 21.03, so we have enough time to test it.

What to you think?

infinisil commented 4 years ago

The thing with defaultPackages is that it again has the very same problem: You can't remove a single package from it without redefining the whole list. For your use case of having a minimal system it might work well, but for people who just want to remove a single package it doesn't. I think this might be a decent temporary partial solution though and I wouldn't be opposed to a PR.

Because this is a problem for all listOf options though, I'm intending to soon create an RFC to deprecate the listOf type completely, while introducing a lot of replacement types with better semantics. I think it might even be possible to even keep the existing environment.systemPackages in a fully backwards compatible way while still allowing overriding of anything.

xaverdh commented 4 years ago

+1 on the defaultPackages idea. We really need to decouple

what we test to yield a working system

from

what people might want in a standard installation

Could also be done without an additional option of course, but I think its nice to have a place where this distinction is reified in the source.

stale[bot] commented 3 years ago

I marked this as stale due to inactivity. → More info

winston0410 commented 3 years ago

The thing with defaultPackages is that it again has the very same problem: You can't remove a single package from it without redefining the whole list. For your use case of having a minimal system it might work well, but for people who just want to remove a single package it doesn't. I think this might be a decent temporary partial solution though and I wouldn't be opposed to a PR.

Because this is a problem for all listOf options though, I'm intending to soon create an RFC to deprecate the listOf type completely, while introducing a lot of replacement types with better semantics. I think it might even be possible to even keep the existing environment.systemPackages in a fully backwards compatible way while still allowing overriding of anything.

+1

Would using set a good idea there? And provide a Null package so that it can replace the original default package from the set, equals to removing it.

stale[bot] commented 2 years ago

I marked this as stale due to inactivity. → More info

ambroisie commented 2 years ago

Still relevant.

Fryuni commented 1 year ago

This issue has become a major problem for me since some packages installed with xfce conflict with other things in my system and I can't remove them.

I have a somewhat simpler solution, what if instead of instead of trying to change how the systemPackages or default modules in particular are defined we solve this for all merged properties on module resolution.

Currently we have lib.mkOrder to ensure a list is merged in a particular order and lib.mkForce to ignore the value from any module that is not also a lib.mkForce. That is implemented here: https://github.com/NixOS/nixpkgs/blob/9ecb3b8e4440db6051202d5183139c2608ea8ba4/lib/modules.nix#L726-L739

My proposal is to add a lib.mkExcluded, which would remove entries from the resolved list, but could still be overruled by lib.mkForce.

It would be simple give the power to the users to remove whatever they wanted. There is a slight inconvenience that if a user wants to add package A and remove package B it would need to be done in two separate modules:

{ pkgs, ... }:
{
  import = [ ./excludedPackages.nix ];
  environment.systemPackages = [ pkgs.A ];
}

# File: excludedPackages.nix
{ pkgs, lib, ... }:
{
  environment.systemPackages = lib.mkExcluded [ pkgs.B ];
}

What do you all think?

I'll make it in a fork for now since I need this functionality, but I'll if open a PR if this solution is acceptable.

Fryuni commented 1 year ago

Other possible names would be mkNegative, mkRemoved, mkWithout, mkLess, mkDrop,...

hinshun commented 1 year ago

@Fryuni do you have your fork changes pushed anywhere?

Fryuni commented 1 year ago

I don't think I have pushed it anywhere. I remember that I got it working (although not properly tested for conflicts with other use cases) but later I switched from xfce, so I no longer have the conflict.

I'll see if I can find it and push to GH, then I'll link it here.

SeriousBusiness100 commented 1 year ago

Tangental to XFCE

infinisil commented 1 year ago

There's now https://github.com/NixOS/nixpkgs/pull/255086 which would fix this!