Skip to content

Commit b59c1c3

Browse files
committed
memfs: Add deterministic modification times
Memfs returns the latest time on every invocation of ModTime(), which causes issues in go-git when an accurate modification time is required. Relates to go-git/go-git#1342, when using the latest version of go-git-fixtures. Signed-off-by: Paulo Gomes <[email protected]>
1 parent a0a6b08 commit b59c1c3

File tree

3 files changed

+45
-8
lines changed

3 files changed

+45
-8
lines changed

memfs/memory.go

+13-8
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ type file struct {
228228
position int64
229229
flag int
230230
mode os.FileMode
231+
modTime time.Time
231232

232233
isClosed bool
233234
}
@@ -291,6 +292,7 @@ func (f *file) WriteAt(p []byte, off int64) (int, error) {
291292
return 0, errors.New("write not supported")
292293
}
293294

295+
f.modTime = time.Now()
294296
n, err := f.content.WriteAt(p, off)
295297
f.position = off + int64(n)
296298

@@ -322,6 +324,7 @@ func (f *file) Duplicate(filename string, mode os.FileMode, flag int) billy.File
322324
content: f.content,
323325
mode: mode,
324326
flag: flag,
327+
modTime: f.modTime,
325328
}
326329

327330
if isTruncate(flag) {
@@ -337,9 +340,10 @@ func (f *file) Duplicate(filename string, mode os.FileMode, flag int) billy.File
337340

338341
func (f *file) Stat() (os.FileInfo, error) {
339342
return &fileInfo{
340-
name: f.Name(),
341-
mode: f.mode,
342-
size: f.content.Len(),
343+
name: f.Name(),
344+
mode: f.mode,
345+
size: f.content.Len(),
346+
modTime: f.modTime,
343347
}, nil
344348
}
345349

@@ -354,9 +358,10 @@ func (f *file) Unlock() error {
354358
}
355359

356360
type fileInfo struct {
357-
name string
358-
size int
359-
mode os.FileMode
361+
name string
362+
size int
363+
mode os.FileMode
364+
modTime time.Time
360365
}
361366

362367
func (fi *fileInfo) Name() string {
@@ -371,8 +376,8 @@ func (fi *fileInfo) Mode() os.FileMode {
371376
return fi.mode
372377
}
373378

374-
func (*fileInfo) ModTime() time.Time {
375-
return time.Now()
379+
func (fi *fileInfo) ModTime() time.Time {
380+
return fi.modTime
376381
}
377382

378383
func (fi *fileInfo) IsDir() bool {

memfs/memory_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/go-git/go-billy/v5"
1111
"github.com/go-git/go-billy/v5/util"
1212
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
1314
)
1415

1516
func TestRootExists(t *testing.T) {
@@ -28,6 +29,35 @@ func TestCapabilities(t *testing.T) {
2829
assert.Equal(t, billy.DefaultCapabilities&^billy.LockCapability, caps)
2930
}
3031

32+
func TestModTime(t *testing.T) {
33+
fs := New()
34+
_, err := fs.Create("/file1")
35+
require.NoError(t, err)
36+
37+
_, err = fs.Create("/file2")
38+
require.NoError(t, err)
39+
40+
fi1a, err := fs.Stat("/file1")
41+
require.NoError(t, err)
42+
43+
fi2, err := fs.Stat("/file2")
44+
require.NoError(t, err)
45+
46+
fi1b, err := fs.Stat("/file1")
47+
require.NoError(t, err)
48+
49+
modtime := fi1a.ModTime()
50+
51+
// file 1 and file 2 should have different mod times.
52+
assert.NotEqual(t, modtime, fi2.ModTime())
53+
54+
// a new file info for the same unmodified file, should still match mod time.
55+
assert.Equal(t, modtime, fi1b.ModTime())
56+
57+
// new calls to ModTime() retain existing mod time.
58+
assert.Equal(t, modtime, fi1a.ModTime())
59+
}
60+
3161
func TestNegativeOffsets(t *testing.T) {
3262
fs := New()
3363
f, err := fs.Create("negative")

memfs/storage.go

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"path/filepath"
99
"strings"
1010
"sync"
11+
"time"
1112
)
1213

1314
type storage struct {
@@ -46,6 +47,7 @@ func (s *storage) New(path string, mode os.FileMode, flag int) (*file, error) {
4647
content: &content{name: name},
4748
mode: mode,
4849
flag: flag,
50+
modTime: time.Now(),
4951
}
5052

5153
s.files[path] = f

0 commit comments

Comments
 (0)