snapshots.go

 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// Paths and tags are omitted when empty. Hostname shows "(unknown)"
37// when blank.
38func FormatSnapshotLine(s Snapshot) string {
39	var b strings.Builder
40
41	b.WriteString(s.ShortID)
42	b.WriteString("  ")
43	b.WriteString(s.Time.Format("2006-01-02 15:04"))
44
45	b.WriteString("  ")
46	if s.Hostname == "" {
47		b.WriteString("(unknown)")
48	} else {
49		b.WriteString(s.Hostname)
50	}
51
52	if len(s.Paths) > 0 {
53		b.WriteString("  ")
54		b.WriteString(strings.Join(s.Paths, ", "))
55	}
56
57	if len(s.Tags) > 0 {
58		b.WriteString("  [")
59		b.WriteString(strings.Join(s.Tags, ", "))
60		b.WriteString("]")
61	}
62
63	return b.String()
64}