This WIP project houses the hacky (but increasingly less so) scripts that I use to help with the maintenance of meta.mainProgram attributes for packages in nixpkgs, with the goal of increasing the number of packages that function with nix run.
Currently the project provides 3 primary scripts,
add-mpsadd-mps-interactiverm-mps
all of which take two arguments, a path to nixpkgs on the local system, and an attribute path to a package set in nixpkg, e.g., '[ "perlPackages" ]'.
Usage examples:
nix run .#add-mps -- ~/Code/nixpkgs '[ "pkgs" ]'
# or since it's the default package
nix run . -- ~/Code/nixpkgs '[ "pkgs" ]'
The add-mps script finds all packages in the given package set that don't have meta.mainProgram defined and then:
- Checks whether the official binary cache contains the store path for each package using
nix store ls; and- if it does, it retrieves the names of all executables located in
bin/; - otherwise, it uses
hydra checkto see if the package failed to build on Hydra; and- if it didn't, and the store path for the package isn't listed in
failed-builds.txt, it builds the package locally; and- if it succeeds, it retrieves the names of all executables located in
bin/; - otherwise, it appends the store path of the package to
failed-builds.txt.
- if it succeeds, it retrieves the names of all executables located in
- if it didn't, and the store path for the package isn't listed in
- if it does, it retrieves the names of all executables located in
- If a single executable was found, and the name of that executable differs from the packages
name(more specifically the result ofbuiltins.parseDrvName name) orpname, it attempts to insert ameta.mainProgramdefinition into the appropriate file; and- if is succeeds, it prints a message to that effect;
- otherwise, it prints a message with info helpful for trying to insert the
meta.mainProgramdefinition manually.
Known issues:
- The meta attribute under which the script attempts to insert the
meta.mainProgamdefinition spans multiple lines. In this case the script will insert themeta.mainProgamdefinition on the incorrect line producing a syntax error in the file. - The meta attribute under which the script inserts the
meta.mainProgamdefinition is in a meta block shared by unrelated packages. For example, it used to be the case that for packages in forperlPackages, if the package didn't have meta attributes defined, the script would insert themeta.mainProgamdefinition intopkgs/development/perl-modules/generic/default.nix, which applies to all packages inperlPackages. This case is now handled, but there are likely others that aren't. - If the package definition is auto-generated, the inserted
meta.mainProgramdefinition won't be helpful since it will be overwritten the next time the package definitions are generated. Exceptions arehaskellPackageswhich the script explicitly skips, andnodePackageswhich has it's own mechanism for addingmeta.mainProgramdefinitions which this script knows how to handle. - Sometimes the executables available for a package differ between platforms, e.g.,
docker-credential-helpersprovides a single executable on Darwin but multiple executables on Linux. - Sometimes the name of an executable changes based on the packages definition. The most common example of this is when the executables name includes the specific version of the package. In these cases the
meta.mainProgramdefinition should be manually edited to ensure it remains correct, e.g.,mainProgram = "foo_${version}";. - Sometimes a package includes a single executable whose name differs from the packages
nameorpname, but it really doesn't make sense at all for that executable the be the thing that would be run if someone tried tonix runthe package. In these cases, the package should be added to lib/package-to-skip.nix.
As such, always make sure you review the changes made by this script to ensure they are valid. One way to catch problematic additions of meta.mainProgram definitions by this script, is to run rm-mps after running add-mps.
The add-mps-interactive does the same thing as add-mps up to step 2, at which point it presents a selection prompt (if executables where found, and none of them matched the package's name or pname), that list all executables found as well as "Skip" and "Exclude". If the user selects,
- one of the listed executables, it then attempts to insert the
meta.mainProgramdefinition into the appropriate file; - "Skip", it does nothing an moves on to the next package;
- "Exclude", it adds an entry to lib/package-to-skip.nix for the package, which will cause that package to be excluded from future runs of the scripts in this project.
Usage example:
nix run .#rm-mps -- ~/Code/nixpkgs '[ "pkgs" ]'
The rm-mps script finds all packages in the given package set that have meta.mainProgram defined and then,
- it attempts to finds all executables provided for each package in the same way as
add-mps; and - if it could query the store path for the package; and
- one of the following conditions is met:
- the
bin/directory doesn't exist; - the
bin/directory is empty; - one of the executables in
bin/match the package'snameorpname; or - none of the executables in
bin/match the definedmainProgram;
- the
- the
meta.mainProgramline for the package is removed from the appropriate file.
- one of the following conditions is met:
Known issues:
- Sometimes multiple variations of packages exist in
nixpkgsthat are generated by, e.g., overriding a particular package, or calling a function that generates the package derivation with different arguments. In these cases, sometimes one of the packages'nameorpnamematch an executable found in thebin/triggering the removal of themeta.mainProgramfor that package, which due to it being shared with other packages who'snameorpnamedon't match for some reason, would cause those packages to stop working withnix run.
As such, always make sure you review the changes made by this script to ensure they are valid.