diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 320fd56..e2f110d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -43,3 +43,10 @@ jobs: with: files: ./coverage.txt verbose: true +defaults: + run: + # NOTE: some of behavioral-tests requires tty... but + # + # GitHub Actions run without a TTY device. This is a workaround to get one, + # based on https://github.com/actions/runner/issues/241#issuecomment-2019042651 + shell: 'script --return --quiet --log-out /dev/null --command "bash -e {0}"' diff --git a/behavioral-tests/ctrl-c-graceful/custom-fake-server.sh b/behavioral-tests/ctrl-c-graceful/custom-fake-server.sh new file mode 100755 index 0000000..c437577 --- /dev/null +++ b/behavioral-tests/ctrl-c-graceful/custom-fake-server.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +child_pid= + +xtrap() { + echo "Getting SIGNAL $1. Exiting" + kill -9 $child_pid + exit +} + +trap "xtrap SIGINT" 2 # graceful shutdown handler + +echo "Arguments: $@" + +( + # pretending someone kills process + for i in "$@"; do + echo "Working hard on ${i}..." + sleep 5 + done +) & + +child_pid=$! + +wait diff --git a/behavioral-tests/ctrl-c-graceful/custom-run.sh b/behavioral-tests/ctrl-c-graceful/custom-run.sh new file mode 100755 index 0000000..8cb76ed --- /dev/null +++ b/behavioral-tests/ctrl-c-graceful/custom-run.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +# emulate terminal: run command in separate process group +set -m +( + go run ../../cmd/... ./custom-fake-server.sh ARG1 ARG2 ARG3 > output.log +) & +set +m +child_pgid=${!} + +sleep 1 # allow to work a little +kill -2 -${child_pgid} # emulate user's ctrl-C + +wait ${child_pgid} + +echo "ok" diff --git a/behavioral-tests/ctrl-c-graceful/expected.log b/behavioral-tests/ctrl-c-graceful/expected.log new file mode 100644 index 0000000..64adce8 --- /dev/null +++ b/behavioral-tests/ctrl-c-graceful/expected.log @@ -0,0 +1,3 @@ +INVALID JSON: "Arguments: ARG1 ARG2 ARG3" +INVALID JSON: "Working hard on ARG1..." +INVALID JSON: "Getting SIGNAL SIGINT. Exiting" diff --git a/cmd/pplog/main.go b/cmd/pplog/main.go index d32b325..32c78f3 100644 --- a/cmd/pplog/main.go +++ b/cmd/pplog/main.go @@ -7,6 +7,7 @@ import ( "io/fs" "os" "os/exec" + "os/signal" "path" "runtime/debug" "strings" @@ -178,10 +179,29 @@ func main() { showBuildInfo() return } - if flag.NArg() >= 1 { - runSubprocessMode() - } else { - runPipeMode() + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM) + + done := make(chan struct{}) + go func() { + if flag.NArg() >= 1 { + runSubprocessMode() + } else { + runPipeMode() + } + close(done) + }() + + select { + case <-interrupt: + deb("interrupt, allow target to shutdown gracefully...") + case <-done: + } + + select { + case <-interrupt: + deb("second interrupt, exit immediately") + case <-done: } }