check / check (push) Failing after 2s
SIGINT, SIGTERM and SIGHUP were caught for the whole run, so the mnemonic prompt waited for Enter and an interrupted `age encrypt -o` put the encryption of the cut-off input in place. Now they end the tool at once, except where a command cleans up first: `ssh to` and `ssh install` while ssh or sftp runs, and `age encrypt -o` and `age decrypt -o` while they write. A signal those two have received when their input ends removes the unfinished file and exits 1; a later one leaves the whole file in place. The tool stays on the main thread, where Linux delivers the signal first. Signals the tool was started ignoring stay ignored, so a run under nohup survives a hangup. Model: opus-5-5
54 lines
1.5 KiB
Go
54 lines
1.5 KiB
Go
// Package signals catches the signals that end the tool, for the
|
|
// commands that clean up before they end.
|
|
package signals
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
)
|
|
|
|
// Context is signal.NotifyContext for SIGINT, SIGTERM and SIGHUP: the
|
|
// context it returns is cancelled when one of them arrives, and stop
|
|
// stops catching them. It leaves out any of the three the tool was
|
|
// started with set to be ignored, as nohup does with SIGHUP, because
|
|
// catching a signal turns an ignored one back on and would end a run
|
|
// that was meant to survive it.
|
|
func Context(parent context.Context) (context.Context, context.CancelFunc) {
|
|
endings := caught()
|
|
|
|
// Given no signals at all, NotifyContext would catch every one.
|
|
if len(endings) == 0 {
|
|
return context.WithCancel(parent)
|
|
}
|
|
|
|
return signal.NotifyContext(parent, endings...)
|
|
}
|
|
|
|
// Notify is signal.Notify for the signals Context catches: each one
|
|
// that arrives is sent to c, until signal.Stop(c).
|
|
func Notify(c chan<- os.Signal) {
|
|
endings := caught()
|
|
|
|
// Given no signals at all, Notify would catch every one.
|
|
if len(endings) > 0 {
|
|
signal.Notify(c, endings...)
|
|
}
|
|
}
|
|
|
|
// caught returns those of SIGINT, SIGTERM and SIGHUP that the tool was
|
|
// not started with set to be ignored.
|
|
func caught() []os.Signal {
|
|
endings := []os.Signal{syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP}
|
|
kept := make([]os.Signal, 0, len(endings))
|
|
|
|
for _, ending := range endings {
|
|
if !signal.Ignored(ending) {
|
|
kept = append(kept, ending)
|
|
}
|
|
}
|
|
|
|
return kept
|
|
}
|