thefuck
thefuck copied to clipboard
feat: new rule for `nix-shell`
Implementation is similar to the one explained in https://github.com/nvbn/thefuck/issues/912#issue-441679613.
In a nutshell, it tries to wrap the user's failed command in a nix-shell call.
$ ponysay moo
The program 'ponysay' is not in your PATH. You can make it available in an
ephemeral shell by typing:
nix-shell -p ponysay
$ fuck
nix-shell -p ponysay --run "ponysay moo" [enter/↑/↓/ctrl+c]
Further info on nix-shell: https://thiagowfx.github.io/2022/02/nix-shell-in-a-nutshell/#hello-world-classic
Been loving this. Hope it gets reviewed and upstreamed for all. Thanks for making this!
I've just discovered thefuck
and I can't imagine how I didn't stumble into it earlier.
This PR would fit like a glove for me that just switched to nixos and haven't yet grown the muscle memory of typing the nix-shell
whenever my command fails.
i would love to see this merged as well
looks like you can use this already using e.g. an overlay, altho i had a bit of trouble getting it to work out of the box.
specifically, without adding doCheck = false;
, i would run into this error:
error: builder for '/nix/store/rl44gb6qd4x2myclj9i8cpkfrvw6ysqa-thefuck-3.32.drv' failed with exit code 2;
last 10 log lines:
> thefuck/system/unix.py:6
> /build/source/thefuck/system/unix.py:6: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
> from distutils.spawn import find_executable
>
> -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
> =========================== short test summary info ============================
> ERROR - ModuleNotFoundError: No module named 'pytest_docker_pexpect'
> !!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
> ========================= 1 warning, 1 error in 0.09s ==========================
> /nix/store/bknngadwym46j65qs14ic2w79rpav888-stdenv-linux/setup: line 1582: pop_var_context: head of shell_variables not a function context
i had tried removing the added test, altho that appeared not to resolve the issue.
it would seem cool to similarly get an approach using nix run
, i.e. go from suggesting nix-shell -p ponysay --run "ponysay moo"
to nix run nixpkgs#ponysay -- moo
- this might eventually help extend beyond just nixpkgs
.
edit: https://github.com/KiaraGrouwstra/thefuck/commit/81d6786c80b86f2cc80b3ea90adc214df8266643
I've been using a custom rule that supports the new unified CLI for a while, and was planning on opening a PR once this one has been merged (I hesitate to update this current PR as it's already tested and ready to be merged). I don't know if that will happen soon, so in the meantime I've pushed the changes to this new branch instead, which builds on this here PR. You can use the updated rule by adding it as a custom rule to your config.
In the new rule, three variants are suggested. Assuming I run cowsay hello world
, I am presented with the following:
-
nix run nixpkgs#cowsay -- hello world
: This runs my command in a non-interactive shell. Uses the nix unified CLI. -
nix shell nixpkgs#cowsay
: This enters an interactive shell withcowsay
available, but does not run any command. This is useful if you'd rather run the command yourself after entering the shell because your command requires delicate massaging (e.g. running it withsudo
, prefixing it with environment variable, juggling quote variants, etc). -
nix-shell -p cowsay --run "cowsay hello world"
. This runs my command in a non-interactive shell. Uses the nix original CLI. -
nix shell nixpkgs#cowsay --command cowsay hello world
: Very similar to the first one so I've personally disabled this one.
Thoughts on future updates:
- It'd be nice if there was a variant that runs my command and then keeps me in the shell.
- We should expose a couple of flags for users to configure this.
-
disable_unified_cli
(boolean) -
disable_original_cli
(boolean)
-
- As far as I can tell, the
command-not-found
db doesn't really play nice if you use flakes to configure your system and might return stale results (unless you update it manually?).nix-index
seems to be the go-to alternative. It'd be great if we could optionally use that instead (perhaps behind a flagenable_nix_index
for users who have installednix-index
(programs.nix-index.enable = true;
in home manager).
@thenbe i agree integrating with nix-index
's command-not-found
replacement seems cool, as a flake user.
i kinda wish we could have command-not-found
(and this thefuck
integration) extend to flake inputs beyond nixpkgs as well, such as to packages from NUR for example. preferably this should be dynamic based on your inputs rather than hardcoded to specific ones like nixpkgs, or NUR for that matter.
i'll admit i haven't really figured out how that might work tho.
just tried these with a command like program_i_have | program_i_dont_have
, seems that may complicate the suggestions a bit
I'm not sure if thefuck
can handle piping.
If I make a typo git statis
it will correct me to git status
. But if I do echo hello | git statis
it does not correct my typo. thefuck
seems to work mostly on single commands AFAICT.
@thenbe hm, i'm not sure.
fortune | cowsay
The program 'cowsay' is not in your PATH. It is provided by several packages.
You can make it available in an ephemeral shell by typing one of the following:
nix-shell -p cowsay
nix-shell -p neo-cowsay
$ fuck
nix run nixpkgs#fortune | cowsay
feels like it knows about the whole command given it's reproducing it?
another common nix thing we might be able to address from thefuck
would be errors about packages being unfree
edit: https://github.com/KiaraGrouwstra/thefuck/commit/16d838bf6f63117b161a2f1e6572e06108b007eb
@thenbe what was the argument to favor nix run
over nix shell
again? i guess the latter seems a bit more generic in case of handling non-standard binaries at least
If I'm only looking to execute a program (and don't need to be dropped into a shell) then I prefer nix run
over nix shell
as the documentation suggests nix run
specifically for this use case.
I also recall nix run
being more performant (perhaps because we forego the overhead of launching a shell?). This last point is not derived from benchmarks, only anecdotal evidence.
i guess the latter seems a bit more generic in case of handling non-standard binaries at least
I've added this variant (the 4th one in my previous post), but disabled it after a while when I realized that I never reach for it. Do you find that you still need it over nix run
(the 1st variant in my previous post)?
another common nix thing we might be able to address from
thefuck
would be errors about packages being unfreeedit: KiaraGrouwstra@16d838b
This would be useful. Does it still complain about the --impure
flag? Or do you use a workaround for that?
i've been using thefuck
mostly thru its zsh
plugin, which just gets you the top suggestion. i found that failed for me for e.g. poppler_utils
, which bundles multiple binaries.
to be fair tho, i'm not sure that accounts for a large portion of its invocations, so maybe it could make sense to just actually type out fuck
in those cases.
what was the --impure
error? i'm not sure i'd run into that.
by the way, had you managed to also package your branch for nix? considering i seemed to need that doCheck = false;
to get our branches to build thru nix.
I just have it aliased to f
for extra convenience.
I opted not to package it for nix separately since fuck
already exposes a method for easily adding custom rules. Instead, I placed the rule in ~/mydotfiles/thefuck/rules/nix-shell.py
then told home-manager to symlink it to the appropriate place in .config
:
# home.nix
home.file.".config/thefuck/rules/nix-shell.py".source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/mydotfiles/thefuck/rules/nix-shell.py";
This way I don't need to rebuild every time I tweak the rule.
what was the --impure error?
The unified CLI commands (nix shell
, nix run
, etc) will not acknowledge environment variables unless the --impure
flag is used.
output
$ NIXPKGS_ALLOW_UNFREE=1 nix shell nixpkgs#github-copilot-cli
error:
… in the condition of the assert statement
at /nix/store/xwc3zfc544jg6zhr0wi6k8253s7mwlhi-source/lib/customisation.nix:267:17:
266| in commonAttrs // {
267| drvPath = assert condition; drv.drvPath;
| ^
268| outPath = assert condition; drv.outPath;
… while evaluating the attribute 'handled'
at /nix/store/xwc3zfc544jg6zhr0wi6k8253s7mwlhi-source/pkgs/stdenv/generic/check-meta.nix:490:7:
489| # or, alternatively, just output a warning message.
490| handled =
| ^
491| (
(stack trace truncated; use '--show-trace' to show the full trace)
error: Package ‘github-copilot-cli-0.1.36’ in /nix/store/xwc3zfc544jg6zhr0wi6k8253s7mwlhi-source/pkgs/tools/misc/github-copilot-cli/default.nix:21 has
an unfree license (‘unfree’), refusing to evaluate.
a) To temporarily allow unfree packages, you can use an environment variable
for a single invocation of the nix tools.
$ export NIXPKGS_ALLOW_UNFREE=1
Note: When using `nix shell`, `nix build`, `nix develop`, etc with a flake,
then pass `--impure` in order to allow use of environment variables.
b) For `nixos-rebuild` you can set
{ nixpkgs.config.allowUnfree = true; }
in configuration.nix to override this.
Alternatively you can configure a predicate to allow specific packages:
{ nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"github-copilot-cli-0.1.36"
];
}
c) For `nix-env`, `nix-build`, `nix-shell` or any other Nix command you can add
{ allowUnfree = true; }
to ~/.config/nixpkgs/config.nix.
# it wants this instead:
$ NIXPKGS_ALLOW_UNFREE=1 nix shell nixpkgs#github-copilot-cli --impure
aah i see! i'd yet to take that into account. 🙈
specifying the rules rather than doing overlays makes sense - thanks!