largefiles: copy files into .hg/largefiles atomically
Copying from the user cache into .hg/largefiles could fail halfway
though with a partially written file.
--- a/hgext/largefiles/lfutil.py Thu Nov 24 18:12:13 2011 +0100
+++ b/hgext/largefiles/lfutil.py Thu Nov 24 18:13:18 2011 +0100
@@ -77,8 +77,11 @@
try:
util.oslink(src, dest)
except OSError:
- # if hardlinks fail, fallback on copy
- shutil.copyfile(src, dest)
+ # if hardlinks fail, fallback on atomic copy
+ dst = util.atomictempfile(dest)
+ for chunk in util.filechunkiter(open(src)):
+ dst.write(chunk)
+ dst.close()
os.chmod(dest, os.stat(src).st_mode)
def usercachepath(ui, hash):
--- a/tests/test-largefiles-small-disk.t Thu Nov 24 18:12:13 2011 +0100
+++ b/tests/test-largefiles-small-disk.t Thu Nov 24 18:13:18 2011 +0100
@@ -15,6 +15,10 @@
> yield f.read(4)
> raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
> util.filechunkiter = filechunkiter
+ > #
+ > def oslink(src, dest):
+ > raise OSError("no hardlinks, try copying instead")
+ > util.oslink = oslink
> EOF
$ echo "[extensions]" >> $HGRCPATH
@@ -37,3 +41,28 @@
>>> import os; os.path.exists("$HOME/.cache/largefiles/")
False
+
+Make the commit with space on the device:
+
+ $ hg commit -m big
+
+Now make a clone with a full disk, and make sure lfutil.link function
+makes copies instead of hardlinks:
+
+ $ cd ..
+ $ hg --config extensions.criple=$TESTTMP/criple.py clone --pull alice bob
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ getting changed largefiles
+ abort: No space left on device
+ [255]
+
+The largefile is not created in .hg/largefiles:
+
+ $ ls bob/.hg/largefiles
+ dirstate