80 lines
2.4 KiB
Go
80 lines
2.4 KiB
Go
package main
|
|
|
|
// What a pass left (ADR 0428 §6): the outcome file, and the pass's exit. A refused step is not judged by a health
|
|
// check of its own: the sync is a run-once process, so its non-zero exit is the node-engine's gate (ADR 0136). The
|
|
// module's step is reported failed, apply-failing is raised, and every apply runs it again until it passes, which is
|
|
// the "next pass" of §6. Its last stderr lines name each refused repository, its step and the forge's answer.
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// WriteOutcome keeps what the pass did per repository, whole or not at all.
|
|
func WriteOutcome(file string, o Outcome) error {
|
|
raw, err := json.MarshalIndent(o, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tmp, err := os.CreateTemp(filepath.Dir(file), ".repositories-*")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer os.Remove(tmp.Name())
|
|
if _, err := tmp.Write(append(raw, '\n')); err != nil {
|
|
tmp.Close()
|
|
return err
|
|
}
|
|
if err := tmp.Chmod(0o644); err != nil {
|
|
tmp.Close()
|
|
return err
|
|
}
|
|
if err := tmp.Close(); err != nil {
|
|
return err
|
|
}
|
|
return os.Rename(tmp.Name(), file)
|
|
}
|
|
|
|
// ReadOutcome reads what the last pass left.
|
|
func ReadOutcome(file string) (*Outcome, error) {
|
|
raw, err := os.ReadFile(file)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var o Outcome
|
|
if err := json.Unmarshal(raw, &o); err != nil {
|
|
return nil, fmt.Errorf("the outcome %s is not readable: %w", file, err)
|
|
}
|
|
return &o, nil
|
|
}
|
|
|
|
// Report says on stderr what the pass refused and is the pass's exit: 0 when every listed repository was made, put
|
|
// right or already right; 1 otherwise. One line per refused repository, "repositories: <name>: <step> refused:
|
|
// <forge answer>", then a summary line, so the line the node-engine keeps last names what to look at.
|
|
func Report(o Outcome, stderr io.Writer) int {
|
|
if o.Failed != "" {
|
|
fmt.Fprintf(stderr, "repositories: the pass did not run: %s; nothing was made\n", o.Failed)
|
|
return 1
|
|
}
|
|
refused := o.Refused()
|
|
if len(refused) == 0 {
|
|
return 0
|
|
}
|
|
for _, r := range refused {
|
|
fmt.Fprintf(stderr, "repositories: %s: %s refused: %s\n", r.Name, r.Step, r.Said)
|
|
}
|
|
if len(refused) > 1 {
|
|
names := make([]string, 0, len(refused))
|
|
for _, r := range refused {
|
|
names = append(names, r.Name)
|
|
}
|
|
fmt.Fprintf(stderr, "repositories: %d of %d repositories had a step refused (%s); nothing further of them was done, the rest were\n",
|
|
len(refused), len(o.Repositories), strings.Join(names, ", "))
|
|
}
|
|
return 1
|
|
}
|