nixpkgs-architecture / simple-package-paths

Nix RFC draft for auto-calling packages in nixpkgs
18 stars 1 forks source link

feature: simple-package-paths start-date: 2022-09-02 author: Silvan Mosberger co-authors: Nixpkgs Architecture Team shepherd-team: (names, to be nominated and accepted by RFC steering committee) shepherd-leader: (name to be appointed by RFC steering committee) related-issues: https://github.com/NixOS/nixpkgs/pull/211832

Warning This RFC draft is being discussed as RFC 140, please give feedback in that PR instead of this repository.

Summary

Auto-generate trivial top-level attribute definitions in pkgs/top-level/all-packages.nix from a directory structure that matches the attribute name. This makes it much easier to contribute new packages packages, since there's no more guessing needed as to where the package should go, both in the ad-hoc directory categories and in pkgs/top-level/all-packages.nix.

Motivation

Detailed design

This RFC establishes the standard of using pkgs/unit/${shard}/${name} "unit" directories for the definitions of the Nix packages pkgs.${name} in nixpkgs, where shard = toLower (substring 0 2 name). All unit directories are automatically discovered and incorporated into the pkgs set using pkgs.${name} = pkgs.callPackage pkgs/unit/${shard}/${name}/pkg-fun.nix { }.

The following requirements will be checked by CI. This standard must be followed for newly added packages that can satisfy these requirements. A treewide migration to this standard will be performed for existing packages that can satisfy these requirements.

Structure

The pkgs/unit directory must only contain unit directories, and only in subdirectories of the form ${shard}/${name}. Each unit directory must contain at least a pkg-fun.nix file, but may contain arbitrary other files and directories.

This ensures that maintainers don't have to verify this structure manually, which is prone to mistakes.

Only derivations

If pkgs/unit/${shard}/${name} exists, pkgs.${name} must be a derivation that can be built directly with nix-build.

This ensures that people can expect the unit directories to correspond to buildable packages and not functions like pkgs.fetchFromGitHub or pkgs.buildRustCrate.

Stable boundary

Unit directories may only interact with the rest of nixpkgs via the stable pkgs.${name} attributes, not with file references:

The only notable exception to this rule is the pkgs/top-level/all-packages.nix file which may reference the pkg-fun.nix file according to the next requirement.

Custom arguments

If pkgs/top-level/all-packages.nix contains a definition for the attribute ${name} and the unit directory pkgs/unit/${shard}/${name} exists, then the attribute value must be defined as pkgs.callPackage pkgs/unit/${shard}/${name}/pkg-fun.nix args, where args may be a freely chosen expression.

This ensures that even if a package initially doesn't require a custom args, if it later does, it doesn't have to be moved out of the pkgs/unit directory to pass custom arguments.

Examples

To add a new package pkgs.foobar to nixpkgs, one only needs to create the file pkgs/unit/fo/foobar/pkg-fun.nix. No need to find an appropriate category nor to modify pkgs/top-level/all-packages.nix anymore.

With many packages, the pkgs/unit directory may look like this:

pkgs
└── unit
   ├── _0
   │  ├── _0verkill
   │  └── _0x
   ┊
   ├── ch
   │  ├── ChowPhaser
   │  ├── CHOWTapeModel
   │  ├── chroma
   │  ┊
   ┊
   ├── t
   │  └── t
   ┊

Interactions

Drawbacks

Alternatives

Alternate pkgs/unit structure

Alternate pkg-fun.nix filename

Alternate pkgs/unit location

Filepath backwards-compatibility

Additionally have a backwards-compatibility layer for moved paths, such as a symlink pointing from the old to the new location, or for Nix files even a builtins.trace "deprecated" (import ../new/path).

Not having the reference requirement

The reference requirement could be removed, which would allow unit directories to reference files outside themselves, and the other way around. This is not great because it encourages the use of file paths as an API, rather than explicitly exposing functionality from Nix expressions.

Restrict design to try delay issues like "package variants" {#no-variants}

We perceived some uncertainty around package variants that led us to scope these out at first, but we did not identify a real problem that would arise from allowing non-auto-called attributes to reference pkgs/unit files. However, imposing unnecessary restrictions would be counterproductive because:

That said, we did identify risks:

Recommend a callPackage pattern with default arguments

  • While this RFC doesn't address expressions where the second callPackage argument isn't {}, there is an easy way to transition to an argument of {}: For every attribute of the form name = attrs.value; in the argument, make sure attrs is in the arguments of the file, then add name ? attrs.value to the arguments. Then the expression in all-packages.nix can too be auto-called
    • Don't do this for name = value pairs though, that's an alias-like thing

callPackage does not favor the default argument when both a default argument and a value in pkgs exist. Changing the semantics of callPackage is out of scope.

Allow callPackage arguments to be specified in <unit>/args.nix

The idea was to expand the auto-calling logic according to:

Unit directories are automatically discovered and transformed to a definition of the form

# If args.nix doesn't exist
pkgs.${name} = pkgs.callPackage ${unitDir}/pkg-fun.nix {}
# If args.nix does exists
pkgs.${name} = pkgs.callPackage ${unitDir}/pkg-fun.nix (import ${unitDir}/args.nix pkgs);

Pro:

Con:

Unresolved questions

Future work

All of these questions are in scope to be addressed in future discussions in the Nixpkgs Architecture Team:

Definitions