From f6a6e8f98997f421a3cc6193a8ebd88b7389cb67 Mon Sep 17 00:00:00 2001 From: Stefan Tatschner Date: Tue, 13 Aug 2024 11:49:42 +0200 Subject: [PATCH] fix(hr): Handle BrokenPipeError according to official recommendations https://docs.python.org/3/library/signal.html#note-on-sigpipe --- src/hr/__init__.py | 14 ++++++++++++-- tests/bats/100-hr.bats | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/hr/__init__.py b/src/hr/__init__.py index 6eae8c269..e8001d843 100644 --- a/src/hr/__init__.py +++ b/src/hr/__init__.py @@ -3,6 +3,8 @@ # SPDX-License-Identifier: Apache-2.0 import argparse +import os +import signal import sys from itertools import islice from pathlib import Path @@ -89,8 +91,16 @@ def main() -> None: print(f"invalid file format: {e}", file=sys.stderr) sys.exit(1) # BrokenPipeError appears when stuff is piped to | head. - except (KeyboardInterrupt, BrokenPipeError): - pass + # This is not an error for hr. + except BrokenPipeError: + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another BrokenPipeError at shutdown. + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + sys.exit(0) + except KeyboardInterrupt: + sys.exit(128 + signal.SIGINT) if __name__ == "__main__": diff --git a/tests/bats/100-hr.bats b/tests/bats/100-hr.bats index 53fe31da5..c2fa663e1 100644 --- a/tests/bats/100-hr.bats +++ b/tests/bats/100-hr.bats @@ -29,6 +29,10 @@ run -1 bash -c "echo 'invalid json' | hr -" } +@test "pipe to head and handle SIGPIPE" { + hr "$BATS_TEST_DIRNAME/testfiles/log-01.json.zst" | head +} + @test "filter priority" { local additional_line additional_line='{"module": "foo", "data": "I am the line!", "host": "kronos", "datetime":"2020-04-23T15:21:50.620310", "priority": 5, "version": 2}'