Signals end every command, not only ssh to and ssh install (closes #48)
check / check (push) Successful in 2m20s
check / check (push) Successful in 2m20s
SIGINT, SIGTERM and SIGHUP were caught for the whole run, but only the ssh and sftp children acted on them: the mnemonic prompt waited for Enter, and an interrupted `age encrypt -o` went on to put the encryption of the cut-off input in place. Now `ssh to` and `ssh install` catch them from once the mnemonic is read until their cleanup has run, and `age encrypt -o` and `age decrypt -o` catch them while they write, to remove the unfinished file and exit with status 1; everywhere else they end the tool at once. Tests cover an interrupted `age encrypt -o` and `age decrypt -o` and the install working directory on a signal. Model: opus-5-5
This commit is contained in:
+25
-1
@@ -6,7 +6,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"sneak.berlin/go/keyfunc/internal/agekey"
|
||||
@@ -185,16 +187,38 @@ func output(cmd *cobra.Command) (io.Writer, func(error) error, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// From before the new file is made until it is renamed or removed,
|
||||
// a signal removes it and ends the tool with status 1, even while
|
||||
// the work is blocked reading its input, so an interrupted run
|
||||
// leaves no file.
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP)
|
||||
|
||||
// The file is made in the same directory so that putting it in
|
||||
// place is a rename and never a copy, and it is readable only by
|
||||
// its owner, which is the mode it keeps once renamed.
|
||||
file, err := os.CreateTemp(filepath.Dir(name), filepath.Base(name)+".")
|
||||
if err != nil {
|
||||
signal.Stop(signals)
|
||||
|
||||
return nil, nil, fmt.Errorf("creating a file beside %s: %w", name, err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if _, received := <-signals; received {
|
||||
_ = os.Remove(file.Name())
|
||||
|
||||
os.Exit(1)
|
||||
}
|
||||
}()
|
||||
|
||||
return file, func(failed error) error {
|
||||
return finish(file, name, failed)
|
||||
finished := finish(file, name, failed)
|
||||
|
||||
signal.Stop(signals)
|
||||
close(signals)
|
||||
|
||||
return finished
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user