# HG changeset patch # User Levi Bard # Date 1355147922 -3600 # Node ID 7e2b9f6a2cd043966fca50a29a9867fb12387a22 # Parent ebc0fa067c07808b77f060e285d0c9d8d25c6750 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 ebc0fa067c07 -r 7e2b9f6a2cd0 hgext/largefiles/reposetup.py --- 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): diff -r ebc0fa067c07 -r 7e2b9f6a2cd0 tests/test-largefiles.t --- 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: