forked from elastic/beats
-
Notifications
You must be signed in to change notification settings - Fork 0
/
action.go
157 lines (139 loc) · 4.62 KB
/
action.go
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package file_integrity
import (
"math/bits"
"strings"
)
// Action is a description of the changes described by an event.
type Action uint8
// ActionArray is just syntactic sugar to invoke methods on []Action receiver
type ActionArray []Action
// List of possible Actions.
const (
None Action = 0
AttributesModified = 1 << (iota - 1)
Created
Deleted
Updated
Moved
ConfigChange
)
var actionNames = map[Action]string{
None: "none",
AttributesModified: "attributes_modified",
Created: "created",
Deleted: "deleted",
Updated: "updated",
Moved: "moved",
ConfigChange: "config_change",
}
type actionOrderKey struct {
ExistsBefore, ExistsNow bool
Action Action
}
// Given the previous and current state of the file, and an action mask
// returns a meaningful ordering for the actions in the mask
var actionOrderMap = map[actionOrderKey]ActionArray{
{false, false, Created | Deleted}: {Created, Deleted},
{true, true, Created | Deleted}: {Deleted, Created},
{false, false, Moved | Created}: {Created, Moved},
{true, true, Moved | Created}: {Moved, Created},
{true, true, Moved | Deleted}: {Deleted, Moved},
{false, false, Moved | Deleted}: {Moved, Deleted},
{false, true, Updated | Created}: {Created, Updated},
{true, false, Updated | Deleted}: {Updated, Deleted},
{false, true, Updated | Moved}: {Moved, Updated},
{true, false, Updated | Moved}: {Updated, Moved},
{false, true, Moved | Created | Deleted}: {Created, Deleted, Moved},
{true, false, Moved | Created | Deleted}: {Deleted, Created, Moved},
{false, false, Updated | Moved | Created}: {Created, Updated, Moved},
{true, true, Updated | Moved | Created}: {Moved, Created, Updated},
{false, false, Updated | Moved | Deleted}: {Moved, Updated, Deleted},
{true, true, Updated | Moved | Deleted}: {Deleted, Moved, Updated},
{false, false, Updated | Created | Deleted}: {Created, Updated, Deleted},
{true, true, Updated | Created | Deleted}: {Deleted, Created, Updated},
{false, true, Updated | Moved | Created | Deleted}: {Created, Deleted, Moved, Updated},
{true, false, Updated | Moved | Created | Deleted}: {Deleted, Created, Updated, Moved},
}
func (action Action) isMultiple() bool {
return bits.OnesCount8(uint8(action)) > 1
}
func (action Action) String() string {
if name, found := actionNames[action]; found {
return name
}
var list []string
for flag, name := range actionNames {
if action&flag != 0 {
action ^= flag
list = append(list, name)
}
}
if action != 0 {
list = append(list, "unknown")
}
return strings.Join(list, "|")
}
// MarshalText marshals the Action to a textual representation of itself.
func (action Action) MarshalText() ([]byte, error) { return []byte(action.String()), nil }
func resolveActionOrder(action Action, existedBefore, existsNow bool) ActionArray {
if action == None {
return nil
}
if !action.isMultiple() {
return []Action{action}
}
key := actionOrderKey{existedBefore, existsNow, action}
if result, ok := actionOrderMap[key]; ok {
return result
}
// Can't resolve a meaningful order for the actions, usually the file
// has received further actions after the event being processed
return action.InAnyOrder()
}
func (action Action) InOrder(existedBefore, existsNow bool) ActionArray {
hasConfigChange := 0 != action&ConfigChange
hasUpdate := 0 != action&Updated
hasAttrMod := 0 != action&AttributesModified
action = Action(int(action) & int(^(ConfigChange | AttributesModified)))
if hasAttrMod {
action |= Updated
}
result := resolveActionOrder(action, existedBefore, existsNow)
if hasConfigChange {
result = append(result, ConfigChange)
}
if hasAttrMod {
for idx, value := range result {
if value == Updated {
if !hasUpdate {
result[idx] = AttributesModified
} else {
result = append(result, None)
copy(result[idx+2:], result[idx+1:])
result[idx+1] = AttributesModified
}
break
}
}
}
return result
}
func (action Action) InAnyOrder() ActionArray {
if !action.isMultiple() {
return []Action{action}
}
var result []Action
for k := range actionNames {
if 0 != action&k {
result = append(result, k)
}
}
return result
}
func (actions ActionArray) StringArray() []string {
result := make([]string, len(actions))
for index, value := range actions {
result[index] = value.String()
}
return result
}