[PATCH v2] largefiles: Commit directories that only contain largefiles (issue3548)

Levi Bard taktaktaktaktaktaktaktaktaktak at gmail.com
Wed Dec 12 08:48:23 CST 2012


# HG changeset patch
# User Levi Bard <levi at unity3d.com>
# Date 1355147922 -3600
# Node ID e7e98a8bfe36017d32965856e8ef9a8cb4929353
# Parent  40374059d227850ec2f5fb4f21a1b619136e2a6a
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.

diff -r 40374059d227 -r e7e98a8bfe36 hgext/largefiles/lfutil.py
--- a/hgext/largefiles/lfutil.py	Tue Nov 27 22:24:02 2012 +0100
+++ b/hgext/largefiles/lfutil.py	Mon Dec 10 14:58:42 2012 +0100
@@ -306,7 +306,7 @@
 def isstandin(filename):
     '''Return true if filename is a big file standin. filename must be
     in Mercurial's internal form (slash-separated).'''
-    return filename.startswith(shortname + '/')
+    return filename.startswith(shortname + '/') or filename == shortname
 
 def splitstandin(filename):
     # Split on / because that's what dirstate always uses, even on Windows.
diff -r 40374059d227 -r e7e98a8bfe36 hgext/largefiles/reposetup.py
--- a/hgext/largefiles/reposetup.py	Tue Nov 27 22:24:02 2012 +0100
+++ b/hgext/largefiles/reposetup.py	Mon Dec 10 14:58:42 2012 +0100
@@ -359,11 +359,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.
@@ -394,7 +391,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
 
@@ -467,6 +463,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):
diff -r 40374059d227 -r e7e98a8bfe36 tests/test-largefiles.t
--- a/tests/test-largefiles.t	Tue Nov 27 22:24:02 2012 +0100
+++ 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:
 


More information about the Mercurial-devel mailing list