This is how it is done everywhere else.
But the logic here is a bit more complex because shallow clone
needs to reference the original linknode implementation. But
at least now all function implementations are defined in the
same place.
| hg-reviewers | 
This is how it is done everywhere else.
But the logic here is a bit more complex because shallow clone
needs to reference the original linknode implementation. But
at least now all function implementations are defined in the
same place.
| Automatic diff as part of commit; lint not applicable. | 
| Automatic diff as part of commit; unit tests not applicable. | 
| Path | Packages | |||
|---|---|---|---|---|
| M | mercurial/changegroup.py (38 lines) | 
| Status | Author | Revision | |
|---|---|---|---|
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | ||
| Closed | indygreg | 
| mfdicts = None | mfdicts = None | ||||
| if self._ellipses and self._isshallow: | if self._ellipses and self._isshallow: | ||||
| mfdicts = [(self._repo.manifestlog[n].read(), lr) | mfdicts = [(self._repo.manifestlog[n].read(), lr) | ||||
| for (n, lr) in mfs.iteritems()] | for (n, lr) in mfs.iteritems()] | ||||
| mfs.clear() | mfs.clear() | ||||
| clrevs = set(cl.rev(x) for x in clnodes) | clrevs = set(cl.rev(x) for x in clnodes) | ||||
| if not fastpathlinkrev: | for chunk in self.generatefiles(changedfiles, commonrevs, | ||||
| def linknodes(unused, fname): | source, mfdicts, fastpathlinkrev, | ||||
| return fnodes.get(fname, {}) | fnodes, clrevs): | ||||
| else: | |||||
| cln = cl.node | |||||
| def linknodes(filerevlog, fname): | |||||
| llr = filerevlog.linkrev | |||||
| fln = filerevlog.node | |||||
| revs = ((r, llr(r)) for r in filerevlog) | |||||
| return dict((fln(r), cln(lr)) for r, lr in revs if lr in clrevs) | |||||
| for chunk in self.generatefiles(changedfiles, linknodes, commonrevs, | |||||
| source, mfdicts): | |||||
| yield chunk | yield chunk | ||||
| yield self._close() | yield self._close() | ||||
| if clnodes: | if clnodes: | ||||
| repo.hook('outgoing', node=hex(clnodes[0]), source=source) | repo.hook('outgoing', node=hex(clnodes[0]), source=source) | ||||
| def _generatechangelog(self, cl, nodes): | def _generatechangelog(self, cl, nodes): | ||||
| for x in self._packmanifests(dir, store, revs, lookupfn): | for x in self._packmanifests(dir, store, revs, lookupfn): | ||||
| size += len(x) | size += len(x) | ||||
| yield x | yield x | ||||
| self._verbosenote(_('%8.i (manifests)\n') % size) | self._verbosenote(_('%8.i (manifests)\n') % size) | ||||
| yield self._manifestsend | yield self._manifestsend | ||||
| # The 'source' parameter is useful for extensions | # The 'source' parameter is useful for extensions | ||||
| def generatefiles(self, changedfiles, linknodes, commonrevs, source, | def generatefiles(self, changedfiles, commonrevs, source, | ||||
| mfdicts): | mfdicts, fastpathlinkrev, fnodes, clrevs): | ||||
| changedfiles = list(filter(self._filematcher, changedfiles)) | changedfiles = list(filter(self._filematcher, changedfiles)) | ||||
| if not fastpathlinkrev: | |||||
| def normallinknodes(unused, fname): | |||||
| return fnodes.get(fname, {}) | |||||
| else: | |||||
| cln = self._repo.changelog.node | |||||
| def normallinknodes(store, fname): | |||||
| flinkrev = store.linkrev | |||||
| fnode = store.node | |||||
| revs = ((r, flinkrev(r)) for r in store) | |||||
| return dict((fnode(r), cln(lr)) | |||||
| for r, lr in revs if lr in clrevs) | |||||
| if self._isshallow: | if self._isshallow: | ||||
| # In a shallow clone, the linknodes callback needs to also include | # In a shallow clone, the linknodes callback needs to also include | ||||
| # those file nodes that are in the manifests we sent but weren't | # those file nodes that are in the manifests we sent but weren't | ||||
| # introduced by those manifests. | # introduced by those manifests. | ||||
| commonctxs = [self._repo[c] for c in commonrevs] | commonctxs = [self._repo[c] for c in commonrevs] | ||||
| oldlinknodes = linknodes | |||||
| clrev = self._repo.changelog.rev | clrev = self._repo.changelog.rev | ||||
| # Defining this function has a side-effect of overriding the | # Defining this function has a side-effect of overriding the | ||||
| # function of the same name that was passed in as an argument. | # function of the same name that was passed in as an argument. | ||||
| # TODO have caller pass in appropriate function. | # TODO have caller pass in appropriate function. | ||||
| def linknodes(flog, fname): | def linknodes(flog, fname): | ||||
| for c in commonctxs: | for c in commonctxs: | ||||
| try: | try: | ||||
| fnode = c.filenode(fname) | fnode = c.filenode(fname) | ||||
| self._clrevtolocalrev[c.rev()] = flog.rev(fnode) | self._clrevtolocalrev[c.rev()] = flog.rev(fnode) | ||||
| except error.ManifestLookupError: | except error.ManifestLookupError: | ||||
| pass | pass | ||||
| links = oldlinknodes(flog, fname) | links = normallinknodes(flog, fname) | ||||
| if len(links) != len(mfdicts): | if len(links) != len(mfdicts): | ||||
| for mf, lr in mfdicts: | for mf, lr in mfdicts: | ||||
| fnode = mf.get(fname, None) | fnode = mf.get(fname, None) | ||||
| if fnode in links: | if fnode in links: | ||||
| links[fnode] = min(links[fnode], lr, key=clrev) | links[fnode] = min(links[fnode], lr, key=clrev) | ||||
| elif fnode: | elif fnode: | ||||
| links[fnode] = lr | links[fnode] = lr | ||||
| return links | return links | ||||
| else: | |||||
| linknodes = normallinknodes | |||||
| return self._generatefiles(changedfiles, linknodes, commonrevs, source) | return self._generatefiles(changedfiles, linknodes, commonrevs, source) | ||||
| def _generatefiles(self, changedfiles, linknodes, commonrevs, source): | def _generatefiles(self, changedfiles, linknodes, commonrevs, source): | ||||
| repo = self._repo | repo = self._repo | ||||
| cl = repo.changelog | cl = repo.changelog | ||||
| progress = repo.ui.makeprogress(_('bundling'), unit=_('files'), | progress = repo.ui.makeprogress(_('bundling'), unit=_('files'), | ||||
| total=len(changedfiles)) | total=len(changedfiles)) | ||||