`/dev/tty` not available in `checkPhase` when writing my first derivation

Hello to all the nix-learning and nix-knowning people :slight_smile:

I started to write my first own derivation from scratch. I want to package a project I develop and hopefully include it into the official nixpkgs later on.

This is my default.nix so far:

{ pkgs ? import <nixpkgs> {}, doCheck ? true }:

let
  stdenv = pkgs.stdenv;
  fetchFromGitHub = pkgs.fetchFromGitHub;
in
stdenv.mkDerivation rec {
  pname = "nvimpager";
  version = "0.9";

  src = fetchFromGitHub {
    owner = "lucc";
    repo = pname;
    rev = "v${version}";
    sha256 = "1xy5387szfw0bp8dr7d4z33wd4xva7q219rvz8gc0vvv1vsy73va";
  };

  buildInputs = with pkgs; [
    ncurses # for tput
    neovim
    procps # for nvim_get_proc() which uses ps(1)
    pandoc
  ];

  makeFlags = [ "PREFIX=$(out)" ];
  buildFlags = [ "nvimpager.configured" ];
  preBuild = ''
    substituteInPlace nvimpager \
      --replace '/usr/bin/env bash' '${pkgs.bash}/bin/bash' \
      --replace ':-nvim' ':-${pkgs.neovim}/bin/nvim'
    '';
  checkInputs = with pkgs; [ lua51Packages.busted ];
  checkTarget = "test";
  inherit doCheck;

  meta = with stdenv.lib; {
    description = "Use neovim as pager";
    longDescription = ''
      Use neovim as a pager to view manpages, diffs, etc with nvim's syntax
      highlighting.  Includes a cat mode to print highlighted files to stdout
      and a ansi esc mode to highlight ansi escape sequences in neovim.
    '';
    homepage = "https://github.com/lucc/nvimpager";
    license = licenses.bsd2;
    platforms = platforms.all;
  };
}

Building it with nix-build default.nix --arg doCheck false seems to work and I can use the program inside the derivation’s output. My problem lies with the check phase. When I run with doCheck true I get many test failures,especially this message: ./nvimpager: line 127: /dev/tty: No such device or address (my program is a script that redirects from /dev/tty).

The thing is if I use my derivation with nix-shell default.nix and run make test it works perfectly. So what is nix-build doing or how can I fix that?

On top of that I also interested in all the criticism and comments that you can give to help me learn to write a better derivation.

Do you have build sandboxing enabled.

This could be a side effect of this… you can find some more info here (search for sandbox)

https://nixos.wiki/wiki/Nix

https://nixos.org/manual/nix/stable/#sec-conf-file

and sandbox-paths might be able to help you.

sandbox-paths
A list of paths bind-mounted into Nix sandbox environments. You can use the syntax target=source to mount a path in a different location in the sandbox; for instance, /bin=/nix-bin will mount the path /nix-bin as /bin inside the sandbox. If source is followed by ?, then it is not an error if source does not exist; for example, /dev/nvidiactl? specifies that /dev/nvidiactl will only be mounted in the sandbox if it exists in the host filesystem.

Depending on how Nix was built, the default value for this option may be empty or provide /bin/sh as a bind-mount of bash.
``

Indeed that is the case, I have sandbox = true in /etc/nix/nix.conf (I am on NixOS and the default for nix.useSandbox is true).

Now I tried sudo nix-build --option extra-sandbox-paths /dev/tty default.nix but the error is the same. That looks strange to me. How should I activate extra-sandbox-paths for one build? Or do I need to set it permanently?


Footnote: Yeah I learned about sandboxing today :slight_smile:

If I use --option sandbox-paths /dev/tty instead the test fail even more dramatic because lua’s io.popen returns nil (the test suite is in lua and calls external commands).

Thanks for trying to nixify your software …it can only make NIX/OS better , if more software is available, then it can only make the ecosystem better.

as for your problem, maybe this lua test suite is having a problem determining what tty or pseudo tty it’s test/process is attached to.

I’m guessing that it’s busted output handler is trying to open the a tty for output.but having trouble…

http://olivinelabs.com/busted/

mentioned that it has a few different output handlers, maybe try a different (the one made for CI maybe better)? maybe related or unrelated…

Sadly the output handler for busted is not the solution. I tested the different ones advertised on the busted site but that did not change anything.

The error message does also not come from busted. The architecture is like this:

nix-build --> make --> busted --> ./nvimpager --> nvim --> lua/nvimpager.lua

and the error is from the shell script nvimpager.

Maybe I should go ahead and open a PR and someone on Github can help me fix that. Or can I mark the tests as “run without sandbox” somehow?

Also: Can I encode the extra sandbox path in the default.nix file declarative or can I only provide it on the command line?

Searching on Github I only found two issues where the same symptom was visible but the fixes are unrelated to the symptom (Cuda-8.0 derivation does not build · Issue #27913 · NixOS/nixpkgs · GitHub, Can't build nvidia-x11 on unstable · Issue #74523 · NixOS/nixpkgs · GitHub). In one case they even just excluded the problematic tests from the check phase. But that would exclude 26/122 tests for me :frowning:

Would it maybe work if you install a terminal emulator in checkInputs and then run the tests in that terminal? E.g.

{
  checkInputs = [ pkgs.xterm ];
  checkPhase = ''
    xterm -e make check
  '';
}

@olmokramer that does not work at once because xterm can not connect to the display:

/nix/store/mky314anzlqa3jqqacbp1kry3nzzcw0l-xterm-362/bin/xterm: Xt error: Can't open display: 
/nix/store/mky314anzlqa3jqqacbp1kry3nzzcw0l-xterm-362/bin/xterm: DISPLAY is not set

I also tried this idea with tmux but the error stays the same.

Xterm also sounds like a strange workaround and I then have to deal with the display in the sandbox. Not sure if that is the way to go.

I now opened a pull request for this:
https://github.com/NixOS/nixpkgs/pull/107057

If you only need a pseudo tty, you can also run script -c <yourcommand>.

Thank you @Mic92 that solved it. I pushed the fix :rocket: