aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--misc/meson.build6
-rwxr-xr-xmisc/runinpty.py77
-rw-r--r--package.nix3
-rw-r--r--tests/functional/common/vars-and-functions.sh.in4
-rw-r--r--tests/functional/flakes/show.sh3
-rw-r--r--tests/functional/meson.build2
6 files changed, 91 insertions, 4 deletions
diff --git a/misc/meson.build b/misc/meson.build
index a8f09722c..bf3c157f7 100644
--- a/misc/meson.build
+++ b/misc/meson.build
@@ -4,3 +4,9 @@ subdir('zsh')
subdir('systemd')
subdir('flake-registry')
+
+runinpty = configure_file(
+ copy : true,
+ input : meson.current_source_dir() / 'runinpty.py',
+ output : 'runinpty.py',
+)
diff --git a/misc/runinpty.py b/misc/runinpty.py
new file mode 100755
index 000000000..a7649b735
--- /dev/null
+++ b/misc/runinpty.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+# SPDX-FileCopyrightText: 2001, 2002, 2003, 2004, 2005, 2006 Python Software Foundation; All Rights Reserved
+# SPDX-FileCopyrightText: 2024 Jade Lovelace
+# SPDX-License-Identifier: LGPL-2.1-or-later
+"""
+This script exists to lose Lix a dependency on expect(1) for the ability to run
+something in a pty.
+
+Yes, it could be replaced by script(1) but macOS and Linux script(1) have
+diverged sufficiently badly that even specifying a subcommand to run is not the
+same.
+"""
+import pty
+import sys
+import os
+from termios import ONLCR, ONLRET, ONOCR, OPOST, TCSAFLUSH, tcgetattr, tcsetattr
+from tty import setraw
+import termios
+
+def setup_terminal():
+ # does not matter which fd we use because we are in a fresh pty
+ modi = tcgetattr(pty.STDOUT_FILENO)
+ [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] = modi
+
+ # Turning \n into \r\n is not cool, Linux!
+ oflag &= ~ONLCR
+ # I don't know what "implementation dependent postprocessing means" but it
+ # sounds bad
+ oflag &= ~OPOST
+ # Assume that NL performs the role of CR; do not insert CRs at column 0
+ oflag |= ONLRET | ONOCR
+
+ modi = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
+
+ tcsetattr(pty.STDOUT_FILENO, TCSAFLUSH, modi)
+
+
+def spawn(argv: list[str]):
+ """
+ As opposed to pty.spawn, this one more seriously controls the pty settings.
+ Necessary to turn off such fun functionality as onlcr (LF to CRLF).
+
+ This is essentially copy pasted from pty.spawn, since there is no way to
+ hook the child pre-execve
+ """
+ pid, master_fd = pty.fork()
+ if pid == pty.CHILD:
+ setup_terminal()
+ os.execlp(argv[0], *argv)
+
+ try:
+ mode = tcgetattr(pty.STDIN_FILENO)
+ setraw(pty.STDIN_FILENO)
+ restore = True
+ except termios.error:
+ restore = False
+
+ try:
+ pty._copy(master_fd, pty._read, pty._read) # type: ignore
+ finally:
+ if restore:
+ tcsetattr(pty.STDIN_FILENO, TCSAFLUSH, mode) # type: ignore
+
+ os.close(master_fd)
+ return os.waitpid(pid, 0)[1]
+
+
+def main():
+ if len(sys.argv) == 1:
+ print(f'Usage: {sys.argv[0]} [command args]', file=sys.stderr)
+ sys.exit(1)
+
+ sys.exit(os.waitstatus_to_exitcode(spawn(sys.argv[1:])))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/package.nix b/package.nix
index 18c8475bb..295e9139f 100644
--- a/package.nix
+++ b/package.nix
@@ -20,7 +20,6 @@
doxygen,
editline-lix ? __forDefaults.editline-lix,
editline,
- expect,
git,
gtest,
jq,
@@ -275,8 +274,6 @@ stdenv.mkDerivation (finalAttrs: {
# configure, but we don't actually want to *run* the checks here.
++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs;
- nativeCheckInputs = [ expect ];
-
checkInputs = [
gtest
rapidcheck
diff --git a/tests/functional/common/vars-and-functions.sh.in b/tests/functional/common/vars-and-functions.sh.in
index eda15308d..451cf5383 100644
--- a/tests/functional/common/vars-and-functions.sh.in
+++ b/tests/functional/common/vars-and-functions.sh.in
@@ -234,6 +234,10 @@ enableFeatures() {
sed -i 's/experimental-features .*/& '"$features"'/' "$NIX_CONF_DIR"/nix.conf
}
+runinpty() {
+ @python@ @runinpty@ "$@"
+}
+
set -x
onError() {
diff --git a/tests/functional/flakes/show.sh b/tests/functional/flakes/show.sh
index 25f481575..857c77ae1 100644
--- a/tests/functional/flakes/show.sh
+++ b/tests/functional/flakes/show.sh
@@ -104,7 +104,8 @@ cat >flake.nix<<EOF
};
}
EOF
-unbuffer sh -c '
+
+runinpty sh -c '
stty rows 20 cols 100
nix flake show > show-output.txt
'
diff --git a/tests/functional/meson.build b/tests/functional/meson.build
index 2b5dfe422..fb8d77a57 100644
--- a/tests/functional/meson.build
+++ b/tests/functional/meson.build
@@ -7,6 +7,8 @@ test_confdata = {
'sandbox_shell': busybox.found() ? busybox.full_path() : '',
'PACKAGE_VERSION': meson.project_version(),
'system': host_system,
+ 'python': python.full_path(),
+ 'runinpty': runinpty.full_path(),
}
# Just configures `common/vars-and-functions.sh.in`.