forked from lix-project/lix
build: remove expect as a dependency
I was packaging Lix 2.91 for nixpkgs and was annoyed at the expect
dependency. Turns out that you can replace unbuffer with a pretty-short
Python script.
It became less short after I found out that Linux was converting \n to
\r\n in the terminal subsystem, which was not very funny, but is at
least solved by twiddling termios bits.
Change-Id: I8a2700abcbbf6a9902e01b05b40fa9340c0ab90c
This commit is contained in:
parent
292567e0b0
commit
0c76195351
6 changed files with 91 additions and 4 deletions
|
@ -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',
|
||||
)
|
||||
|
|
77
misc/runinpty.py
Executable file
77
misc/runinpty.py
Executable file
|
@ -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()
|
|
@ -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
|
||||
|
|
|
@ -234,6 +234,10 @@ enableFeatures() {
|
|||
sed -i 's/experimental-features .*/& '"$features"'/' "$NIX_CONF_DIR"/nix.conf
|
||||
}
|
||||
|
||||
runinpty() {
|
||||
@python@ @runinpty@ "$@"
|
||||
}
|
||||
|
||||
set -x
|
||||
|
||||
onError() {
|
||||
|
|
|
@ -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
|
||||
'
|
||||
|
|
|
@ -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`.
|
||||
|
|
Loading…
Reference in a new issue