1package cache
2
3import (
4 "encoding/gob"
5
6 "github.com/MichaelMure/git-bug/bug"
7 "github.com/MichaelMure/git-bug/identity"
8 "github.com/MichaelMure/git-bug/util/lamport"
9)
10
11// Package initialisation used to register the type for (de)serialization
12func init() {
13 gob.Register(BugExcerpt{})
14}
15
16// BugExcerpt hold a subset of the bug values to be able to sort and filter bugs
17// efficiently without having to read and compile each raw bugs.
18type BugExcerpt struct {
19 Id string
20
21 CreateLamportTime lamport.Time
22 EditLamportTime lamport.Time
23 CreateUnixTime int64
24 EditUnixTime int64
25
26 Status bug.Status
27 Labels []bug.Label
28
29 // If author is identity.Bare, LegacyAuthor is set
30 // If author is identity.Identity, AuthorId is set and data is deported
31 // in a IdentityExcerpt
32 LegacyAuthor LegacyAuthorExcerpt
33 AuthorId string
34
35 CreateMetadata map[string]string
36}
37
38// identity.Bare data are directly embedded in the bug excerpt
39type LegacyAuthorExcerpt struct {
40 Name string
41 Login string
42}
43
44func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
45 e := &BugExcerpt{
46 Id: b.Id(),
47 CreateLamportTime: b.CreateLamportTime(),
48 EditLamportTime: b.EditLamportTime(),
49 CreateUnixTime: b.FirstOp().GetUnixTime(),
50 EditUnixTime: snap.LastEditUnix(),
51 Status: snap.Status,
52 Labels: snap.Labels,
53 CreateMetadata: b.FirstOp().AllMetadata(),
54 }
55
56 switch snap.Author.(type) {
57 case *identity.Identity:
58 e.AuthorId = snap.Author.Id()
59 case *identity.Bare:
60 e.LegacyAuthor = LegacyAuthorExcerpt{
61 Login: snap.Author.Login(),
62 Name: snap.Author.Name(),
63 }
64 default:
65 panic("unhandled identity type")
66 }
67
68 return e
69}
70
71func (b *BugExcerpt) HumanId() string {
72 return bug.FormatHumanID(b.Id)
73}
74
75/*
76 * Sorting
77 */
78
79type BugsById []*BugExcerpt
80
81func (b BugsById) Len() int {
82 return len(b)
83}
84
85func (b BugsById) Less(i, j int) bool {
86 return b[i].Id < b[j].Id
87}
88
89func (b BugsById) Swap(i, j int) {
90 b[i], b[j] = b[j], b[i]
91}
92
93type BugsByCreationTime []*BugExcerpt
94
95func (b BugsByCreationTime) Len() int {
96 return len(b)
97}
98
99func (b BugsByCreationTime) Less(i, j int) bool {
100 if b[i].CreateLamportTime < b[j].CreateLamportTime {
101 return true
102 }
103
104 if b[i].CreateLamportTime > b[j].CreateLamportTime {
105 return false
106 }
107
108 // When the logical clocks are identical, that means we had a concurrent
109 // edition. In this case we rely on the timestamp. While the timestamp might
110 // be incorrect due to a badly set clock, the drift in sorting is bounded
111 // by the first sorting using the logical clock. That means that if users
112 // synchronize their bugs regularly, the timestamp will rarely be used, and
113 // should still provide a kinda accurate sorting when needed.
114 return b[i].CreateUnixTime < b[j].CreateUnixTime
115}
116
117func (b BugsByCreationTime) Swap(i, j int) {
118 b[i], b[j] = b[j], b[i]
119}
120
121type BugsByEditTime []*BugExcerpt
122
123func (b BugsByEditTime) Len() int {
124 return len(b)
125}
126
127func (b BugsByEditTime) Less(i, j int) bool {
128 if b[i].EditLamportTime < b[j].EditLamportTime {
129 return true
130 }
131
132 if b[i].EditLamportTime > b[j].EditLamportTime {
133 return false
134 }
135
136 // When the logical clocks are identical, that means we had a concurrent
137 // edition. In this case we rely on the timestamp. While the timestamp might
138 // be incorrect due to a badly set clock, the drift in sorting is bounded
139 // by the first sorting using the logical clock. That means that if users
140 // synchronize their bugs regularly, the timestamp will rarely be used, and
141 // should still provide a kinda accurate sorting when needed.
142 return b[i].EditUnixTime < b[j].EditUnixTime
143}
144
145func (b BugsByEditTime) Swap(i, j int) {
146 b[i], b[j] = b[j], b[i]
147}