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// 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}