Show More
@@ -12,16 +12,14 b' import stat' | |||||
12 | import time |
|
12 | import time | |
13 |
|
13 | |||
14 | from mercurial.i18n import _ |
|
14 | from mercurial.i18n import _ | |
15 |
from mercurial.node import bin, hex, nullid |
|
15 | from mercurial.node import bin, hex, nullid | |
16 | from mercurial import ( |
|
16 | from mercurial import ( | |
17 | ancestor, |
|
|||
18 | changegroup, |
|
17 | changegroup, | |
19 | changelog, |
|
18 | changelog, | |
20 | context, |
|
19 | context, | |
21 | error, |
|
20 | error, | |
22 | extensions, |
|
21 | extensions, | |
23 | match, |
|
22 | match, | |
24 | pycompat, |
|
|||
25 | store, |
|
23 | store, | |
26 | streamclone, |
|
24 | streamclone, | |
27 | util, |
|
25 | util, | |
@@ -30,11 +28,9 b' from mercurial import (' | |||||
30 | wireprotov1server, |
|
28 | wireprotov1server, | |
31 | ) |
|
29 | ) | |
32 | from . import ( |
|
30 | from . import ( | |
33 | constants, |
|
|||
34 | lz4wrapper, |
|
31 | lz4wrapper, | |
35 | shallowrepo, |
|
32 | shallowrepo, | |
36 | shallowutil, |
|
33 | shallowutil, | |
37 | wirepack, |
|
|||
38 | ) |
|
34 | ) | |
39 |
|
35 | |||
40 | _sshv1server = wireprotoserver.sshv1protocolhandler |
|
36 | _sshv1server = wireprotoserver.sshv1protocolhandler | |
@@ -86,8 +82,6 b' def onetimesetup(ui):' | |||||
86 | 'getfiles', '', permission='pull')(getfiles) |
|
82 | 'getfiles', '', permission='pull')(getfiles) | |
87 | wireprotov1server.wireprotocommand( |
|
83 | wireprotov1server.wireprotocommand( | |
88 | 'getfile', 'file node', permission='pull')(getfile) |
|
84 | 'getfile', 'file node', permission='pull')(getfile) | |
89 | wireprotov1server.wireprotocommand( |
|
|||
90 | 'getpackv1', '*', permission='pull')(getpack) |
|
|||
91 |
|
85 | |||
92 | class streamstate(object): |
|
86 | class streamstate(object): | |
93 | match = None |
|
87 | match = None | |
@@ -421,134 +415,3 b' def gcserver(ui, repo):' | |||||
421 | os.remove(filepath) |
|
415 | os.remove(filepath) | |
422 |
|
416 | |||
423 | ui.progress(_removing, None) |
|
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