Skip to content

Commit

Permalink
haskell: support cross in generateOptparseApplicativeCompletions
Browse files Browse the repository at this point in the history
Deprecate haskell.lib{,.compose}.generateOptparseApplicativeCompletion*
in favor of the newly added
haskell.packages.*.generateOptparseApplicativeCompletions (plural!)
which takes into account whether we are cross-compiling or not. If we
are, generating completions is disabled, since we can't execute software
built for a different platform.

The move is necessary, so we can receive the /same/ stdenv as the
package we are overriding in order to accurately check whether we can
execute produced binaries.

Resolves #174040.
Resolves #49648.
  • Loading branch information
sternenseemann committed Oct 6, 2022
1 parent e7b47a7 commit ac1f1ad
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 50 deletions.
21 changes: 21 additions & 0 deletions nixos/doc/manual/from_md/release-notes/rl-2211.section.xml
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,27 @@
module removed, due to lack of maintainers.
</para>
</listitem>
<listitem>
<para>
<literal>generateOptparseApplicativeCompletions</literal> and
<literal>generateOptparseApplicativeCompletion</literal> from
<literal>haskell.lib.compose</literal> (and
<literal>haskell.lib</literal>) have been deprecated in favor
of <literal>generateOptparseApplicativeCompletions</literal>
(plural!) as provided by the haskell package sets (so
<literal>haskellPackages.generateOptparseApplicativeCompletions</literal>
etc.). The latter allows for cross-compilation (by
automatically disabling generation of completion in the cross
case). For it to work properly you need to make sure that the
function comes from the same context as the package you are
trying to override, i.e. always use the same package set as
your package is coming from or – even better – use
<literal>self.generateOptparseApplicativeCompletions</literal>
if you are overriding a haskell package set. The old functions
are retained for backwards compatibility, but yield are
warning.
</para>
</listitem>
<listitem>
<para>
The <literal>services.graphite.api</literal> and
Expand Down
9 changes: 9 additions & 0 deletions nixos/doc/manual/release-notes/rl-2211.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,15 @@ Available as [services.patroni](options.html#opt-services.patroni.enable).

- virtlyst package and `services.virtlyst` module removed, due to lack of maintainers.

- `generateOptparseApplicativeCompletions` and `generateOptparseApplicativeCompletion` from `haskell.lib.compose`
(and `haskell.lib`) have been deprecated in favor of `generateOptparseApplicativeCompletions` (plural!) as
provided by the haskell package sets (so `haskellPackages.generateOptparseApplicativeCompletions` etc.).
The latter allows for cross-compilation (by automatically disabling generation of completion in the cross case).
For it to work properly you need to make sure that the function comes from the same context as the package
you are trying to override, i.e. always use the same package set as your package is coming from or – even
better – use `self.generateOptparseApplicativeCompletions` if you are overriding a haskell package set.
The old functions are retained for backwards compatibility, but yield are warning.

- The `services.graphite.api` and `services.graphite.beacon` NixOS options, and
the `python3.pkgs.graphite_api`, `python3.pkgs.graphite_beacon` and
`python3.pkgs.influxgraph` packages, have been removed due to lack of upstream
Expand Down
30 changes: 16 additions & 14 deletions pkgs/development/haskell-modules/configuration-common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ self: super: {

# 2020-06-05: HACK: does not pass own build suite - `dontCheck`
# 2022-06-17: Use hnix-store 0.5 until hnix 0.17
hnix = generateOptparseApplicativeCompletion "hnix" (dontCheck (
hnix = self.generateOptparseApplicativeCompletions [ "hnix" ] (dontCheck (
super.hnix.overrideScope (hself: hsuper: {
hnix-store-core = hself.hnix-store-core_0_5_0_0;
hnix-store-remote = hself.hnix-store-remote_0_5_0_0;
Expand Down Expand Up @@ -719,7 +719,7 @@ self: super: {
# updated dependencies (haskeline and megaparsec) which can be
# removed when the next idris release (1.3.4 probably) comes
# around.
idris = generateOptparseApplicativeCompletion "idris"
idris = self.generateOptparseApplicativeCompletions [ "idris" ]
(doJailbreak (dontCheck super.idris));

# https://github.com/pontarius/pontarius-xmpp/issues/105
Expand Down Expand Up @@ -998,14 +998,14 @@ self: super: {
servant-auth-server = doJailbreak super.servant-auth-server;

# Generate cli completions for dhall.
dhall = generateOptparseApplicativeCompletion "dhall" super.dhall;
dhall = self.generateOptparseApplicativeCompletions [ "dhall" ] super.dhall;
# For reasons that are not quire clear 'dhall-json' won't compile without 'tasty 1.4' due to its tests
# https://github.com/commercialhaskell/stackage/issues/5795
# This issue can be mitigated with 'dontCheck' which skips the tests and their compilation.
dhall-json = generateOptparseApplicativeCompletions ["dhall-to-json" "dhall-to-yaml"] (dontCheck super.dhall-json);
dhall-nix = generateOptparseApplicativeCompletion "dhall-to-nix" super.dhall-nix;
dhall-yaml = generateOptparseApplicativeCompletions ["dhall-to-yaml-ng" "yaml-to-dhall"] super.dhall-yaml;
dhall-nixpkgs = generateOptparseApplicativeCompletion "dhall-to-nixpkgs" super.dhall-nixpkgs;
dhall-json = self.generateOptparseApplicativeCompletions ["dhall-to-json" "dhall-to-yaml"] (dontCheck super.dhall-json);
dhall-nix = self.generateOptparseApplicativeCompletions [ "dhall-to-nix" ] super.dhall-nix;
dhall-yaml = self.generateOptparseApplicativeCompletions ["dhall-to-yaml-ng" "yaml-to-dhall"] super.dhall-yaml;
dhall-nixpkgs = self.generateOptparseApplicativeCompletions [ "dhall-to-nixpkgs" ] super.dhall-nixpkgs;

# https://github.com/haskell-hvr/netrc/pull/2#issuecomment-469526558
netrc = doJailbreak super.netrc;
Expand All @@ -1014,7 +1014,7 @@ self: super: {
hgettext = doJailbreak super.hgettext;

stack =
generateOptparseApplicativeCompletion "stack"
self.generateOptparseApplicativeCompletions [ "stack" ]
# stack has a bunch of constraints in its .cabal file that don't seem to be necessary
(doJailbreak
(super.stack.overrideScope (self: super: {
Expand Down Expand Up @@ -1067,7 +1067,7 @@ self: super: {
hoopl = dontCheck super.hoopl;

# Generate shell completion for spago
spago = generateOptparseApplicativeCompletion "spago" super.spago;
spago = self.generateOptparseApplicativeCompletions [ "spago" ] super.spago;

# 2020-06-05: HACK: Package can not pass test suite,
# Upstream Report: https://github.com/kcsongor/generic-lens/issues/83
Expand Down Expand Up @@ -1505,7 +1505,7 @@ self: super: {
# PATH.
# - Patch can be removed on next package set bump
update-nix-fetchgit = let deps = [ pkgs.git pkgs.nix pkgs.nix-prefetch-git ];
in generateOptparseApplicativeCompletion "update-nix-fetchgit" (overrideCabal
in self.generateOptparseApplicativeCompletions [ "update-nix-fetchgit" ] (overrideCabal
(drv: {
buildTools = drv.buildTools or [ ] ++ [ pkgs.buildPackages.makeWrapper ];
postInstall = drv.postInstall or "" + ''
Expand Down Expand Up @@ -1633,7 +1633,9 @@ self: super: {
http-media = doJailbreak super.http-media;

# 2022-03-19: strict upper bounds https://github.com/poscat0x04/hinit/issues/2
hinit = doJailbreak (generateOptparseApplicativeCompletion "hi" (super.hinit.override { haskeline = self.haskeline_0_8_2; }));
hinit = doJailbreak
(self.generateOptparseApplicativeCompletions [ "hi" ]
(super.hinit.override { haskeline = self.haskeline_0_8_2; }));

# 2022-03-19: Keeping jailbreak because of tons of strict bounds: https://github.com/snapframework/snap/issues/220
snap = doJailbreak super.snap;
Expand Down Expand Up @@ -1676,7 +1678,7 @@ self: super: {
# waiting for aeson bump
servant-swagger-ui-core = doJailbreak super.servant-swagger-ui-core;

hercules-ci-agent = generateOptparseApplicativeCompletion "hercules-ci-agent" super.hercules-ci-agent;
hercules-ci-agent = self.generateOptparseApplicativeCompletions [ "hercules-ci-agent" ] super.hercules-ci-agent;

# Test suite doesn't compile with aeson 2.0
# https://github.com/hercules-ci/hercules-ci-agent/pull/387
Expand All @@ -1687,7 +1689,7 @@ self: super: {
(overrideCabal (drv: { hydraPlatforms = super.hercules-ci-cli.meta.platforms; }))
# See hercules-ci-optparse-applicative in non-hackage-packages.nix.
(addBuildDepend super.hercules-ci-optparse-applicative)
(generateOptparseApplicativeCompletion "hci")
(self.generateOptparseApplicativeCompletions [ "hci" ])
];

pipes-aeson = appendPatches [
Expand Down Expand Up @@ -2571,7 +2573,7 @@ in {
# likely be removed when purescript-0.14.6 is released.
doJailbreak
# Generate shell completions
(generateOptparseApplicativeCompletion "purs")
(self.generateOptparseApplicativeCompletions [ "purs" ])
];

purescript-cst = purescriptStOverride super.purescript-cst;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ self: super: {
}) (doJailbreak super.language-haskell-extract);

# hnix 0.9.0 does not provide an executable for ghc < 8.10, so define completions here for now.
hnix = generateOptparseApplicativeCompletion "hnix"
hnix = self.generateOptparseApplicativeCompletions [ "hnix" ]
(overrideCabal (drv: {
# executable is allowed for ghc >= 8.10 and needs repline
executableHaskellDepends = drv.executableToolDepends or [] ++ [ self.repline ];
Expand Down
14 changes: 7 additions & 7 deletions pkgs/development/haskell-modules/configuration-nix.nix
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,12 @@ self: super: builtins.intersectAttrs super {
sfml-audio = appendConfigureFlag "--extra-include-dirs=${pkgs.openal}/include/AL" super.sfml-audio;

# avoid compiling twice by providing executable as a separate output (with small closure size)
niv = enableSeparateBinOutput (generateOptparseApplicativeCompletion "niv" super.niv);
niv = enableSeparateBinOutput (self.generateOptparseApplicativeCompletions [ "niv" ] super.niv);
ghcid = enableSeparateBinOutput super.ghcid;
ormolu = generateOptparseApplicativeCompletion "ormolu" (enableSeparateBinOutput super.ormolu);
ormolu = self.generateOptparseApplicativeCompletions [ "ormolu" ] (enableSeparateBinOutput super.ormolu);

# Generate shell completion.
cabal2nix = generateOptparseApplicativeCompletion "cabal2nix" super.cabal2nix;
cabal2nix = self.generateOptparseApplicativeCompletions [ "cabal2nix" ] super.cabal2nix;

arbtt = overrideCabal (drv: {
# The test suite needs the packages's executables in $PATH to succeed.
Expand Down Expand Up @@ -814,7 +814,7 @@ self: super: builtins.intersectAttrs super {
install -D man/pnbackup.1 $out/share/man/man1/pnbackup.1
'' + (drv.postInstall or "");
})
(generateOptparseApplicativeCompletion "pnbackup" super.pinboard-notes-backup);
(self.generateOptparseApplicativeCompletions [ "pnbackup" ] super.pinboard-notes-backup);

# Pass the correct libarchive into the package.
streamly-archive = super.streamly-archive.override { archive = pkgs.libarchive; };
Expand Down Expand Up @@ -875,7 +875,7 @@ self: super: builtins.intersectAttrs super {
}) super.tophat;

# Runtime dependencies and CLI completion
nvfetcher = generateOptparseApplicativeCompletion "nvfetcher" (overrideCabal
nvfetcher = self.generateOptparseApplicativeCompletions [ "nvfetcher" ] (overrideCabal
(drv: {
# test needs network
doCheck = false;
Expand All @@ -889,7 +889,7 @@ self: super: builtins.intersectAttrs super {

rel8 = addTestToolDepend pkgs.postgresql super.rel8;

cachix = generateOptparseApplicativeCompletion "cachix" (super.cachix.override { nix = pkgs.nixVersions.nix_2_9; });
cachix = self.generateOptparseApplicativeCompletions [ "cachix" ] (super.cachix.override { nix = pkgs.nixVersions.nix_2_9; });

hercules-ci-agent = super.hercules-ci-agent.override { nix = pkgs.nixVersions.nix_2_9; };
hercules-ci-cnix-expr =
Expand Down Expand Up @@ -917,7 +917,7 @@ self: super: builtins.intersectAttrs super {
# to arbitrary files in $HOME. This doesn't either not achieve anything
# or even fail, so we prevent it and install everything necessary ourselves.
# See also: https://hackage.haskell.org/package/cli-setup-0.2.1.4/docs/src/Distribution.CommandLine.html#setManpathGeneric
ats-format = generateOptparseApplicativeCompletion "atsfmt" (
ats-format = self.generateOptparseApplicativeCompletions [ "atsfmt" ] (
justStaticExecutables (
overrideCabal (drv: {
# use vanilla Setup.hs
Expand Down
45 changes: 19 additions & 26 deletions pkgs/development/haskell-modules/lib/compose.nix
Original file line number Diff line number Diff line change
Expand Up @@ -418,23 +418,14 @@ rec {
builtins.listToAttrs (map toKeyVal haskellPaths);

addOptparseApplicativeCompletionScripts = exeName: pkg:
builtins.trace "addOptparseApplicativeCompletionScripts is deprecated in favor of generateOptparseApplicativeCompletion. Please change ${pkg.name} to use the latter or its plural form."
(generateOptparseApplicativeCompletion exeName pkg);
lib.warn "addOptparseApplicativeCompletionScripts is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions. Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!"
(__generateOptparseApplicativeCompletion exeName pkg);

/*
Modify a Haskell package to add shell completion scripts for the
given executable produced by it. These completion scripts will be
picked up automatically if the resulting derivation is installed,
e.g. by `nix-env -i`.
Invocation:
generateOptparseApplicativeCompletion command pkg
command: name of an executable
pkg: Haskell package that builds the executables
INTERNAL function retained for backwards compatibility, use
haskell.packages.*.generateOptparseApplicativeCompletions instead!
*/
generateOptparseApplicativeCompletion = exeName: overrideCabal (drv: {
__generateOptparseApplicativeCompletion = exeName: overrideCabal (drv: {
postInstall = (drv.postInstall or "") + ''
bashCompDir="''${!outputBin}/share/bash-completion/completions"
zshCompDir="''${!outputBin}/share/zsh/vendor-completions"
Expand All @@ -453,20 +444,22 @@ rec {
});

/*
Modify a Haskell package to add shell completion scripts for the
given executables produced by it. These completion scripts will be
picked up automatically if the resulting derivation is installed,
e.g. by `nix-env -i`.
Invocation:
generateOptparseApplicativeCompletions commands pkg
commands: name of an executable
pkg: Haskell package that builds the executables
Retained for backwards compatibility.
Use haskell.packages.*.generateOptparseApplicativeCompletions
which is cross aware instead.
*/
generateOptparseApplicativeCompletions = commands: pkg:
pkgs.lib.foldr generateOptparseApplicativeCompletion pkg commands;
lib.warnIf (lib.isInOldestRelease 2211) "haskellLib.generateOptparseApplicativeCompletions is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions. Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!"
(pkgs.lib.foldr __generateOptparseApplicativeCompletion pkg commands);

/*
Retained for backwards compatibility.
Use haskell.packages.*.generateOptparseApplicativeCompletions
which is cross aware instead.
*/
generateOptparseApplicativeCompletion = command: pkg:
lib.warnIf (lib.isInOldestRelease 2211) "haskellLib.generateOptparseApplicativeCompletion is deprecated in favor of haskellPackages.generateOptparseApplicativeCompletions (plural!). Please change ${pkg.name} to use the latter and make sure it uses its matching haskell.packages set!"
(__generateOptparseApplicativeCompletion command pkg);

# Don't fail at configure time if there are multiple versions of the
# same package in the (recursive) dependencies of the package being
Expand Down
30 changes: 30 additions & 0 deletions pkgs/development/haskell-modules/make-package-set.nix
Original file line number Diff line number Diff line change
Expand Up @@ -597,4 +597,34 @@ in package-set { inherit pkgs lib callPackage; } self // {
}
pkg;

/*
Modify a Haskell package to add shell completion scripts for the
given executables produced by it. These completion scripts will be
picked up automatically if the resulting derivation is installed,
e.g. by `nix-env -i`.
This depends on the `--*-completion` flag `optparse-applicative` provides
automatically. Since we need to invoke installed executables, completions
are not generated if we are cross-compiling.
commands: names of the executables built by the derivation
pkg: Haskell package that builds the executables
Example:
generateOptparseApplicativeCompletions [ "exec1" "exec2" ] pkg
Type: [str] -> drv -> drv
*/
generateOptparseApplicativeCompletions =
self.callPackage (
{ stdenv }:

commands:
pkg:

if stdenv.buildPlatform.canExecute stdenv.hostPlatform
then lib.foldr haskellLib.__generateOptparseApplicativeCompletion pkg commands
else pkg
) { };

}
6 changes: 4 additions & 2 deletions pkgs/top-level/all-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3230,7 +3230,8 @@ with pkgs;

cue2pops = callPackage ../tools/cd-dvd/cue2pops { };

cabal2nix-unwrapped = haskell.lib.compose.justStaticExecutables (haskell.lib.compose.generateOptparseApplicativeCompletion "cabal2nix" haskellPackages.cabal2nix);
cabal2nix-unwrapped = haskell.lib.compose.justStaticExecutables
(haskellPackages.generateOptparseApplicativeCompletions [ "cabal2nix" ] haskellPackages.cabal2nix);

cabal2nix = symlinkJoin {
inherit (cabal2nix-unwrapped) name meta;
Expand Down Expand Up @@ -9377,7 +9378,8 @@ with pkgs;

ngrep = callPackage ../tools/networking/ngrep { };

neuron-notes = haskell.lib.compose.justStaticExecutables (haskell.lib.compose.generateOptparseApplicativeCompletion "neuron" haskellPackages.neuron);
neuron-notes = haskell.lib.compose.justStaticExecutables
(haskellPackages.generateOptparseApplicativeCompletions [ "neuron" ] haskellPackages.neuron);

ngrok = callPackage ../tools/networking/ngrok { };

Expand Down

0 comments on commit ac1f1ad

Please sign in to comment.