##// END OF EJS Templates
lfs: add "bytes" as the unit to the upload/download progress bar...
lfs: add "bytes" as the unit to the upload/download progress bar Facebook also passes `util.bytecount()` as a pretty formatter here, but our progress bar doesn't support that. Differential Revision: https://phab.mercurial-scm.org/D7872

File last commit:

r43812:2fe6121c default
r44534:05881d00 default
Show More
shallowbundle.py
303 lines | 9.9 KiB | text/x-python | PythonLexer
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 # shallowbundle.py - bundle10 implementation for use with shallow repositories
#
# Copyright 2013 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from mercurial.i18n import _
from mercurial.node import bin, hex, nullid
from mercurial import (
bundlerepo,
changegroup,
error,
match,
mdiff,
pycompat,
)
from . import (
Augie Fackler
remotefilelog: consolidate and rename bundle2 capability...
r40544 constants,
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 remotefilelog,
shallowutil,
)
NoFiles = 0
LocalFiles = 1
AllFiles = 2
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 def shallowgroup(cls, self, nodelist, rlog, lookup, units=None, reorder=None):
if not isinstance(rlog, remotefilelog.remotefilelog):
Augie Fackler
formatting: blacken the codebase...
r43346 for c in super(cls, self).group(nodelist, rlog, lookup, units=units):
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 yield c
return
if len(nodelist) == 0:
yield self.close()
return
nodelist = shallowutil.sortnodes(nodelist, rlog.parents)
# add the parent of the first rev
p = rlog.parents(nodelist[0])[0]
nodelist.insert(0, p)
# build deltas
for i in pycompat.xrange(len(nodelist) - 1):
prev, curr = nodelist[i], nodelist[i + 1]
linknode = lookup(curr)
for c in self.nodechunk(rlog, curr, prev, linknode):
yield c
yield self.close()
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 class shallowcg1packer(changegroup.cgpacker):
def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
Pulkit Goyal
shallowutil: introduce a helper function isenabled()...
r40549 if shallowutil.isenabled(self._repo):
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 fastpathlinkrev = False
Augie Fackler
formatting: blacken the codebase...
r43346 return super(shallowcg1packer, self).generate(
commonrevs, clnodes, fastpathlinkrev, source
)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
def group(self, nodelist, rlog, lookup, units=None, reorder=None):
Augie Fackler
formatting: blacken the codebase...
r43346 return shallowgroup(
shallowcg1packer, self, nodelist, rlog, lookup, units=units
)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
def generatefiles(self, changedfiles, *args):
try:
linknodes, commonrevs, source = args
except ValueError:
commonrevs, source, mfdicts, fastpathlinkrev, fnodes, clrevs = args
Pulkit Goyal
shallowutil: introduce a helper function isenabled()...
r40549 if shallowutil.isenabled(self._repo):
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 repo = self._repo
if isinstance(repo, bundlerepo.bundlerepository):
# If the bundle contains filelogs, we can't pull from it, since
# bundlerepo is heavily tied to revlogs. Instead require that
# the user use unbundle instead.
# Force load the filelog data.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 bundlerepo.bundlerepository.file(repo, b'foo')
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 if repo._cgfilespos:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"cannot pull from full bundles",
hint=b"use `hg unbundle` instead",
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return []
filestosend = self.shouldaddfilegroups(source)
if filestosend == NoFiles:
Augie Fackler
formatting: blacken the codebase...
r43346 changedfiles = list(
[f for f in changedfiles if not repo.shallowmatch(f)]
)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
Augie Fackler
formatting: blacken the codebase...
r43346 return super(shallowcg1packer, self).generatefiles(changedfiles, *args)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
def shouldaddfilegroups(self, source):
repo = self._repo
Pulkit Goyal
shallowutil: introduce a helper function isenabled()...
r40549 if not shallowutil.isenabled(repo):
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return AllFiles
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if source == b"push" or source == b"bundle":
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return AllFiles
caps = self._bundlecaps or []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if source == b"serve" or source == b"pull":
Augie Fackler
remotefilelog: consolidate and rename bundle2 capability...
r40544 if constants.BUNDLE2_CAPABLITY in caps:
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return LocalFiles
else:
# Serving to a full repo requires us to serve everything
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b"pulling from a shallow repo\n"))
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return AllFiles
return NoFiles
def prune(self, rlog, missing, commonrevs):
if not isinstance(rlog, remotefilelog.remotefilelog):
Augie Fackler
formatting: blacken the codebase...
r43346 return super(shallowcg1packer, self).prune(
rlog, missing, commonrevs
)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
repo = self._repo
results = []
for fnode in missing:
fctx = repo.filectx(rlog.filename, fileid=fnode)
if fctx.linkrev() not in commonrevs:
results.append(fnode)
return results
def nodechunk(self, revlog, node, prevnode, linknode):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prefix = b''
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 if prevnode == nullid:
rawdata: update callers in shallowbundle...
r43050 delta = revlog.rawdata(node)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 prefix = mdiff.trivialdiffheader(len(delta))
else:
# Actually uses remotefilelog.revdiff which works on nodes, not revs
delta = revlog.revdiff(prevnode, node)
p1, p2 = revlog.parents(node)
flags = revlog.flags(node)
meta = self.builddeltaheader(node, p1, p2, prevnode, linknode, flags)
meta += prefix
l = len(meta) + len(delta)
yield changegroup.chunkheader(l)
yield meta
yield delta
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 def makechangegroup(orig, repo, outgoing, version, source, *args, **kwargs):
Pulkit Goyal
shallowutil: introduce a helper function isenabled()...
r40549 if not shallowutil.isenabled(repo):
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return orig(repo, outgoing, version, source, *args, **kwargs)
original = repo.shallowmatch
try:
# if serving, only send files the clients has patterns for
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if source == b'serve':
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 bundlecaps = kwargs.get('bundlecaps')
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 includepattern = None
excludepattern = None
Augie Fackler
formatting: blacken the codebase...
r43346 for cap in bundlecaps or []:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if cap.startswith(b"includepattern="):
raw = cap[len(b"includepattern=") :]
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 if raw:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 includepattern = raw.split(b'\0')
elif cap.startswith(b"excludepattern="):
raw = cap[len(b"excludepattern=") :]
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 if raw:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 excludepattern = raw.split(b'\0')
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 if includepattern or excludepattern:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.shallowmatch = match.match(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.root, b'', None, includepattern, excludepattern
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 else:
Martin von Zweigbergk
match: delete unused root and cwd arguments from {always,never,exact}() (API)...
r41825 repo.shallowmatch = match.always()
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return orig(repo, outgoing, version, source, *args, **kwargs)
finally:
repo.shallowmatch = original
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 def addchangegroupfiles(orig, repo, source, revmap, trp, expectedfiles, *args):
Pulkit Goyal
shallowutil: introduce a helper function isenabled()...
r40549 if not shallowutil.isenabled(repo):
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 return orig(repo, source, revmap, trp, expectedfiles, *args)
newfiles = 0
visited = set()
revisiondatas = {}
queue = []
# Normal Mercurial processes each file one at a time, adding all
# the new revisions for that file at once. In remotefilelog a file
# revision may depend on a different file's revision (in the case
# of a rename/copy), so we must lay all revisions down across all
# files in topological order.
# read all the file chunks but don't add them
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 progress = repo.ui.makeprogress(_(b'files'), total=expectedfiles)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 while True:
chunkdata = source.filelogheader()
if not chunkdata:
break
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f = chunkdata[b"filename"]
repo.ui.debug(b"adding %s revisions\n" % f)
Martin von Zweigbergk
remotefilelog: use progress helper in shallowbundle...
r40879 progress.increment()
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
if not repo.shallowmatch(f):
fl = repo.file(f)
deltas = source.deltaiter()
fl.addgroup(deltas, revmap, trp)
continue
chain = None
while True:
# returns: (node, p1, p2, cs, deltabase, delta, flags) or None
revisiondata = source.deltachunk(chain)
if not revisiondata:
break
chain = revisiondata[0]
revisiondatas[(f, chain)] = revisiondata
queue.append((f, chain))
if f not in visited:
newfiles += 1
visited.add(f)
if chain is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"received file revlog group is empty"))
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
processed = set()
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 def available(f, node, depf, depnode):
if depnode != nullid and (depf, depnode) not in processed:
if not (depf, depnode) in revisiondatas:
# It's not in the changegroup, assume it's already
# in the repo
return True
# re-add self to queue
queue.insert(0, (f, node))
# add dependency in front
queue.insert(0, (depf, depnode))
return False
return True
skipcount = 0
# Prefetch the non-bundled revisions that we will need
prefetchfiles = []
for f, node in queue:
revisiondata = revisiondatas[(f, node)]
# revisiondata: (node, p1, p2, cs, deltabase, delta, flags)
dependents = [revisiondata[1], revisiondata[2], revisiondata[4]]
for dependent in dependents:
if dependent == nullid or (f, dependent) in revisiondatas:
continue
prefetchfiles.append((f, hex(dependent)))
repo.fileservice.prefetch(prefetchfiles)
# Apply the revisions in topological order such that a revision
# is only written once it's deltabase and parents have been written.
while queue:
f, node = queue.pop(0)
if (f, node) in processed:
continue
skipcount += 1
if skipcount > len(queue) + 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"circular node dependency"))
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
fl = repo.file(f)
revisiondata = revisiondatas[(f, node)]
# revisiondata: (node, p1, p2, cs, deltabase, delta, flags)
node, p1, p2, linknode, deltabase, delta, flags = revisiondata
if not available(f, node, f, deltabase):
continue
rawdata: update callers in shallowbundle...
r43050 base = fl.rawdata(deltabase)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 text = mdiff.patch(base, delta)
Augie Fackler
remotefilelog: check against bytes type instead of buffer and coerce to bytes...
r41292 if not isinstance(text, bytes):
text = bytes(text)
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
meta, text = shallowutil.parsemeta(text)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'copy' in meta:
copyfrom = meta[b'copy']
copynode = bin(meta[b'copyrev'])
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530 if not available(f, node, copyfrom, copynode):
continue
for p in [p1, p2]:
if p != nullid:
if not available(f, node, f, p):
continue
fl.add(text, meta, trp, linknode, p1, p2)
processed.add((f, node))
skipcount = 0
Martin von Zweigbergk
remotefilelog: use progress helper in shallowbundle...
r40879 progress.complete()
Augie Fackler
remotefilelog: import pruned-down remotefilelog extension from hg-experimental...
r40530
return len(revisiondatas), newfiles