devshell
devshell copied to clipboard
Different shell?
Is your feature request related to a problem? Please describe.
I'm used to fish, makes me more productive.
I'm using startup hooks, so direnv doesn't solve the problem.
Describe the solution you'd like
Respect user's $SHELL if it's available after running nix develop.
Describe alternatives you've considered
TBH I have not found any 😕
Additional context
How do you handle when there are two shells loading the same environment, is the second one detecting that all the processes have started?
For now, I have worked with the assumption that it's best to start the processes manually to give the user more control. And startup hooks would only be used for initialization.
Usually it's not a problem because the services use either a pidfile or a port, so they'll just fail to boot in that case.
For now I have found this workaround, but I guess it would be awesome if it could be added by default:
nix-shell --command "$SHELL"
If you use direnv, then it also acts as an interface between your shell and whatever environment variables nix-shell is providing.
I've found out that you can get current user's shell with:
grep ^$USER: /etc/passwd | cut -f 7 -d :
So it would be great if that can be added as a hook and then that is the shell that gets spawned when doing nix-shell or nix develop.
The main problem with https://github.com/numtide/devshell/issues/171#issuecomment-1081722373 is that services do not get reaped after exiting the shell.
I think $SHELL is more reliable because sometimes the shell gets overridden in the Terminal emulator configuration. On Linux you can also look at /proc/$PPID/exe. But yeah, those are all heuristics
The problem with $SHELL is that it's already overriden by devshell. Or you mean not overriding it?
I mean as a source of information. But devshell would have to be modified to take that into account. It also opens a bunch of questions like what to do with --pure if the original shell is not available in the PATH.
I don't think --pure has much sense while developing. In any case, IMHO it shouldn't be very hard: just search for the variable and set it only if missing. Isn't it?
El lun, 11 abr 2022 18:12, Jonas Chevalier @.***> escribió:
I mean as a source of information. But devshell would have to be modified to take that into account. It also opens a bunch of questions like what to do with --pure if the original shell is not available in the PATH.
— Reply to this email directly, view it on GitHub https://github.com/numtide/devshell/issues/171#issuecomment-1095317258, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAHNXDLTAJ4F3EXYGAJY7MLVERMQLANCNFSM5O6MOHFA . You are receiving this because you authored the thread.Message ID: @.***>
Tangentially I'm also currently trying to find ways how to add proper multi-shell support. I'd be interested in exploring. My current thinking is just: don't at all:
{
devshell.startup.completion = l.stringsWithDeps.noDepEntry ''
# bash | zsh | oil
source <(std _carapace)
# elvish
# eval (std _carapace | slurp)
# fish
# std _carapace | source
# nushell
# std _carapace nushell | save out.nu
# source out.nu
# powershell
# Set-PSReadLineOption -Colors @{ "Selection" = "`e[7m" }
# Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
# std _carapace | Out-String | Invoke-Expression
# tcsh
# set autolist
# eval `std _carapace tcsh`
# xonsh
# COMPLETIONS_CONFIRM=True
# exec($(std _carapace))
'';
}
Here are my findings, so far while trying to get shell completion to work across different shells:
nix develop --command "$SHELL"is potentially slow since it reloads the entire shell again.nix developin general is not a good interface to load a devshell since it fixes the shell tobashand foregoes pretty much all the features of the host shell.result/entrypoint- when sourced loads the environment efficiently, when run, switches hard-coded to bash.
direnv
- when direnv sources
result/entrypointit's not interactive so the interactive commands don't load and the sourcing environment is alsobash, therefore shell-specific completion scripts aren't loaded either.
So this PR is a direct conclusion of the above analysis: https://github.com/numtide/devshell/pull/205
After furthed research, I conclude that it would be best to use nix print-dev-env --json ... which returns something link the following JSON
JSON
{
"bashFunctions": {
"runHook":" \n eval \"$shellHook\";\n unset runHook\n"
},
"variables": {
"BASH": {"type": "var", "value": "/noshell"},
"BASHOPTS": {"type": "unknown"},
"BASHPID": {"type": "unknown"},
"COMP_WORDBREAKS": {"type": "var", "value": " \t\n\"'@><=;|&(:"},
"EPOCHREALTIME": {"type": "var", "value": "1653957355.162904"},
"EPOCHSECONDS": {"type": "var", "value": "1653957355"},
"HOME": {"type": "exported", "value": "/homeless-shelter"},
"HOSTTYPE": {"type": "var", "value": "x86_64"},
"IFS": {"type": "var", "value": " \t\n"},
"IN_NIX_SHELL": {"type": "exported", "value": "impure"},
"LINENO": {"type": "var", "value": "73"},
"MACHTYPE": {"type": "var", "value": "x86_64-pc-linux-gnu"},
"NIX_BUILD_CORES": {"type": "exported", "value": "4"},
"NIX_BUILD_TOP": {"type": "exported", "value": "/build"},
"NIX_LOG_FD": {"type": "exported", "value": "2"},
"NIX_STORE": {"type": "exported", "value": "/nix/store"},
"OLDPWD": {"type": "exported", "value": ""},
"OPTERR": {"type": "var", "value": "1"},
"OPTIND": {"type": "unknown"},
"OSTYPE": {"type": "var", "value": "linux-gnu"},
"PATH": {"type": "exported", "value": "/path-not-set"},
"PS4": {"type": "var", "value": "+ "},
"SHELL": {"type": "var", "value": "/noshell"},
"SHELLOPTS": {"type": "unknown"},
"SRANDOM": {"type": "unknown"},
"TEMP": {"type": "exported", "value": "/build"},
"TEMPDIR": {"type": "exported", "value": "/build"},
"TERM": {"type": "exported", "value": "xterm-256color"},
"TMP": {"type": "exported", "value": "/build"},
"TMPDIR": {"type": "exported", "value": "/build"},
"builder": {"type": "exported", "value": "/nix/store/d60gkg5dkw4y5kc055n4m0xyvcjz65im-bash-interactive-5.1-p16/bin/bash"},
"dontAddDisableDepTrack": {"type": "exported", "value": "1"},
"name": {"type": "exported", "value": "Standard"},
"out": {"type": "exported", "value": "/nix/store/wg3jq1c0y99vx35pl2p1a9py83z1qwsj-Standard-env"},
"outputs": {"type": "var", "value": "out"},
"shellHook": {"type": "exported", "value": "# Remove all the unnecessary noise that is set by the build env\nunset NIX_BUILD_TOP NIX_BUILD_CORES NIX_STORE\nunset TEMP TEMPDIR TMP TMPDIR\nunset builder name out shellHook stdenv system\n# Flakes stuff\nunset dontAddDisableDepTrack outputs\n\n# For `nix develop`\nif [[ \"$SHELL\" == \"/noshell\" ]]; then\n export SHELL=/nix/store/d60gkg5dkw4y5kc055n4m0xyvcjz65im-bash-interactive-5.1-p16/bin/bash\nfi\n\n# Load the environment\nsource \"/nix/store/2qpifmmkcrqn7nmj9bh718ah1xq9x1xv-devshell-dir/env.bash\"\n"},
"stdenv": {"type": "exported", "value": "/nix/store/bq3ply37g51zxb6qqh04rhb2gawhii4l-naked-stdenv"},
"system": {"type": "exported", "value": "x86_64-linux"}
}
}
It should be relatively straight forward to write a rendered that would render this for:
- bash (already built-in)
- zsh, et al. -- maybe keep on par with: https://rsteube.github.io/carapace/carapace/gen/hiddenSubcommand.html
Then a new devshell would be launched with something a long these lines:
nix print-dev-env --json ... | devshell render --elvish > ./tempfile
# will/should properly increment SHLVL
elvish -c "source ./tempfile" # or whatever the right syntax would be
and that could be shortened to magic, still:
devshell apply # detecting the right shell based on `SHELL`
Looks like we can have this a lot easier:
nix build "${nix_args[@]}" --profile "$profile_path/shell-profile"
bash -c "source $profile_path/shell-profile/env.bash; SHLVL=$SHLVL; exec $SHELL -i"
- your current shell (required to have the
-iflag, but could be shimmed easily) - with the devshell's env additions
- and the correct
SHLVL - correct
$SHELLas opposed to after invokingnix develop ... CTRL+Ddrops you one shell deeper and reverts the env (as expected)
In context: https://github.com/divnix/std/commit/37529d6110f2b4b536b82acabe370b3803e9078d
Sub-shells are the only way to go if we want something more than env vars (ie direnv).
The easiest for that is to start the sub-shell using the entry point script:
out=$(nix-build ...)
"$out/entrypoint" "$SHELL"
(while at it, you might want to sandbox the whole user environment so the project cannot leak or extract user credentials.)
Of course, the issue then is how to keep the user's configuration in the sub-shell. And what parts are fair game to be overwritten?
FWIW in the mean time I've been able to get to a comfortable dev experience using a combination of direnv and some vscode extensions.
-
Avoid starting services when entering the shell. Direnv doesn't support it, and Bash is not very helpful on reaping services.
-
vscode is also no good at reaping. I just wrap services with tini and it works as expected. To configure for example the postgres server, I did:
pkgs.devshell.mkShell { imports = [ # Includes postgres command, env and initial db setup "${pkgs.devshell.extraModulesDir}/services/postgres.nix" ]; devshell.packages = with pkgs; [ tini # Service helpers (writeScriptBin "service-postgres" '' #!/usr/bin/env bash exec tini -sp SIGTERM -- postgres '') ]; # ... } -
Recommend pinage404.nix-extension-pack. It includes the excellent mkhl.direnv extension which makes all definitions from the devshell available to the IDE.
-
Recommend too actboy168.tasks and configure some tasks, so the dev has a button in the nav bar to start services.
-
Wire those tasks with launch configurations.
At the end, the result is that the dev just opens the workspace on vscode and gets recommended extensions. Installs them, and automatically direnv makes all bins and env available. Then you get a taskbar button to start background services, and can also just hit F5 to start a debugging session which starts those services before.
I'm doing something similar but use a Procfile executed by hivemind to start the services.
@yajo the last commit changed postgres so make sure to replace postgres with start-postgres
I never used hivemind, but maybe there could be some extra module that solves this issue. One shouldn't care so much about what process manager is used as long as things get reaped as expected. That's probably a separate issue.
I wonder what let to the choice or hivemind over something like arion
Arion uses containers, right? Hivemind or Tini are only process managers AFAICS. I am ditching containers on dev because they add almost no value in that scenario once you use nix IMHO.
Especially on mac where docker has to sync the files between the host and the docker VM, it adds quite a bit of overhead. In exchange for a bit of port-mapping and state folder discipline, you get a great increment in speed and debugging.
General recommendation, nix develop -c fish doesn't print the welcome message. Any simple workaround to fix that?