New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rename files in cache too if they exist #3480
Conversation
|
cb7fa09
to
acd0bda
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great thing to do - thanks for tackling this.
I put some notes inline.
I think we should try to write a test for this, then we'll be sure it works properly on all OSes - what do you think?
vfs/cache.go
Outdated
return true | ||
} | ||
} | ||
if err = os.Link(osOldPath, osNewPath); err == nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use os.Rename always? Isn't it equivalent to Link+Remove?
os.Link doesn't work on all windows fileystems (eg FAT)
os.Rename may have troubles renaming over an existing file on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not much of difference either way. Didn't try it on windows, if it doesn't work there, I will just remove the section that tries to link.
As for rename, what do you think would be better? Remove the existing destination or do nothing and print an error log?
@@ -270,12 +270,63 @@ func (c *cache) exists(name string) bool { | |||
if err != nil { | |||
return false | |||
} | |||
if fi.IsDir() { | |||
// checks for non-regular files (e.g. directories, symlinks, devices, etc.) | |||
if !fi.Mode().IsRegular() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
vfs/cache.go
Outdated
return false | ||
} | ||
return true | ||
} | ||
|
||
// renames the file in cache | ||
func (c *cache) rename(name string, newName string) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be more go style to return an annotated error, than a boolean here I think...
vfs/cache.go
Outdated
} | ||
if !sfi.Mode().IsRegular() { | ||
// cannot copy non-regular files (e.g., directories, symlinks, devices, etc.) | ||
fs.Errorf("rename: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... so instead of fs.Errorf(...); return false
do
return errors.Errorf("rename: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String()))
vfs/cache.go
Outdated
dfi, err := os.Stat(osNewPath) | ||
if err != nil { | ||
if !os.IsNotExist(err) { | ||
fs.Errorf(name, "rename: Failed to stat destination: %v", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...and likewise wrap the errors when you have them so this should be
return errors.Wrap(err, "rename: Failed to stat destination")
vfs/file.go
Outdated
|
||
// Rename in the cache too if it exists | ||
if f.d.vfs.Opt.CacheMode >= CacheModeWrites && f.d.vfs.cache.exists(f.Path()) { | ||
if ok := f.d.vfs.cache.rename(f.Path(), newPath); !ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then this should be something like
err = f.d.vfs.cache.rename(f.Path(), newPath)
if err != nil {
fs.Infof(f.Path(), "File.Rename failed in Cache: %v", err)
}
vfs/cache.go
Outdated
osNewPath := c.toOSPath(newName) | ||
sfi, err := os.Stat(osOldPath) | ||
if err != nil { | ||
return false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return errors.Wrap(err, "rename: source file")
fs.Errorf("rename: non-regular destination file: %s (%q)", dfi.Name(), dfi.Mode().String()) | ||
return false | ||
} | ||
if os.SameFile(sfi, dfi) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How likely do you think os.SameFile
is to return true here? I'm struggling to see how it might happen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just thought it better to be safe than have an issue afterwards in case it ever happens. This avoids silent failures from rename in case both the source & destination point to the same file via links.
Source: https://forum.golangbridge.org/t/os-rename-and-hard-link-overwrite/7838
Thanks for the review. As for the tests, I may need some help with that. Haven't written any tests before 😅 |
Take a look in the cache_test.go file there is a fair amount of machinery in there. You'd write a test for the rename function in there. It would be good if we could also adjust the rename file test to check the correct things are happening in the cache but that might be a bit trickier. Line 469 in d1a39dc
|
How are you doing with this? Need help finishing it off? |
Need to get some time together to finish off the tests. Will be updating it by the weekend at the latest. |
Great :-) Let me know if you need any help. |
Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com>
Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com>
acd0bda
to
112f2d0
Compare
@ncw Sorry for the delay, but doesn't look like I will have any time in the next 2-3 months to write any tests and finish this. I have just pushed the latest changeset that I had started on and hope that you or someone else can use that and finish this PR. |
That is no problem. I'll try to get this merged one way or another in 1.51 @bdutro do you fancy finishing this off? |
@ncw, sure. How should I add my changes? It seems like the proper way is to do a pull request against @darthShadow's branch, which would then get added to this pull request when it's merged. Edit: Also, does this just need a test added, or do we need to fix the test failures as well? |
I would pull the current changes into a local branch, add your commits there then make a new pull request I think.
Both I think. |
This is now merged in #3688 - thank you @darthShadow for the initial work and @bdutro for finishing it off. |
What is the purpose of this change?
Files in cache should be renamed too along with renames on the remote
Was the change discussed in an issue or in the forum before?
#2907
Checklist