largefiles: commit directories that only contain largefiles (
issue3548)
If we pass a directory to commit whose only commitable files
are largefiles, the core commit code aborts before finding
the largefiles.
So we do the following:
For directories that only have largefiles as matches,
we explicitly add the largefiles to the matchlist and remove
the directory.
In other cases, we leave the match list unmodified.
--- a/hgext/largefiles/reposetup.py Thu Dec 06 13:21:27 2012 -0600
+++ b/hgext/largefiles/reposetup.py Mon Dec 10 14:58:42 2012 +0100
@@ -355,11 +355,8 @@
lfdirstate.write()
return result
- for f in match.files():
- if lfutil.isstandin(f):
- raise util.Abort(
- _('file "%s" is a largefile standin') % f,
- hint=('commit the largefile itself instead'))
+ lfiles = lfutil.listlfiles(self)
+ match._files = self._subdirlfs(match.files(), lfiles)
# Case 2: user calls commit with specified patterns: refresh
# any matching big files.
@@ -390,7 +387,6 @@
# standins corresponding to the big files requested by the
# user. Have to modify _files to prevent commit() from
# complaining "not tracked" for big files.
- lfiles = lfutil.listlfiles(self)
match = copy.copy(match)
origmatchfn = match.matchfn
@@ -463,6 +459,60 @@
return super(lfilesrepo, self).push(remote, force, revs,
newbranch)
+ def _subdirlfs(self, files, lfiles):
+ '''
+ Adjust matched file list
+ If we pass a directory to commit whose only commitable files
+ are largefiles, the core commit code aborts before finding
+ the largefiles.
+ So we do the following:
+ For directories that only have largefiles as matches,
+ we explicitly add the largefiles to the matchlist and remove
+ the directory.
+ In other cases, we leave the match list unmodified.
+ '''
+ actualfiles = []
+ dirs = []
+ regulars = []
+
+ for f in files:
+ if lfutil.isstandin(f + '/'):
+ raise util.Abort(
+ _('file "%s" is a largefile standin') % f,
+ hint=('commit the largefile itself instead'))
+ # Scan directories
+ if os.path.isdir(self.wjoin(f)):
+ dirs.append(f)
+ else:
+ regulars.append(f)
+
+ for f in dirs:
+ matcheddir = False
+ d = self.dirstate.normalize(f) + '/'
+ # Check for matched normal files
+ for mf in regulars:
+ if self.dirstate.normalize(mf).startswith(d):
+ actualfiles.append(f)
+ matcheddir = True
+ break
+ if not matcheddir:
+ # If no normal match, manually append
+ # any matching largefiles
+ for lf in lfiles:
+ if self.dirstate.normalize(lf).startswith(d):
+ actualfiles.append(lf)
+ if not matcheddir:
+ actualfiles.append(lfutil.standin(f))
+ matcheddir = True
+ # Nothing in dir, so readd it
+ # and let commit reject it
+ if not matcheddir:
+ actualfiles.append(f)
+
+ # Always add normal files
+ actualfiles += regulars
+ return actualfiles
+
repo.__class__ = lfilesrepo
def checkrequireslfiles(ui, repo, **kwargs):
--- a/tests/test-largefiles.t Thu Dec 06 13:21:27 2012 -0600
+++ b/tests/test-largefiles.t Mon Dec 10 14:58:42 2012 +0100
@@ -345,6 +345,63 @@
A sub2/large6
A sub2/large7
+Committing directories containing only largefiles.
+
+ $ mkdir -p z/y/x/m
+ $ touch z/y/x/m/large1
+ $ touch z/y/x/large2
+ $ hg add --large z/y/x/m/large1 z/y/x/large2
+ $ hg commit -m "Subdir with directory only containing largefiles" z
+ Invoking status precommit hook
+ M large3
+ A large5
+ A sub2/large6
+ A sub2/large7
+ A z/y/x/large2
+ A z/y/x/m/large1
+ $ hg rollback --quiet
+ $ touch z/y/x/m/normal
+ $ hg add z/y/x/m/normal
+ $ hg commit -m "Subdir with mixed contents" z
+ Invoking status precommit hook
+ M large3
+ A large5
+ A sub2/large6
+ A sub2/large7
+ A z/y/x/large2
+ A z/y/x/m/large1
+ A z/y/x/m/normal
+ $ hg st
+ M large3
+ A large5
+ A sub2/large6
+ A sub2/large7
+ $ hg rollback --quiet
+ $ hg revert z/y/x/large2 z/y/x/m/large1
+ $ rm z/y/x/large2 z/y/x/m/large1
+ $ hg commit -m "Subdir with normal contents" z
+ Invoking status precommit hook
+ M large3
+ A large5
+ A sub2/large6
+ A sub2/large7
+ A z/y/x/m/normal
+ $ hg st
+ M large3
+ A large5
+ A sub2/large6
+ A sub2/large7
+ $ hg rollback --quiet
+ $ hg revert --quiet z
+ $ hg commit -m "Empty subdir" z
+ abort: z: no match under directory!
+ [255]
+ $ rm -rf z
+ $ hg ci -m "standin" .hglf
+ abort: file ".hglf" is a largefile standin
+ (commit the largefile itself instead)
+ [255]
+
Test "hg status" with combination of 'file pattern' and 'directory
pattern' for largefiles: