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 Title string
29 LenComments int
30
31 // If author is identity.Bare, LegacyAuthor is set
32 // If author is identity.Identity, AuthorId is set and data is deported
33 // in a IdentityExcerpt
34 LegacyAuthor LegacyAuthorExcerpt
35 AuthorId string
36
37 CreateMetadata map[string]string
38}
39
40// identity.Bare data are directly embedded in the bug excerpt
41type LegacyAuthorExcerpt struct {
42 Name string
43 Login string
44}
45
46func NewBugExcerpt(b bug.Interface, snap *bug.Snapshot) *BugExcerpt {
47 e := &BugExcerpt{
48 Id: b.Id(),
49 CreateLamportTime: b.CreateLamportTime(),
50 EditLamportTime: b.EditLamportTime(),
51 CreateUnixTime: b.FirstOp().GetUnixTime(),
52 EditUnixTime: snap.LastEditUnix(),
53 Status: snap.Status,
54 Labels: snap.Labels,
55 Title: snap.Title,
56 LenComments: len(snap.Comments),
57 CreateMetadata: b.FirstOp().AllMetadata(),
58 }
59
60 switch snap.Author.(type) {
61 case *identity.Identity:
62 e.AuthorId = snap.Author.Id()
63 case *identity.Bare:
64 e.LegacyAuthor = LegacyAuthorExcerpt{
65 Login: snap.Author.Login(),
66 Name: snap.Author.Name(),
67 }
68 default:
69 panic("unhandled identity type")
70 }
71
72 return e
73}
74
75func (b *BugExcerpt) HumanId() string {
76 return bug.FormatHumanID(b.Id)
77}
78
79/*
80 * Sorting
81 */
82
83type BugsById []*BugExcerpt
84
85func (b BugsById) Len() int {
86 return len(b)
87}
88
89func (b BugsById) Less(i, j int) bool {
90 return b[i].Id < b[j].Id
91}
92
93func (b BugsById) Swap(i, j int) {
94 b[i], b[j] = b[j], b[i]
95}
96
97type BugsByCreationTime []*BugExcerpt
98
99func (b BugsByCreationTime) Len() int {
100 return len(b)
101}
102
103func (b BugsByCreationTime) Less(i, j int) bool {
104 if b[i].CreateLamportTime < b[j].CreateLamportTime {
105 return true
106 }
107
108 if b[i].CreateLamportTime > b[j].CreateLamportTime {
109 return false
110 }
111
112 // When the logical clocks are identical, that means we had a concurrent
113 // edition. In this case we rely on the timestamp. While the timestamp might
114 // be incorrect due to a badly set clock, the drift in sorting is bounded
115 // by the first sorting using the logical clock. That means that if users
116 // synchronize their bugs regularly, the timestamp will rarely be used, and
117 // should still provide a kinda accurate sorting when needed.
118 return b[i].CreateUnixTime < b[j].CreateUnixTime
119}
120
121func (b BugsByCreationTime) Swap(i, j int) {
122 b[i], b[j] = b[j], b[i]
123}
124
125type BugsByEditTime []*BugExcerpt
126
127func (b BugsByEditTime) Len() int {
128 return len(b)
129}
130
131func (b BugsByEditTime) Less(i, j int) bool {
132 if b[i].EditLamportTime < b[j].EditLamportTime {
133 return true
134 }
135
136 if b[i].EditLamportTime > b[j].EditLamportTime {
137 return false
138 }
139
140 // When the logical clocks are identical, that means we had a concurrent
141 // edition. In this case we rely on the timestamp. While the timestamp might
142 // be incorrect due to a badly set clock, the drift in sorting is bounded
143 // by the first sorting using the logical clock. That means that if users
144 // synchronize their bugs regularly, the timestamp will rarely be used, and
145 // should still provide a kinda accurate sorting when needed.
146 return b[i].EditUnixTime < b[j].EditUnixTime
147}
148
149func (b BugsByEditTime) Swap(i, j int) {
150 b[i], b[j] = b[j], b[i]
151}