Show More
@@ -12,16 +12,14 b' import stat' | |||
|
12 | 12 | import time |
|
13 | 13 | |
|
14 | 14 | from mercurial.i18n import _ |
|
15 |
from mercurial.node import bin, hex, nullid |
|
|
15 | from mercurial.node import bin, hex, nullid | |
|
16 | 16 | from mercurial import ( |
|
17 | ancestor, | |
|
18 | 17 | changegroup, |
|
19 | 18 | changelog, |
|
20 | 19 | context, |
|
21 | 20 | error, |
|
22 | 21 | extensions, |
|
23 | 22 | match, |
|
24 | pycompat, | |
|
25 | 23 | store, |
|
26 | 24 | streamclone, |
|
27 | 25 | util, |
@@ -30,11 +28,9 b' from mercurial import (' | |||
|
30 | 28 | wireprotov1server, |
|
31 | 29 | ) |
|
32 | 30 | from . import ( |
|
33 | constants, | |
|
34 | 31 | lz4wrapper, |
|
35 | 32 | shallowrepo, |
|
36 | 33 | shallowutil, |
|
37 | wirepack, | |
|
38 | 34 | ) |
|
39 | 35 | |
|
40 | 36 | _sshv1server = wireprotoserver.sshv1protocolhandler |
@@ -86,8 +82,6 b' def onetimesetup(ui):' | |||
|
86 | 82 | 'getfiles', '', permission='pull')(getfiles) |
|
87 | 83 | wireprotov1server.wireprotocommand( |
|
88 | 84 | 'getfile', 'file node', permission='pull')(getfile) |
|
89 | wireprotov1server.wireprotocommand( | |
|
90 | 'getpackv1', '*', permission='pull')(getpack) | |
|
91 | 85 | |
|
92 | 86 | class streamstate(object): |
|
93 | 87 | match = None |
@@ -421,134 +415,3 b' def gcserver(ui, repo):' | |||
|
421 | 415 | os.remove(filepath) |
|
422 | 416 | |
|
423 | 417 | ui.progress(_removing, None) |
|
424 | ||
|
425 | def getpack(repo, proto, args): | |
|
426 | """A server api for requesting a pack of file information. | |
|
427 | """ | |
|
428 | if shallowrepo.requirement in repo.requirements: | |
|
429 | raise error.Abort(_('cannot fetch remote files from shallow repo')) | |
|
430 | if not isinstance(proto, _sshv1server): | |
|
431 | raise error.Abort(_('cannot fetch remote files over non-ssh protocol')) | |
|
432 | ||
|
433 | def streamer(): | |
|
434 | """Request format: | |
|
435 | ||
|
436 | [<filerequest>,...]\0\0 | |
|
437 | filerequest = <filename len: 2 byte><filename><count: 4 byte> | |
|
438 | [<node: 20 byte>,...] | |
|
439 | ||
|
440 | Response format: | |
|
441 | [<fileresponse>,...]<10 null bytes> | |
|
442 | fileresponse = <filename len: 2 byte><filename><history><deltas> | |
|
443 | history = <count: 4 byte>[<history entry>,...] | |
|
444 | historyentry = <node: 20 byte><p1: 20 byte><p2: 20 byte> | |
|
445 | <linknode: 20 byte><copyfrom len: 2 byte><copyfrom> | |
|
446 | deltas = <count: 4 byte>[<delta entry>,...] | |
|
447 | deltaentry = <node: 20 byte><deltabase: 20 byte> | |
|
448 | <delta len: 8 byte><delta> | |
|
449 | """ | |
|
450 | fin = proto._fin | |
|
451 | files = _receivepackrequest(fin) | |
|
452 | ||
|
453 | # Sort the files by name, so we provide deterministic results | |
|
454 | for filename, nodes in sorted(files.iteritems()): | |
|
455 | fl = repo.file(filename) | |
|
456 | ||
|
457 | # Compute history | |
|
458 | history = [] | |
|
459 | for rev in ancestor.lazyancestors(fl.parentrevs, | |
|
460 | [fl.rev(n) for n in nodes], | |
|
461 | inclusive=True): | |
|
462 | linkrev = fl.linkrev(rev) | |
|
463 | node = fl.node(rev) | |
|
464 | p1node, p2node = fl.parents(node) | |
|
465 | copyfrom = '' | |
|
466 | linknode = repo.changelog.node(linkrev) | |
|
467 | if p1node == nullid: | |
|
468 | copydata = fl.renamed(node) | |
|
469 | if copydata: | |
|
470 | copyfrom, copynode = copydata | |
|
471 | p1node = copynode | |
|
472 | ||
|
473 | history.append((node, p1node, p2node, linknode, copyfrom)) | |
|
474 | ||
|
475 | # Scan and send deltas | |
|
476 | chain = _getdeltachain(fl, nodes, -1) | |
|
477 | ||
|
478 | for chunk in wirepack.sendpackpart(filename, history, chain): | |
|
479 | yield chunk | |
|
480 | ||
|
481 | yield wirepack.closepart() | |
|
482 | proto._fout.flush() | |
|
483 | ||
|
484 | return wireprototypes.streamres(streamer()) | |
|
485 | ||
|
486 | def _receivepackrequest(stream): | |
|
487 | files = {} | |
|
488 | while True: | |
|
489 | filenamelen = shallowutil.readunpack(stream, | |
|
490 | constants.FILENAMESTRUCT)[0] | |
|
491 | if filenamelen == 0: | |
|
492 | break | |
|
493 | ||
|
494 | filename = shallowutil.readexactly(stream, filenamelen) | |
|
495 | ||
|
496 | nodecount = shallowutil.readunpack(stream, | |
|
497 | constants.PACKREQUESTCOUNTSTRUCT)[0] | |
|
498 | ||
|
499 | # Read N nodes | |
|
500 | nodes = shallowutil.readexactly(stream, constants.NODESIZE * nodecount) | |
|
501 | nodes = set(nodes[i:i + constants.NODESIZE] for i in | |
|
502 | pycompat.xrange(0, len(nodes), constants.NODESIZE)) | |
|
503 | ||
|
504 | files[filename] = nodes | |
|
505 | ||
|
506 | return files | |
|
507 | ||
|
508 | def _getdeltachain(fl, nodes, stophint): | |
|
509 | """Produces a chain of deltas that includes each of the given nodes. | |
|
510 | ||
|
511 | `stophint` - The changeset rev number to stop at. If it's set to >= 0, we | |
|
512 | will return not only the deltas for the requested nodes, but also all | |
|
513 | necessary deltas in their delta chains, as long as the deltas have link revs | |
|
514 | >= the stophint. This allows us to return an approximately minimal delta | |
|
515 | chain when the user performs a pull. If `stophint` is set to -1, all nodes | |
|
516 | will return full texts. """ | |
|
517 | chain = [] | |
|
518 | ||
|
519 | seen = set() | |
|
520 | for node in nodes: | |
|
521 | startrev = fl.rev(node) | |
|
522 | cur = startrev | |
|
523 | while True: | |
|
524 | if cur in seen: | |
|
525 | break | |
|
526 | base = fl._revlog.deltaparent(cur) | |
|
527 | linkrev = fl.linkrev(cur) | |
|
528 | node = fl.node(cur) | |
|
529 | p1, p2 = fl.parentrevs(cur) | |
|
530 | if linkrev < stophint and cur != startrev: | |
|
531 | break | |
|
532 | ||
|
533 | # Return a full text if: | |
|
534 | # - the caller requested it (via stophint == -1) | |
|
535 | # - the revlog chain has ended (via base==null or base==node) | |
|
536 | # - p1 is null. In some situations this can mean it's a copy, so | |
|
537 | # we need to use fl.read() to remove the copymetadata. | |
|
538 | if (stophint == -1 or base == nullrev or base == cur | |
|
539 | or p1 == nullrev): | |
|
540 | delta = fl.read(cur) | |
|
541 | base = nullrev | |
|
542 | else: | |
|
543 | delta = fl._chunk(cur) | |
|
544 | ||
|
545 | basenode = fl.node(base) | |
|
546 | chain.append((node, basenode, delta)) | |
|
547 | seen.add(cur) | |
|
548 | ||
|
549 | if base == nullrev: | |
|
550 | break | |
|
551 | cur = base | |
|
552 | ||
|
553 | chain.reverse() | |
|
554 | return chain |
General Comments 0
You need to be logged in to leave comments.
Login now