Can I use xonsh as my login shell? If so, how?

On a NixOS 19.09 system, I’d like to try xonsh (NixOS 19.09 package) as my login shell. Towards that end, I tried the following:

  1. In /etc/nixos/configuration.nix, I added
    programs.xonsh.enable = true;
    
    to whitelist xonsh as a login shell.
  2. Also in /etc/nixos/configuration.nix, I changed the entry for my user from
    users.extraUsers.das-g = {
      isNormalUser = true;
      description = "Raphael Das Gupta";
      extraGroups = ["wheel" "networkmanager" "lp" "docker" "dialout" "vboxusers"];
      uid = 1000;
    };
    
    to
    users.extraUsers.das-g = {
      isNormalUser = true;
      description = "Raphael Das Gupta";
      extraGroups = ["wheel" "networkmanager" "lp" "docker" "dialout" "vboxusers"];
      uid = 1000;
      shell = pkgs.xonsh;
    };
    
    (i.e., users.users.das-g.shell = pkgs.xonsh; is now set)
  3. I applied these changes with
    sudo nixos-rebuild boot
    
    to a new system generation
  4. I rebootet into the new system generation

The result was, that the graphical session (GNOME 3 in my case) wouldn’t work anymore. The login screen came up with the entry for my user and all, but if I selected that, entered my password and logged in, I would almost immediately be returned to the login screen, without anything from GNOME showing up.

So I switched to a virtual terminal with Ctrl+Alt+F1. There, I could log in and indeed xonsh was being used. But even basic commands like echo weren’t available and the content of $PATH (which xonsh can fortunately display without relying on echo) looked suspiciously short for a NixOS session: Maybe four or five entries, only.

Was I doing anything wrong and/or missing something? Or is the xonsh derivation not prepared to be used as a login shell? (Should it be, though?) Or is xonsh per se unsuited as a login shell?

The existence of the NixOS option programs.xonsh.enable makes be believe that xonsh is intended to be usable as a login shell on NixOS and that I’ve either missed some step or the package is faulty or incomplete. (Without knowing much about it, I guess it needs some additional wrapper or something.)

The users.<name>.shell option expects the filepath to the executable of the shell. So something like this should work:

shell = "${pkgs.xonsh}/bin/xonsh";

pkgs.xonsh alone is evaluated to the a directory in the Nix store, so that’s why it broke your login.

Does it? The description for users.users.<name?>.shell says

The path to the user’s shell. Can use shell derivations, like pkgs.bashInteractive . Don’t forget to enable your shell in programs if necessary, like programs.zsh.enable = true; .

(emphasis by me)

And indeed, if I don’t overwrite it in /etc/nixos/configuration.nix, nixos-option users.users.das-g.shell reports the value to be /nix/store/lb3hli8d9536g45mndwfwyi6fpny0blh-bash-interactive-4.4-p23, which is also just a directory.

Alas, that leads to the exact same behavior as just shell = pkgs.xonsh; did.

Shouldn’t the login then not have worked at all? Note that I did get a xonsh session, albeit not a very usable one.

I suspect the issue is due to https://github.com/NixOS/nixpkgs/blob/54e89941c303687a6392a3264dbe1540fe3381d8/nixos/modules/programs/xonsh.nix not using config.environment.shellInit, config.environment.loginShellInit and / or config.environment.interactiveShellInit, but I’m unsure which of those it should use and how.

You are right, I made a couple tests and it’s indeed not necessary.

Setting the shell for a user also works without adding the shell to /etc/shells, which is what programs.xonsh.enable et al. do. The Linux programmer’s manual says it’s mainly needed by chsh and some program to check if you are a real user.

Looking at how fish works it seems xonsh is not sourcing the NixOS environment, which would explain the absence of PATH and other variables. It’s not POSIX compatible, so I don’t know how it works, but you would have to add the equivalent of:

      # source the NixOS environment config
      if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]
          source "${config.system.build.setEnvironment}"
      fi

in programs.xonsh.config.

Thanks, yes, that does indeed seem to be (part of) the problem.

Instead of modifying programs.xonsh.config, I’ve now tried to add the sourcing to /etc/xonshrc before the content of programs.xonsh.config:

diff --git a/nixos/modules/programs/xonsh.nix b/nixos/modules/programs/xonsh.nix
index 1590020f7b6..42e47f8c61b 100644
--- a/nixos/modules/programs/xonsh.nix
+++ b/nixos/modules/programs/xonsh.nix
@@ -45,7 +45,13 @@ in
 
   config = mkIf cfg.enable {
 
-    environment.etc.xonshrc.text = cfg.config;
+    environment.etc.xonshrc.text = ''
+      if not ''${...}.get('__NIXOS_SET_ENVIRONMENT_DONE'):
+          $PATH.add('/run/current-system/sw/bin')
+          source-bash "${config.system.build.setEnvironment}"
+
+      ${cfg.config}
+    '';
 
     environment.systemPackages = [ cfg.package ];
 

With this, I get an actually working xonsh shell when I log in on the virtual text console. :+1:

However, if I try to log into a graphical GNOME session, I still get returned to the login screen. Entries in journalctl -b indicate that wayland is getting killed, but I couldn’t yet figure out why. :confused:

I’ve also tried (unconditionally) sourcing /etc/profile instead.

diff --git a/nixos/modules/programs/xonsh.nix b/nixos/modules/programs/xonsh.nix
index 1590020f7b6..c371d2b483b 100644
--- a/nixos/modules/programs/xonsh.nix
+++ b/nixos/modules/programs/xonsh.nix
@@ -45,7 +45,12 @@ in
 
   config = mkIf cfg.enable {
 
-    environment.etc.xonshrc.text = cfg.config;
+    environment.etc.xonshrc.text = ''
+      $PATH.add('/run/current-system/sw/bin')
+      source-bash /etc/profile
+
+      ${cfg.config}
+    '';
 
     environment.systemPackages = [ cfg.package ];
 

That leads to the same behavior:

  • text terminal works
  • graphical login doesn’t

Because working as login-shell for only text-mode is already better than not working as login shell at all, I’ve made a pull request with this addition:

NixOS/nixpkgs#84330