Files
narratio/internal/app/restore_recovery.go

64 lines
1.9 KiB
Go

package app
import (
"encoding/json"
"fmt"
"os"
"strings"
"time"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/fileops"
)
type restoreMarker struct {
StartedAt time.Time `json:"started_at"`
}
func writeRestoreMarker(paths artifacts.SessionPaths) error {
marker := restoreMarker{StartedAt: nowUTC()}
data, err := json.Marshal(marker)
if err != nil {
return fmt.Errorf("encode recovery marker: %w", err)
}
if err := fileops.WriteFileAtomic(paths.RestoreMarkerPath, data, fileops.WorkspaceFileMode); err != nil {
return fmt.Errorf("write recovery marker: %w", err)
}
return nil
}
func clearRestoreMarker(paths artifacts.SessionPaths) error {
if strings.TrimSpace(paths.RestoreMarkerPath) == "" {
return fmt.Errorf("recovery marker path is required")
}
if err := os.Remove(paths.RestoreMarkerPath); err != nil && !os.IsNotExist(err) {
return fmt.Errorf("remove recovery marker: %w", err)
}
return nil
}
func requireCompleteRestore(paths artifacts.SessionPaths) error {
if strings.TrimSpace(paths.RestoreMarkerPath) == "" {
return fmt.Errorf("restore recovery marker path is required")
}
info, err := os.Lstat(paths.RestoreMarkerPath)
if os.IsNotExist(err) {
return nil
}
if err != nil {
return fmt.Errorf("check restore recovery marker: %w", err)
}
if !info.Mode().IsRegular() {
return fmt.Errorf("restore recovery marker is not a regular file; rerun session restore")
}
data, err := os.ReadFile(paths.RestoreMarkerPath)
if err != nil {
return fmt.Errorf("read restore recovery marker: %w", err)
}
var marker restoreMarker
if err := json.Unmarshal(data, &marker); err != nil || marker.StartedAt.IsZero() {
return fmt.Errorf("restore recovery marker is invalid; rerun session restore")
}
return fmt.Errorf("restore is incomplete; rerun session restore before running pipeline stages")
}