Mercurial > public > mercurial-scm > hg
comparison mercurial/debugcommands.py @ 44433:f82d2d4e71db
debugbackupbundle: introduce command to interact with strip backups
This vendors backups extension from hg-experimental.
Listing backups and having some utility to apply them is nice. I know we have
obsmarkers now, but this will help a lot of end users who still uses strip until
we get evolve out of experimental.
Differential Revision: https://phab.mercurial-scm.org/D7932
author | Pulkit Goyal <7895pulkit@gmail.com> |
---|---|
date | Fri, 17 Jan 2020 21:22:23 +0300 |
parents | acbfa31cfaf2 |
children | 9d2b2df2c2ba |
comparison
equal
deleted
inserted
replaced
44427:4ce2330f2d0b | 44433:f82d2d4e71db |
---|---|
9 | 9 |
10 import codecs | 10 import codecs |
11 import collections | 11 import collections |
12 import difflib | 12 import difflib |
13 import errno | 13 import errno |
14 import glob | |
14 import operator | 15 import operator |
15 import os | 16 import os |
16 import platform | 17 import platform |
17 import random | 18 import random |
18 import re | 19 import re |
36 getattr, | 37 getattr, |
37 open, | 38 open, |
38 ) | 39 ) |
39 from . import ( | 40 from . import ( |
40 bundle2, | 41 bundle2, |
42 bundlerepo, | |
41 changegroup, | 43 changegroup, |
42 cmdutil, | 44 cmdutil, |
43 color, | 45 color, |
44 context, | 46 context, |
45 copies, | 47 copies, |
3400 finally: | 3402 finally: |
3401 s.close() | 3403 s.close() |
3402 | 3404 |
3403 | 3405 |
3404 @command( | 3406 @command( |
3407 b"debugbackupbundle", | |
3408 [ | |
3409 ( | |
3410 b"", | |
3411 b"recover", | |
3412 b"", | |
3413 b"brings the specified changeset back into the repository", | |
3414 ) | |
3415 ] | |
3416 + cmdutil.logopts, | |
3417 _(b"hg debugbackupbundle [--recover HASH]"), | |
3418 ) | |
3419 def debugbackupbundle(ui, repo, *pats, **opts): | |
3420 """lists the changesets available in backup bundles | |
3421 | |
3422 Without any arguments, this command prints a list of the changesets in each | |
3423 backup bundle. | |
3424 | |
3425 --recover takes a changeset hash and unbundles the first bundle that | |
3426 contains that hash, which puts that changeset back in your repository. | |
3427 | |
3428 --verbose will print the entire commit message and the bundle path for that | |
3429 backup. | |
3430 """ | |
3431 backups = list( | |
3432 filter( | |
3433 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg") | |
3434 ) | |
3435 ) | |
3436 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True) | |
3437 | |
3438 opts = pycompat.byteskwargs(opts) | |
3439 opts[b"bundle"] = b"" | |
3440 opts[b"force"] = None | |
3441 limit = logcmdutil.getlimit(opts) | |
3442 | |
3443 def display(other, chlist, displayer): | |
3444 if opts.get(b"newest_first"): | |
3445 chlist.reverse() | |
3446 count = 0 | |
3447 for n in chlist: | |
3448 if limit is not None and count >= limit: | |
3449 break | |
3450 parents = [True for p in other.changelog.parents(n) if p != nullid] | |
3451 if opts.get(b"no_merges") and len(parents) == 2: | |
3452 continue | |
3453 count += 1 | |
3454 displayer.show(other[n]) | |
3455 | |
3456 recovernode = opts.get(b"recover") | |
3457 if recovernode: | |
3458 if scmutil.isrevsymbol(repo, recovernode): | |
3459 ui.warn(_(b"%s already exists in the repo\n") % recovernode) | |
3460 return | |
3461 elif backups: | |
3462 msg = _( | |
3463 b"Recover changesets using: hg debugbackupbundle --recover " | |
3464 b"<changeset hash>\n\nAvailable backup changesets:" | |
3465 ) | |
3466 ui.status(msg, label=b"status.removed") | |
3467 else: | |
3468 ui.status(_(b"no backup changesets found\n")) | |
3469 return | |
3470 | |
3471 for backup in backups: | |
3472 # Much of this is copied from the hg incoming logic | |
3473 source = ui.expandpath(os.path.relpath(backup, encoding.getcwd())) | |
3474 source, branches = hg.parseurl(source, opts.get(b"branch")) | |
3475 try: | |
3476 other = hg.peer(repo, opts, source) | |
3477 except error.LookupError as ex: | |
3478 msg = _(b"\nwarning: unable to open bundle %s") % source | |
3479 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name) | |
3480 ui.warn(msg, hint=hint) | |
3481 continue | |
3482 revs, checkout = hg.addbranchrevs( | |
3483 repo, other, branches, opts.get(b"rev") | |
3484 ) | |
3485 | |
3486 if revs: | |
3487 revs = [other.lookup(rev) for rev in revs] | |
3488 | |
3489 quiet = ui.quiet | |
3490 try: | |
3491 ui.quiet = True | |
3492 other, chlist, cleanupfn = bundlerepo.getremotechanges( | |
3493 ui, repo, other, revs, opts[b"bundle"], opts[b"force"] | |
3494 ) | |
3495 except error.LookupError: | |
3496 continue | |
3497 finally: | |
3498 ui.quiet = quiet | |
3499 | |
3500 try: | |
3501 if not chlist: | |
3502 continue | |
3503 if recovernode: | |
3504 with repo.lock(), repo.transaction(b"unbundle") as tr: | |
3505 if scmutil.isrevsymbol(other, recovernode): | |
3506 ui.status(_(b"Unbundling %s\n") % (recovernode)) | |
3507 f = hg.openpath(ui, source) | |
3508 gen = exchange.readbundle(ui, f, source) | |
3509 if isinstance(gen, bundle2.unbundle20): | |
3510 bundle2.applybundle( | |
3511 repo, | |
3512 gen, | |
3513 tr, | |
3514 source=b"unbundle", | |
3515 url=b"bundle:" + source, | |
3516 ) | |
3517 else: | |
3518 gen.apply(repo, b"unbundle", b"bundle:" + source) | |
3519 break | |
3520 else: | |
3521 backupdate = encoding.strtolocal( | |
3522 time.strftime( | |
3523 "%a %H:%M, %Y-%m-%d", | |
3524 time.localtime(os.path.getmtime(source)), | |
3525 ) | |
3526 ) | |
3527 ui.status(b"\n%s\n" % (backupdate.ljust(50))) | |
3528 if ui.verbose: | |
3529 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source)) | |
3530 else: | |
3531 opts[ | |
3532 b"template" | |
3533 ] = b"{label('status.modified', node|short)} {desc|firstline}\n" | |
3534 displayer = logcmdutil.changesetdisplayer( | |
3535 ui, other, opts, False | |
3536 ) | |
3537 display(other, chlist, displayer) | |
3538 displayer.close() | |
3539 finally: | |
3540 cleanupfn() | |
3541 | |
3542 | |
3543 @command( | |
3405 b'debugsub', | 3544 b'debugsub', |
3406 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))], | 3545 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))], |
3407 _(b'[-r REV] [REV]'), | 3546 _(b'[-r REV] [REV]'), |
3408 ) | 3547 ) |
3409 def debugsub(ui, repo, rev=None): | 3548 def debugsub(ui, repo, rev=None): |