Skip to content

Commit 48e30a6

Browse files
committed
small big fixes, archive workflow test
1 parent d7c4ca3 commit 48e30a6

File tree

2 files changed

+337
-3
lines changed

2 files changed

+337
-3
lines changed

time_test.go

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
package fstools_test
2+
3+
import (
4+
"encoding/binary"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
"time"
11+
12+
"github.com/dustin/go-humanize"
13+
14+
"github.com/Avalanche-io/c4"
15+
16+
"github.com/absfs/absfs"
17+
"github.com/absfs/basefs"
18+
"github.com/absfs/fstools"
19+
"github.com/absfs/ioutil"
20+
"github.com/absfs/memfs"
21+
"github.com/absfs/osfs"
22+
)
23+
24+
type fileinfo struct {
25+
Digest c4.Digest // 64
26+
Size int64 // 8
27+
TotalSize int64 // 8
28+
Mode os.FileMode // 4
29+
Children int32 // 4
30+
ModTime time.Time // 15
31+
LatestTime time.Time // 15
32+
Name string // ?
33+
}
34+
35+
func (i *fileinfo) MarshalBinary() (data []byte, err error) {
36+
data = make([]byte, 118+len(i.Name))
37+
copy(data[0:64], i.Digest)
38+
binary.LittleEndian.PutUint64(data[64:72], uint64(i.Size))
39+
binary.LittleEndian.PutUint64(data[72:80], uint64(i.TotalSize))
40+
binary.LittleEndian.PutUint32(data[80:84], uint32(i.Mode))
41+
binary.LittleEndian.PutUint32(data[84:88], uint32(i.Children))
42+
timedata, err := i.ModTime.MarshalBinary()
43+
if err != nil {
44+
return nil, err
45+
}
46+
copy(data[88:103], timedata)
47+
48+
timedata, err = i.LatestTime.MarshalBinary()
49+
if err != nil {
50+
return nil, err
51+
}
52+
copy(data[103:118], timedata)
53+
54+
copy(data[118:], []byte(i.Name))
55+
return data, nil
56+
}
57+
58+
func (i *fileinfo) UnmarshalBinary(data []byte) error {
59+
copy(i.Digest, data[0:64])
60+
i.Size = int64(binary.LittleEndian.Uint64(data[64:72]))
61+
i.TotalSize = int64(binary.LittleEndian.Uint64(data[72:80]))
62+
i.Mode = os.FileMode(binary.LittleEndian.Uint32(data[80:84]))
63+
i.Children = int32(binary.LittleEndian.Uint32(data[84:88]))
64+
i.ModTime.UnmarshalBinary(data[88:103])
65+
i.LatestTime.UnmarshalBinary(data[103:118])
66+
i.Name = string(data[118:])
67+
return nil
68+
}
69+
70+
func TestTime(t *testing.T) {
71+
var fs, localfs absfs.FileSystem
72+
var err error
73+
localfs, err = osfs.NewFS()
74+
if err != nil {
75+
t.Fatal(err)
76+
}
77+
path, err := filepath.Abs("../..") // "/xx/d/go/src/github.com"
78+
if err != nil {
79+
t.Fatal(err)
80+
}
81+
fmt.Printf("loading path %q\n", path)
82+
localfs, err = basefs.NewFS(localfs, path)
83+
if err != nil {
84+
t.Fatal(err)
85+
}
86+
87+
fs, err = memfs.NewFS()
88+
if err != nil {
89+
t.Fatal(err)
90+
}
91+
92+
start_time := time.Now()
93+
cnt := 0
94+
err = fstools.Walk(localfs, "/", func(path string, info os.FileInfo, err error) error {
95+
cnt++
96+
97+
if info.IsDir() && path != "/" {
98+
err = fs.Mkdir(path, info.Mode())
99+
if err != nil {
100+
return err
101+
}
102+
}
103+
metadata := &fileinfo{
104+
Size: info.Size(),
105+
ModTime: info.ModTime(),
106+
Mode: info.Mode(),
107+
Name: info.Name(),
108+
}
109+
return SaveMetadata(fs, path, metadata)
110+
})
111+
if err != nil {
112+
t.Fatal(err)
113+
}
114+
fmt.Printf("local walk: %s\n", time.Now().Sub(start_time))
115+
start_time = time.Now()
116+
fmt.Printf("cnt: %d\n", cnt)
117+
err = fstools.PostOrder(fs, nil, "/", func(path string, info os.FileInfo, err error) error {
118+
metadata, err := LoadMetadata(fs, path)
119+
if err != nil {
120+
fmt.Printf("call error %q: %s\n", path, err)
121+
return err
122+
}
123+
124+
err = fs.Chtimes(path, time.Now(), metadata.ModTime)
125+
if err != nil {
126+
fmt.Printf("error %q: %s\n", path, err)
127+
return err
128+
}
129+
130+
return nil
131+
})
132+
if err != nil {
133+
t.Fatal(err)
134+
}
135+
fmt.Printf("local PostOrder for Chtimes: %s\n", time.Now().Sub(start_time))
136+
137+
f, err := fs.Open("/")
138+
if err != nil {
139+
t.Fatal(err)
140+
}
141+
infos, err := f.Readdir(-1)
142+
if err != nil {
143+
t.Fatal(err)
144+
}
145+
f.Close()
146+
147+
path = "/"
148+
for _, info := range infos {
149+
if info.Name() == "." || info.Name() == ".." {
150+
continue
151+
}
152+
153+
metadata, err := LoadMetadata(fs, filepath.Join(path, info.Name()))
154+
if err != nil {
155+
t.Fatal(err)
156+
}
157+
158+
fmt.Printf("%s %q%*s% 8d %s\n", metadata.Mode, metadata.Name, 20-len(metadata.Name), " ", metadata.Size, metadata.ModTime.Format(time.UnixDate))
159+
}
160+
161+
count := new(intStack)
162+
size := new(intStack)
163+
latest := new(timeStack)
164+
var depth int
165+
depth = 0
166+
cwd := ""
167+
err = fstools.PostOrder(fs, nil, "/", func(path string, info os.FileInfo, err error) error {
168+
metadata, err := LoadMetadata(fs, path)
169+
if err != nil {
170+
fmt.Printf("erroring on %q, %s\n", path, err)
171+
return err
172+
}
173+
174+
dir := filepath.Dir(path)
175+
for !strings.HasPrefix(dir, cwd) {
176+
count.add(count.pop())
177+
size.add(size.pop())
178+
latest.add(latest.pop())
179+
cwd = filepath.Dir(cwd)
180+
}
181+
182+
cwd = dir
183+
paths := strings.Split(cwd, "/")
184+
d := len(paths)
185+
if cwd == "/" {
186+
d = 1
187+
}
188+
if depth < len(paths) {
189+
for j, parent := range paths[depth:] {
190+
if parent == "" && j == 0 {
191+
continue
192+
}
193+
count.push(0)
194+
size.push(0)
195+
latest.push(time.Time{})
196+
}
197+
}
198+
count.add(1)
199+
size.add(metadata.Size)
200+
latest.add(metadata.ModTime)
201+
depth = d
202+
203+
if info.IsDir() {
204+
metadata.Children = int32(count.Peek())
205+
metadata.TotalSize = size.Peek()
206+
metadata.LatestTime = latest.Peek()
207+
}
208+
209+
return SaveMetadata(fs, path, metadata)
210+
})
211+
if err != nil {
212+
t.Fatal(err)
213+
}
214+
215+
metadata, err := LoadMetadata(fs, "/")
216+
if err != nil {
217+
t.Fatal(err)
218+
}
219+
220+
fmt.Printf("totals: children, size: %s, %s\n", humanize.Comma(int64(metadata.Children)), humanize.Bytes(uint64(metadata.TotalSize)))
221+
222+
}
223+
224+
type intStack []int64
225+
226+
func (s *intStack) push(size int64) {
227+
(*s) = append((*s), size)
228+
}
229+
230+
func (s *intStack) pop() (size int64) {
231+
if len(*s) == 0 {
232+
return 0
233+
}
234+
size = (*s)[len(*s)-1]
235+
(*s) = (*s)[:len(*s)-1]
236+
return size
237+
}
238+
239+
func (s *intStack) Peek() (size int64) {
240+
if len(*s) == 0 {
241+
return 0
242+
}
243+
return (*s)[len(*s)-1]
244+
}
245+
246+
func (s *intStack) empty() bool {
247+
return len(*s) == 0
248+
}
249+
250+
func (s *intStack) add(size int64) int64 {
251+
(*s)[len(*s)-1] += size
252+
return (*s)[len(*s)-1]
253+
}
254+
255+
type timeStack []time.Time
256+
257+
func (s *timeStack) push(t time.Time) {
258+
(*s) = append((*s), t)
259+
}
260+
261+
func (s *timeStack) pop() (t time.Time) {
262+
if len(*s) == 0 {
263+
return time.Time{}
264+
}
265+
t = (*s)[len(*s)-1]
266+
(*s) = (*s)[:len(*s)-1]
267+
return t
268+
}
269+
270+
func (s *timeStack) Peek() (size time.Time) {
271+
if len(*s) == 0 {
272+
return time.Time{}
273+
}
274+
return (*s)[len(*s)-1]
275+
}
276+
277+
func (s *timeStack) empty() bool {
278+
return len(*s) == 0
279+
}
280+
281+
func (s *timeStack) add(t time.Time) time.Time {
282+
if t.After((*s)[len(*s)-1]) {
283+
(*s)[len(*s)-1] = t
284+
}
285+
return (*s)[len(*s)-1]
286+
}
287+
288+
func SaveMetadata(fs absfs.Filer, path string, metadata *fileinfo) error {
289+
var f absfs.File
290+
var err error
291+
292+
if metadata.Mode&os.ModeDir != 0 {
293+
f, err = fs.OpenFile(path, os.O_RDWR, metadata.Mode)
294+
} else {
295+
f, err = fs.OpenFile(path, os.O_CREATE|os.O_RDWR|os.O_TRUNC, metadata.Mode)
296+
}
297+
if err != nil {
298+
return err
299+
}
300+
defer f.Close()
301+
data, err := metadata.MarshalBinary()
302+
if err != nil {
303+
return err
304+
}
305+
_, err = f.Write(data)
306+
if err != nil {
307+
return err
308+
}
309+
return nil
310+
// return gob.NewEncoder(f).Encode(metadata)
311+
}
312+
313+
func LoadMetadata(fs absfs.Filer, path string) (*fileinfo, error) {
314+
f, err := fs.OpenFile(path, os.O_RDONLY, 0)
315+
if err != nil {
316+
return nil, err
317+
}
318+
defer f.Close()
319+
320+
data, err := ioutil.ReadAll(f)
321+
if err != nil {
322+
return nil, err
323+
}
324+
metadata := new(fileinfo)
325+
err = metadata.UnmarshalBinary(data)
326+
if err != nil {
327+
return nil, err
328+
}
329+
330+
// err = gob.NewDecoder(bytes.NewReader(data)).Decode(metadata)
331+
// if err != nil {
332+
// return nil, err
333+
// }
334+
return metadata, nil
335+
}

walk.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,16 @@ func PreOrder(fs absfs.Filer, options *Options, path string, fn filepath.WalkFun
209209
}
210210
info, err := fs.Stat(path)
211211
if err != nil {
212-
return nil
212+
return err
213213
}
214-
215214
var stack entrystack
216215

217216
stack.push(&entry{0, filepath.Dir(path), info})
218217
for !stack.empty() {
219218
e := stack.pop()
220219
err = fn(e.Path(), e.info, nil)
221220
if err != nil {
222-
if err != filepath.SkipDir {
221+
if err == filepath.SkipDir {
223222
continue
224223
}
225224
return err

0 commit comments

Comments
 (0)