-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathopen_window.go
More file actions
126 lines (115 loc) · 4.82 KB
/
Copy pathopen_window.go
File metadata and controls
126 lines (115 loc) · 4.82 KB
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// SPDX-License-Identifier: Apache-2.0
package git
// openWindow is the one live commit-shaped event window owned by a branch
// worker. It accepts only events with the same author and target; repeated
// writes to the same Git path are last-write-wins while preserving first-seen
// path order.
type openWindow struct {
// Author is event.UserInfo.Username verbatim.
Author string
// Attribution is the window's attribution outcome, taken from its first event. It pairs
// with Author for coalescing: two events share a window only when BOTH the outcome and the
// author agree, so an unresolved event never coalesces with a resolved one that happens
// to carry an empty username. Exact enum equality is right HERE — canAppend compares two
// events from the same watch pipeline, so the outcomes are directly comparable. It is not
// right when comparing against a CommitRequest, which a different subsystem attributes;
// see pendingCommitRequest.matchesWindow.
Attribution AttributionOutcome
// GitTarget is the target this window is bound to. Each finalized commit
// covers exactly one target so per-target encryption and bootstrap
// configuration apply unambiguously.
GitTarget string
// GitTargetNamespace is the namespace of the target, needed by the
// BranchWorker to resolve the target's encryption configuration.
GitTargetNamespace string
// pathOrder records the order in which distinct Git paths were first
// added to the window. Resources renders in this order so the message
// reflects the burst's arrival shape.
pathOrder []string
// pathToEvent holds the latest event for each path inside the window.
// Earlier events at the same path are subsumed (see GUI-toggle rationale
// in the design).
pathToEvent map[string]Event
// writer resolves an event's destination Git path so re-edits inside the
// window collapse onto the same path key.
writer eventContentWriter
// pendingMessage is the CommitRequest message attached to this window (§6.4).
// Once set, whichever path finalizes the window uses it instead of the
// generated grouped-commit message, so an early cut-off still carries intent.
pendingMessage string
// pendingCR identifies the CommitRequest claiming this window; at most one. On
// finalize its outcome is resolved (Committed once the carrying write pushes).
pendingCR *commitRequestID
}
const groupedCommitOperationKinds = 3
func newOpenWindow(e Event, writer eventContentWriter) *openWindow {
return &openWindow{
Author: e.UserInfo.Username,
Attribution: e.Attribution,
GitTarget: e.GitTargetName,
GitTargetNamespace: e.GitTargetNamespace,
pathToEvent: make(map[string]Event),
writer: writer,
}
}
func (w *openWindow) canAppend(e Event) bool {
if w == nil {
return false
}
return e.Attribution == w.Attribution &&
e.UserInfo.Username == w.Author &&
e.GitTargetName == w.GitTarget &&
e.GitTargetNamespace == w.GitTargetNamespace
}
// add records an event in the window. If the path was already present the
// event replaces the previous one (last-write-wins inside a single window);
// otherwise pathOrder is extended.
func (w *openWindow) add(e Event) {
key := windowPathKey(e, w.writer)
if _, exists := w.pathToEvent[key]; !exists {
w.pathOrder = append(w.pathOrder, key)
}
w.pathToEvent[key] = e
}
// orderedEvents returns one event per distinct path, in the order paths were
// first seen. This is what gets applied to the worktree during commit.
func (w *openWindow) orderedEvents() []Event {
out := make([]Event, 0, len(w.pathOrder))
for _, key := range w.pathOrder {
out = append(out, w.pathToEvent[key])
}
return out
}
// windowPathKey derives a stable key from an event's destination path so
// re-edits of the same resource inside an open window collapse.
func windowPathKey(e Event, writer eventContentWriter) string {
filePath := writer.filePathForIdentifier(e.Identifier)
if base := sanitizePath(e.Path); base != "" {
return base + "/" + filePath
}
return filePath
}
// buildGroupedCommitMessageData produces the template context for a grouped
// commit unit. Operations are counted by Operation tag; Resources is the
// deduplicated list of resource refs in arrival order.
func buildGroupedCommitMessageData(author, gitTarget string, events []Event) GroupedCommitMessageData {
operations := make(map[string]int, groupedCommitOperationKinds)
resources := make([]ResourceRef, 0, len(events))
for _, e := range events {
operations[e.Operation]++
resources = append(resources, ResourceRef{
Group: e.Identifier.Group,
Version: e.Identifier.Version,
Resource: e.Identifier.Resource,
Namespace: e.Identifier.Namespace,
Name: e.Identifier.Name,
})
}
return GroupedCommitMessageData{
Author: author,
GitTarget: gitTarget,
Count: len(events),
Operations: operations,
Resources: resources,
}
}