-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtypes.go
More file actions
248 lines (204 loc) · 6.12 KB
/
types.go
File metadata and controls
248 lines (204 loc) · 6.12 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
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package manager
import (
"fmt"
"sort"
"time"
)
// ProjectState represents the state for each rule associated to the project
type ProjectState map[RuleID]RuleState
// Project represents a configured project in the manager
type Project struct {
Name string
Rules []Rule
State ProjectState
CreatedAt time.Time
}
// UpdateState update the rule state of the project, for the specified the ruleID, using the state passed as parameter
func (project *Project) UpdateState(ruleID RuleID, state RuleState) error {
if project.State == nil {
project.State = ProjectState{}
}
project.State[ruleID] = state
return nil
}
// RemoveFilesFromState takes a list of files that are just being removed and
// and update the project state accordingly, for each rule
func (project *Project) RemoveFilesFromState(removedFiles []File) {
for _, rs := range project.State {
files := []SelectedFile{}
for _, f := range rs.Files {
mustBeRemoved := false
for _, removedFile := range removedFiles {
if f.Path == removedFile.Path {
mustBeRemoved = true
break
}
}
if !mustBeRemoved {
files = append(files, f)
}
}
rs.Files = files
project.UpdateState(rs.Rule.GetID(), rs)
}
}
// DebugPrint outputs debug information on project
func (project *Project) DebugPrint() {
fmt.Printf("name: %v\n", project.Name)
for id, rs := range project.State {
fmt.Printf(" - %v\n", id)
for _, f := range rs.Files {
errState := "✅"
if f.Error != nil {
switch f.Error.Reason {
case RuleStateErrorSizeTooSmall:
errState = "⚠️ too small"
case RuleStateErrorObsolete:
errState = "🆘 obsolete"
}
}
fmt.Printf(" %v [%v] %v\n", f.Path, f.Expiration, errState)
}
}
fmt.Println("")
}
// Rule defines the spec of a backup lifetime management
type Rule struct {
Count int
MinAge int
}
// GetID returns the ID identifying the rule (in project rules scope)
func (r Rule) GetID() RuleID {
return RuleID(fmt.Sprintf("rule%d.%d", r.Count, r.MinAge))
}
// RuleID represents an unique identifier for a rule
type RuleID string
// RuleState stores the current state for a rule:
// i.e. next backup date, selected backup files
type RuleState struct {
Rule Rule
Files []SelectedFile
Next *time.Time
// global error (when the error is not associated to a specific file)
Error *RuleStateError
}
// Check takes a date (e.g. today) and checks if the backup must be done
// according to the `Next` field.
func (rs *RuleState) Check(baseDate time.Time) bool {
// when Next is not set, it's because the process has not been executed yet (files might not be available)
// so consider it's not necessary to perform a backup now, waiting for the Next date to be set
if rs.Next == nil {
return false
}
// the process must not be executed when the Next date is not reached yet
if (*rs.Next).After(baseDate) {
return false
}
return true
}
// RuleStateErrorType represents the reason of a RuleStateError
type RuleStateErrorType int
const (
// RuleStateErrorObsolete indicates that a file is expired
RuleStateErrorObsolete RuleStateErrorType = iota
// RuleStateErrorSizeTooSmall indicates that a file size seems too small
RuleStateErrorSizeTooSmall
// RuleStateErrorNoFile indicates that backup files are missing (no specific file is linked)
RuleStateErrorNoFile
)
func (r RuleStateErrorType) String() string {
reason := ""
switch r {
case RuleStateErrorObsolete:
reason = "outdated"
case RuleStateErrorSizeTooSmall:
reason = "file is too small"
case RuleStateErrorNoFile:
reason = "no available file"
default:
reason = "unknown error"
}
return reason
}
// RuleStateError represents an error on a rule
type RuleStateError struct {
File File
Reason RuleStateErrorType
}
func (e *RuleStateError) Error() string {
f := File{}
if e.File == f {
return e.Reason.String()
}
return "error for '" + e.File.Path + "': " + e.Reason.String()
}
// RulesByMinAge stores a slice of rules, sorted by min age
type RulesByMinAge []Rule
func (r RulesByMinAge) Len() int {
return len(r)
}
func (r RulesByMinAge) Less(i, j int) bool {
return r[i].MinAge < r[j].MinAge
}
func (r RulesByMinAge) Swap(i, j int) {
r[i], r[j] = r[j], r[i]
}
// File represents a backup file
type File struct {
Path string
Date time.Time
Size int64
}
// FilesByFolder represents files mapped by their parent folder
type FilesByFolder map[string][]File
// FilesSortedByDateDesc returns a slice of files,
// sorted by date from earlier to older
func FilesSortedByDateDesc(files []File) []File {
f := make([]File, len(files))
copy(f, files)
sorted := sortedFilesByDate(f)
sort.Sort(sort.Reverse(sorted))
return sorted
}
type sortedFilesByDate []File
func (files sortedFilesByDate) Len() int {
return len(files)
}
func (files sortedFilesByDate) Less(i, j int) bool {
return files[i].Date.Before(files[j].Date)
}
func (files sortedFilesByDate) Swap(i, j int) {
files[i], files[j] = files[j], files[i]
}
// SelectedFile represents a file that is selected for a rule
type SelectedFile struct {
File
Expiration time.Time
Error *RuleStateError
}
// SelectedFilesByExpirationDateDesc stores a slice of files (associated to a rule state),
// which should be sorted by expiration date, from older to earlier
type SelectedFilesByExpirationDateDesc []SelectedFile
// SelectedFilesSortedByExpirationDateDesc takes a list of SelectedFile and sort them by expiration date in desc order
func SelectedFilesSortedByExpirationDateDesc(files []SelectedFile) SelectedFilesByExpirationDateDesc {
f := make([]SelectedFile, len(files))
copy(f, files)
sorted := selectedFilesByExpirationDate(f)
sort.Sort(sort.Reverse(sorted))
return SelectedFilesByExpirationDateDesc(sorted)
}
type selectedFilesByExpirationDate []SelectedFile
func (files selectedFilesByExpirationDate) Len() int {
return len(files)
}
func (files selectedFilesByExpirationDate) Less(i, j int) bool {
return files[i].Expiration.Before(files[j].Expiration)
}
func (files selectedFilesByExpirationDate) Swap(i, j int) {
files[i], files[j] = files[j], files[i]
}
// Account represents a user account that can manage projects & files
type Account struct {
Username string
HashedPassword string
}