-
Notifications
You must be signed in to change notification settings - Fork 0
/
waypoint_file.go
89 lines (72 loc) · 2.35 KB
/
waypoint_file.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
package years
import (
"fmt"
"github.com/djherbis/times"
"log"
"os"
"path/filepath"
"time"
)
// WaypointFile is a Waypoint implementation for files/directories
type WaypointFile struct {
// Path of the waypoint
// It's the request field for .prepare() to be called
path string
// timeGetter is a function that returns time of the waypoint based on file time spec
timeGetter func(timeSpec times.Timespec) time.Time
// fileInfo holds the file info for the given file
fileInfo os.FileInfo
// timeSpec holds cross-platform file time creation/modification/access/birth information
timeSpec times.Timespec
// t is the time of the waypoint
t time.Time
// IsRoot is a boolean flag stating for a root waypoint
isRoot bool
// Waypoints are inner children (subdirectories, files, etc)
waypoints []Waypoint
}
type WaypointFiles []*WaypointFile
func (w *WaypointFile) Time() time.Time { return w.t }
func (w *WaypointFile) Identifier() string { return w.path }
func (w *WaypointFile) IsContainer() bool { return w.fileInfo.IsDir() }
func (w *WaypointFile) Children() []Waypoint { return w.waypoints }
func NewWaypointFile(path string, timeGetter func(timeSpec times.Timespec) time.Time) (*WaypointFile, error) {
stat, err := os.Stat(path)
if err != nil {
return nil, fmt.Errorf("could not os.Stat file: %w", err)
}
timeSpec, err := times.Stat(path)
if err != nil {
return nil, fmt.Errorf("could not times.Stat file: %w", err)
}
w := &WaypointFile{path: path, fileInfo: stat, timeSpec: timeSpec, t: timeGetter(timeSpec)}
if stat.IsDir() {
// Go deeper in the directory
innerPaths, err := filepath.Glob(filepath.Join(w.path, "*"))
if err != nil {
return nil, err
}
for _, innerPath := range innerPaths {
child, err := NewWaypointFile(innerPath, timeGetter)
if err != nil {
// TODO(nice-to-have): add configurable way to halt on child error, to log/omit errors, etc
log.Printf("child: NewWaypointFile(%s) failed: %s\n", innerPath, err)
continue
}
// By default, let's sort nodes in Past->Future order
var inserted bool
for i, existed := range w.waypoints {
if existed.Time().After(child.t) {
w.waypoints = append(w.waypoints[:i+1], w.waypoints[i:]...)
w.waypoints[i] = child
inserted = true
break
}
}
if !inserted {
w.waypoints = append(w.waypoints, child)
}
}
}
return w, nil
}