def getfiles(repo, proto): """A server api for requesting particular versions of particular files. """ if shallowrepo.requirement in repo.requirements: raise error.Abort(_("cannot fetch remote files from shallow repo")) if not isinstance(proto, sshserver.sshserver): raise error.Abort(_("cannot fetch remote files over non-ssh protocol")) def streamer(): fin = proto.fin args = [] responselen = 0 starttime = time.time() while True: request = fin.readline()[:-1] if not request: break hexnode = request[:40] node = bin(hexnode) if node == nullid: yield "0\n" continue path = request[40:] args.append([hexnode, path]) text = _loadfileblob(repo, path, node) response = "%d\n%s" % (len(text), text) responselen += len(response) yield response # it would be better to only flush after processing a whole batch # but currently we don't know if there are more requests coming proto.fout.flush() if repo.ui.configbool("wireproto", "loggetfiles"): _logwireprotorequest(repo, "getfiles", starttime, responselen, args) return wireproto.streamres(streamer())
def stream_out_shallow(repo, proto, other): includepattern = None excludepattern = None raw = other.get("includepattern") if raw: includepattern = raw.split("\0") raw = other.get("excludepattern") if raw: excludepattern = raw.split("\0") oldshallow = state.shallowremote oldmatch = state.match oldnoflatmf = state.noflatmf try: state.shallowremote = True state.match = match.always(repo.root, "") state.noflatmf = other.get("noflatmanifest") == "True" if includepattern or excludepattern: state.match = match.match( repo.root, "", None, includepattern, excludepattern ) streamres = wireproto.stream(repo, proto) # Force the first value to execute, so the file list is computed # within the try/finally scope first = next(streamres.gen) second = next(streamres.gen) def gen(): yield first yield second for value in streamres.gen: yield value return wireproto.streamres(gen()) finally: state.shallowremote = oldshallow state.match = oldmatch state.noflatmf = oldnoflatmf
def getpack(repo, proto, args, version=1): """A server api for requesting a pack of file information.""" if shallowrepo.requirement in repo.requirements: raise error.Abort(_("cannot fetch remote files from shallow repo")) if not isinstance(proto, sshserver.sshserver): raise error.Abort(_("cannot fetch remote files over non-ssh protocol")) def streamer(): # type: () -> Iterable[bytes] """Request format: [<filerequest>,...]\0\0 filerequest = <filename len: 2 byte><filename><count: 4 byte> [<node: 20 byte>,...] Response format: [<fileresponse>,...]<10 null bytes> fileresponse = <filename len: 2 byte><filename><history><deltas> history = <count: 4 byte>[<history entry>,...] historyentry = <node: 20 byte><p1: 20 byte><p2: 20 byte> <linknode: 20 byte><copyfrom len: 2 byte><copyfrom> deltas = <count: 4 byte>[<delta entry>,...] deltaentry = <node: 20 byte><deltabase: 20 byte> <delta len: 8 byte><delta> <metadata> if version == 1: metadata = <nothing> elif version == 2: metadata = <meta len: 4 bytes><metadata-list> metadata-list = [<metadata-item>, ...] metadata-item = <metadata-key: 1 byte> <metadata-value len: 2 byte unsigned> <metadata-value> """ files = _receivepackrequest(proto.fin) args = [] responselen = 0 starttime = time.time() invalidatelinkrev = "invalidatelinkrev" in repo.storerequirements # Sort the files by name, so we provide deterministic results for filename, nodes in sorted(pycompat.iteritems(files)): filename = pycompat.decodeutf8(filename) args.append([filename, [hex(n) for n in nodes]]) fl = repo.file(filename) # Compute history history = [] for rev in fl.ancestors(list(fl.rev(n) for n in nodes), inclusive=True): x, x, x, x, linkrev, p1, p2, node = fl.index[rev] copyfrom = "" p1node = fl.node(p1) p2node = fl.node(p2) if invalidatelinkrev: linknode = nullid else: linknode = repo.changelog.node(linkrev) if p1node == nullid: copydata = fl.renamed(node) if copydata: copyfrom, copynode = copydata p1node = copynode history.append((node, p1node, p2node, linknode, copyfrom)) # Scan and send deltas chain = _getdeltachain(fl, nodes, version) for chunk in wirepack.sendpackpart( filename, history, chain, version=version ): responselen += len(chunk) yield chunk close = wirepack.closepart() responselen += len(close) yield close proto.fout.flush() if repo.ui.configbool("wireproto", "loggetpack"): _logwireprotorequest( repo, "getpackv1" if version == 1 else "getpackv2", starttime, responselen, args, ) return wireproto.streamres(streamer())