Mercurial > public > mercurial-scm > hg
comparison mercurial/sparse.py @ 33555:6755b719048c
sparse: consolidate common code for writing sparse config
In 3 functions we were writing the sparse config and updating the
working directory. In two of them we had a transaction-like process
for restoring the sparse config in case of wdir update fail.
Because the pattern is common, we've already made mistakes, and the
complexity will increase in the near future, let's consolidate the
code into a reusable function.
As part of this refactor, we end up reading the "sparse" file twice
when updating it. This is a bit sub-optimal. But I don't think it
is worth the code complexity to pass around the variables to avoid
the redundancy.
Differential Revision: https://phab.mercurial-scm.org/D109
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 17 Jul 2017 11:21:23 -0700 |
parents | 1d1779734c99 |
children | 22371eabb3b1 |
comparison
equal
deleted
inserted
replaced
33554:2943141f5e07 | 33555:6755b719048c |
---|---|
519 origsparsematch = matcher(repo) | 519 origsparsematch = matcher(repo) |
520 refreshwdir(repo, origstatus, origsparsematch, force=True) | 520 refreshwdir(repo, origstatus, origsparsematch, force=True) |
521 | 521 |
522 prunetemporaryincludes(repo) | 522 prunetemporaryincludes(repo) |
523 | 523 |
524 def _updateconfigandrefreshwdir(repo, includes, excludes, profiles, | |
525 force=False): | |
526 """Update the sparse config and working directory state.""" | |
527 raw = repo.vfs.tryread('sparse') | |
528 oldincludes, oldexcludes, oldprofiles = parseconfig(repo.ui, raw) | |
529 | |
530 oldstatus = repo.status() | |
531 oldmatch = matcher(repo) | |
532 | |
533 # TODO remove this try..except once the matcher integrates better | |
534 # with dirstate. We currently have to write the updated config | |
535 # because that will invalidate the matcher cache and force a | |
536 # re-read. We ideally want to update the cached matcher on the | |
537 # repo instance then flush the new config to disk once wdir is | |
538 # updated. But this requires massive rework to matcher() and its | |
539 # consumers. | |
540 | |
541 writeconfig(repo, includes, excludes, profiles) | |
542 | |
543 try: | |
544 return refreshwdir(repo, oldstatus, oldmatch, force=force) | |
545 except Exception: | |
546 writeconfig(repo, oldincludes, oldexcludes, oldprofiles) | |
547 raise | |
548 | |
524 def clearrules(repo, force=False): | 549 def clearrules(repo, force=False): |
525 """Clears include/exclude rules from the sparse config. | 550 """Clears include/exclude rules from the sparse config. |
526 | 551 |
527 The remaining sparse config only has profiles, if defined. The working | 552 The remaining sparse config only has profiles, if defined. The working |
528 directory is refreshed, as needed. | 553 directory is refreshed, as needed. |
532 includes, excludes, profiles = parseconfig(repo.ui, raw) | 557 includes, excludes, profiles = parseconfig(repo.ui, raw) |
533 | 558 |
534 if not includes and not excludes: | 559 if not includes and not excludes: |
535 return | 560 return |
536 | 561 |
537 oldstatus = repo.status() | 562 _updateconfigandrefreshwdir(repo, set(), set(), profiles, force=force) |
538 oldmatch = matcher(repo) | |
539 writeconfig(repo, set(), set(), profiles) | |
540 refreshwdir(repo, oldstatus, oldmatch, force=force) | |
541 | 563 |
542 def importfromfiles(repo, opts, paths, force=False): | 564 def importfromfiles(repo, opts, paths, force=False): |
543 """Import sparse config rules from files. | 565 """Import sparse config rules from files. |
544 | 566 |
545 The updated sparse config is written out and the working directory | 567 The updated sparse config is written out and the working directory |
546 is refreshed, as needed. | 568 is refreshed, as needed. |
547 """ | 569 """ |
548 with repo.wlock(): | 570 with repo.wlock(): |
549 # read current configuration | 571 # read current configuration |
550 raw = repo.vfs.tryread('sparse') | 572 raw = repo.vfs.tryread('sparse') |
551 oincludes, oexcludes, oprofiles = parseconfig(repo.ui, raw) | 573 includes, excludes, profiles = parseconfig(repo.ui, raw) |
552 includes, excludes, profiles = map( | |
553 set, (oincludes, oexcludes, oprofiles)) | |
554 | |
555 aincludes, aexcludes, aprofiles = activeconfig(repo) | 574 aincludes, aexcludes, aprofiles = activeconfig(repo) |
556 | 575 |
557 # Import rules on top; only take in rules that are not yet | 576 # Import rules on top; only take in rules that are not yet |
558 # part of the active rules. | 577 # part of the active rules. |
559 changed = False | 578 changed = False |
575 if changed: | 594 if changed: |
576 profilecount = len(profiles - aprofiles) | 595 profilecount = len(profiles - aprofiles) |
577 includecount = len(includes - aincludes) | 596 includecount = len(includes - aincludes) |
578 excludecount = len(excludes - aexcludes) | 597 excludecount = len(excludes - aexcludes) |
579 | 598 |
580 oldstatus = repo.status() | 599 fcounts = map(len, _updateconfigandrefreshwdir( |
581 oldsparsematch = matcher(repo) | 600 repo, includes, excludes, profiles, force=force)) |
582 | |
583 # TODO remove this try..except once the matcher integrates better | |
584 # with dirstate. We currently have to write the updated config | |
585 # because that will invalidate the matcher cache and force a | |
586 # re-read. We ideally want to update the cached matcher on the | |
587 # repo instance then flush the new config to disk once wdir is | |
588 # updated. But this requires massive rework to matcher() and its | |
589 # consumers. | |
590 writeconfig(repo, includes, excludes, profiles) | |
591 | |
592 try: | |
593 fcounts = map( | |
594 len, | |
595 refreshwdir(repo, oldstatus, oldsparsematch, force=force)) | |
596 except Exception: | |
597 writeconfig(repo, oincludes, oexcludes, oprofiles) | |
598 raise | |
599 | 601 |
600 printchanges(repo.ui, opts, profilecount, includecount, excludecount, | 602 printchanges(repo.ui, opts, profilecount, includecount, excludecount, |
601 *fcounts) | 603 *fcounts) |
602 | 604 |
603 def updateconfig(repo, pats, opts, include=False, exclude=False, reset=False, | 605 def updateconfig(repo, pats, opts, include=False, exclude=False, reset=False, |
608 Only one of the actions may be performed. | 610 Only one of the actions may be performed. |
609 | 611 |
610 The new config is written out and a working directory refresh is performed. | 612 The new config is written out and a working directory refresh is performed. |
611 """ | 613 """ |
612 with repo.wlock(): | 614 with repo.wlock(): |
613 oldmatcher = matcher(repo) | |
614 | |
615 raw = repo.vfs.tryread('sparse') | 615 raw = repo.vfs.tryread('sparse') |
616 oldinclude, oldexclude, oldprofiles = parseconfig(repo.ui, raw) | 616 oldinclude, oldexclude, oldprofiles = parseconfig(repo.ui, raw) |
617 | 617 |
618 if reset: | 618 if reset: |
619 newinclude = set() | 619 newinclude = set() |
621 newprofiles = set() | 621 newprofiles = set() |
622 else: | 622 else: |
623 newinclude = set(oldinclude) | 623 newinclude = set(oldinclude) |
624 newexclude = set(oldexclude) | 624 newexclude = set(oldexclude) |
625 newprofiles = set(oldprofiles) | 625 newprofiles = set(oldprofiles) |
626 | |
627 oldstatus = repo.status() | |
628 | 626 |
629 if any(pat.startswith('/') for pat in pats): | 627 if any(pat.startswith('/') for pat in pats): |
630 repo.ui.warn(_('warning: paths cannot start with /, ignoring: %s\n') | 628 repo.ui.warn(_('warning: paths cannot start with /, ignoring: %s\n') |
631 % ([pat for pat in pats if pat.startswith('/')])) | 629 % ([pat for pat in pats if pat.startswith('/')])) |
632 elif include: | 630 elif include: |
646 includecount = (len(newinclude - oldinclude) - | 644 includecount = (len(newinclude - oldinclude) - |
647 len(oldinclude - newinclude)) | 645 len(oldinclude - newinclude)) |
648 excludecount = (len(newexclude - oldexclude) - | 646 excludecount = (len(newexclude - oldexclude) - |
649 len(oldexclude - newexclude)) | 647 len(oldexclude - newexclude)) |
650 | 648 |
651 # TODO clean up this writeconfig() + try..except pattern once we can. | 649 fcounts = map(len, _updateconfigandrefreshwdir( |
652 # See comment in importfromfiles() explaining it. | 650 repo, newinclude, newexclude, newprofiles, force=force)) |
653 writeconfig(repo, newinclude, newexclude, newprofiles) | 651 |
654 | 652 printchanges(repo.ui, opts, profilecount, includecount, |
655 try: | 653 excludecount, *fcounts) |
656 fcounts = map( | |
657 len, | |
658 refreshwdir(repo, oldstatus, oldmatcher, force=force)) | |
659 | |
660 printchanges(repo.ui, opts, profilecount, includecount, | |
661 excludecount, *fcounts) | |
662 except Exception: | |
663 writeconfig(repo, oldinclude, oldexclude, oldprofiles) | |
664 raise | |
665 | 654 |
666 def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0, | 655 def printchanges(ui, opts, profilecount=0, includecount=0, excludecount=0, |
667 added=0, dropped=0, conflicting=0): | 656 added=0, dropped=0, conflicting=0): |
668 """Print output summarizing sparse config changes.""" | 657 """Print output summarizing sparse config changes.""" |
669 with ui.formatter('sparse', opts) as fm: | 658 with ui.formatter('sparse', opts) as fm: |