aboutsummaryrefslogtreecommitdiff
path: root/objects/object_snapshot.go
blob: a161f27dddd7854c1fc111ce5be081c8560720f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package objects

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"strings"
	"time"
)

type Snapshot struct {
	Tree      ObjectId
	Date      time.Time
	Container string
	Comment   string
}

func (s Snapshot) Type() ObjectType {
	return OTSnapshot
}

func appendKVPair(b []byte, k, v string) []byte {
	b = append(b, []byte(k)...)
	b = append(b, ' ')
	b = append(b, []byte(v)...)
	b = append(b, '\n')
	return b
}

func (s Snapshot) Payload() (out []byte) {
	out = appendKVPair(out, "container", s.Container)
	out = appendKVPair(out, "date", s.Date.Format(time.RFC3339))
	out = appendKVPair(out, "tree", s.Tree.String())

	if s.Comment != "" {
		out = append(out, '\n')
		out = append(out, []byte(s.Comment)...)
	}

	return out
}

func (s *Snapshot) FromPayload(payload []byte) error {
	r := bytes.NewBuffer(payload)

	seenContainer := false
	seenDate := false
	seenTree := false

	for {
		line, err := r.ReadString('\n')
		if err != nil && err != io.EOF {
			return err
		}
		line = strings.TrimSpace(line)

		if line == "" {
			break // Header read successfully
		}

		parts := strings.SplitN(line, " ", 2)
		if len(parts) != 2 {
			return fmt.Errorf("Invalid header: %s", line)
		}

		headerval := strings.TrimSpace(parts[1])
		switch parts[0] {
		case "container":
			s.Container = headerval
			seenContainer = true
		case "date":
			d, err := time.Parse(time.RFC3339, headerval)
			if err != nil {
				return err
			}
			s.Date = d
			seenDate = true
		case "tree":
			oid, err := ParseObjectId(headerval)
			if err != nil {
				return err
			}
			s.Tree = oid
			seenTree = true
		}

		if err == io.EOF {
			break
		}
	}

	if !seenContainer || !seenDate || !seenTree {
		return errors.New("Missing container, date or tree header")
	}

	b := new(bytes.Buffer)
	if _, err := io.Copy(b, r); err != nil {
		return err
	}

	s.Comment = strings.TrimSpace(string(b.Bytes()))
	return nil
}

func (a Snapshot) Equals(b Snapshot) bool {
	return a.Tree.Equals(b.Tree) &&
		a.Container == b.Container &&
		a.Date.Equal(b.Date) &&
		a.Comment == b.Comment
}