1package restic
2
3import (
4 "encoding/json"
5 "fmt"
6 "strings"
7 "time"
8)
9
10// Snapshot represents a single restic snapshot as returned by
11// `restic snapshots --json`.
12type Snapshot struct {
13 ID string `json:"id"`
14 ShortID string `json:"short_id"`
15 Time time.Time `json:"time"`
16 Hostname string `json:"hostname"`
17 Paths []string `json:"paths"`
18 Tags []string `json:"tags"`
19}
20
21// ParseSnapshots decodes the JSON output of `restic snapshots --json`
22// into a slice of Snapshot values.
23func ParseSnapshots(data []byte) ([]Snapshot, error) {
24 var snapshots []Snapshot
25 if err := json.Unmarshal(data, &snapshots); err != nil {
26 return nil, fmt.Errorf("parsing snapshot JSON: %w", err)
27 }
28 return snapshots, nil
29}
30
31// FormatSnapshotLine returns a single-line human-readable summary of a
32// snapshot, suitable for use as a menu option label. The format is:
33//
34// <short_id> <date> <time> <hostname> <paths> [<tags>]
35//
36// Tags are omitted when empty. Hostname shows "(unknown)" when blank.
37func FormatSnapshotLine(s Snapshot) string {
38 var b strings.Builder
39
40 b.WriteString(s.ShortID)
41 b.WriteString(" ")
42 b.WriteString(s.Time.Format("2006-01-02 15:04"))
43
44 b.WriteString(" ")
45 if s.Hostname == "" {
46 b.WriteString("(unknown)")
47 } else {
48 b.WriteString(s.Hostname)
49 }
50
51 if len(s.Paths) > 0 {
52 b.WriteString(" ")
53 b.WriteString(strings.Join(s.Paths, ", "))
54 }
55
56 if len(s.Tags) > 0 {
57 b.WriteString(" [")
58 b.WriteString(strings.Join(s.Tags, ", "))
59 b.WriteString("]")
60 }
61
62 return b.String()
63}