Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/logcmdutil.py @ 45569:24df19a9ab87
log: pass around --follow/--follow-first options by walkopts
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sat, 12 Sep 2020 21:35:26 +0900 |
parents | c1d0f83d62c4 |
children | bddf70c93614 |
comparison
equal
deleted
inserted
replaced
45568:c1d0f83d62c4 | 45569:24df19a9ab87 |
---|---|
684 | 684 |
685 # raw command-line parameters, which a matcher will be built from | 685 # raw command-line parameters, which a matcher will be built from |
686 pats = attr.ib() # type: List[bytes] | 686 pats = attr.ib() # type: List[bytes] |
687 opts = attr.ib() # type: Dict[bytes, Any] | 687 opts = attr.ib() # type: Dict[bytes, Any] |
688 | 688 |
689 # 0: no follow, 1: follow first, 2: follow both parents | |
690 follow = attr.ib(default=0) # type: int | |
691 | |
689 | 692 |
690 def parseopts(ui, pats, opts): | 693 def parseopts(ui, pats, opts): |
691 # type: (Any, List[bytes], Dict[bytes, Any]) -> walkopts | 694 # type: (Any, List[bytes], Dict[bytes, Any]) -> walkopts |
692 """Parse log command options into walkopts | 695 """Parse log command options into walkopts |
693 | 696 |
694 The returned walkopts will be passed in to getrevs(). | 697 The returned walkopts will be passed in to getrevs(). |
695 """ | 698 """ |
696 return walkopts(pats=pats, opts=opts) | 699 if opts.get(b'follow_first'): |
700 follow = 1 | |
701 elif opts.get(b'follow'): | |
702 follow = 2 | |
703 else: | |
704 follow = 0 | |
705 | |
706 return walkopts(pats=pats, opts=opts, follow=follow) | |
697 | 707 |
698 | 708 |
699 def _makematcher(repo, revs, wopts): | 709 def _makematcher(repo, revs, wopts): |
700 """Build matcher and expanded patterns from log options | 710 """Build matcher and expanded patterns from log options |
701 | 711 |
714 match, pats = scmutil.matchandpats(wctx, wopts.pats, wopts.opts) | 724 match, pats = scmutil.matchandpats(wctx, wopts.pats, wopts.opts) |
715 slowpath = match.anypats() or ( | 725 slowpath = match.anypats() or ( |
716 not match.always() and wopts.opts.get(b'removed') | 726 not match.always() and wopts.opts.get(b'removed') |
717 ) | 727 ) |
718 if not slowpath: | 728 if not slowpath: |
719 follow = wopts.opts.get(b'follow') or wopts.opts.get(b'follow_first') | 729 if wopts.follow and wopts.opts.get(b'rev'): |
720 if follow and wopts.opts.get(b'rev'): | |
721 # There may be the case that a path doesn't exist in some (but | 730 # There may be the case that a path doesn't exist in some (but |
722 # not all) of the specified start revisions, but let's consider | 731 # not all) of the specified start revisions, but let's consider |
723 # the path is valid. Missing files will be warned by the matcher. | 732 # the path is valid. Missing files will be warned by the matcher. |
724 startctxs = [repo[r] for r in revs] | 733 startctxs = [repo[r] for r in revs] |
725 for f in match.files(): | 734 for f in match.files(): |
737 b'cannot follow file not in any of the specified ' | 746 b'cannot follow file not in any of the specified ' |
738 b'revisions: "%s"' | 747 b'revisions: "%s"' |
739 ) | 748 ) |
740 % f | 749 % f |
741 ) | 750 ) |
742 elif follow: | 751 elif wopts.follow: |
743 for f in match.files(): | 752 for f in match.files(): |
744 if f not in wctx: | 753 if f not in wctx: |
745 # If the file exists, it may be a directory, so let it | 754 # If the file exists, it may be a directory, so let it |
746 # take the slow path. | 755 # take the slow path. |
747 if os.path.exists(repo.wjoin(f)): | 756 if os.path.exists(repo.wjoin(f)): |
827 | 836 |
828 | 837 |
829 def _makerevset(repo, wopts, slowpath): | 838 def _makerevset(repo, wopts, slowpath): |
830 """Return a revset string built from log options and file patterns""" | 839 """Return a revset string built from log options and file patterns""" |
831 opts = dict(wopts.opts) | 840 opts = dict(wopts.opts) |
832 # follow or not follow? | |
833 follow = opts.get(b'follow') or opts.get(b'follow_first') | |
834 | 841 |
835 # branch and only_branch are really aliases and must be handled at | 842 # branch and only_branch are really aliases and must be handled at |
836 # the same time | 843 # the same time |
837 opts[b'branch'] = opts.get(b'branch', []) + opts.get(b'only_branch', []) | 844 opts[b'branch'] = opts.get(b'branch', []) + opts.get(b'only_branch', []) |
838 opts[b'branch'] = [repo.lookupbranch(b) for b in opts[b'branch']] | 845 opts[b'branch'] = [repo.lookupbranch(b) for b in opts[b'branch']] |
852 for p in opts.get(b'include', []): | 859 for p in opts.get(b'include', []): |
853 matchargs.append(b'i:' + p) | 860 matchargs.append(b'i:' + p) |
854 for p in opts.get(b'exclude', []): | 861 for p in opts.get(b'exclude', []): |
855 matchargs.append(b'x:' + p) | 862 matchargs.append(b'x:' + p) |
856 opts[b'_matchfiles'] = matchargs | 863 opts[b'_matchfiles'] = matchargs |
857 elif not follow: | 864 elif not wopts.follow: |
858 opts[b'_patslog'] = list(wopts.pats) | 865 opts[b'_patslog'] = list(wopts.pats) |
859 | 866 |
860 expr = [] | 867 expr = [] |
861 for op, val in sorted(pycompat.iteritems(opts)): | 868 for op, val in sorted(pycompat.iteritems(opts)): |
862 if not val: | 869 if not val: |
880 return expr | 887 return expr |
881 | 888 |
882 | 889 |
883 def _initialrevs(repo, wopts): | 890 def _initialrevs(repo, wopts): |
884 """Return the initial set of revisions to be filtered or followed""" | 891 """Return the initial set of revisions to be filtered or followed""" |
885 follow = wopts.opts.get(b'follow') or wopts.opts.get(b'follow_first') | |
886 if wopts.opts.get(b'rev'): | 892 if wopts.opts.get(b'rev'): |
887 revs = scmutil.revrange(repo, wopts.opts[b'rev']) | 893 revs = scmutil.revrange(repo, wopts.opts[b'rev']) |
888 elif follow and repo.dirstate.p1() == nullid: | 894 elif wopts.follow and repo.dirstate.p1() == nullid: |
889 revs = smartset.baseset() | 895 revs = smartset.baseset() |
890 elif follow: | 896 elif wopts.follow: |
891 revs = repo.revs(b'.') | 897 revs = repo.revs(b'.') |
892 else: | 898 else: |
893 revs = smartset.spanset(repo) | 899 revs = smartset.spanset(repo) |
894 revs.reverse() | 900 revs.reverse() |
895 return revs | 901 return revs |
899 # type: (Any, walkopts) -> Tuple[smartset.abstractsmartset, Optional[changesetdiffer]] | 905 # type: (Any, walkopts) -> Tuple[smartset.abstractsmartset, Optional[changesetdiffer]] |
900 """Return (revs, differ) where revs is a smartset | 906 """Return (revs, differ) where revs is a smartset |
901 | 907 |
902 differ is a changesetdiffer with pre-configured file matcher. | 908 differ is a changesetdiffer with pre-configured file matcher. |
903 """ | 909 """ |
904 follow = wopts.opts.get(b'follow') or wopts.opts.get(b'follow_first') | |
905 followfirst = wopts.opts.get(b'follow_first') | |
906 limit = getlimit(wopts.opts) | 910 limit = getlimit(wopts.opts) |
907 revs = _initialrevs(repo, wopts) | 911 revs = _initialrevs(repo, wopts) |
908 if not revs: | 912 if not revs: |
909 return smartset.baseset(), None | 913 return smartset.baseset(), None |
910 match, pats, slowpath = _makematcher(repo, revs, wopts) | 914 match, pats, slowpath = _makematcher(repo, revs, wopts) |
911 wopts = attr.evolve(wopts, pats=pats) | 915 wopts = attr.evolve(wopts, pats=pats) |
912 | 916 |
913 filematcher = None | 917 filematcher = None |
914 if follow: | 918 if wopts.follow: |
915 if slowpath or match.always(): | 919 if slowpath or match.always(): |
916 revs = dagop.revancestors(repo, revs, followfirst=followfirst) | 920 revs = dagop.revancestors(repo, revs, followfirst=wopts.follow == 1) |
917 else: | 921 else: |
918 revs, filematcher = _fileancestors(repo, revs, match, followfirst) | 922 revs, filematcher = _fileancestors( |
923 repo, revs, match, followfirst=wopts.follow == 1 | |
924 ) | |
919 revs.reverse() | 925 revs.reverse() |
920 if filematcher is None: | 926 if filematcher is None: |
921 filematcher = _makenofollowfilematcher(repo, wopts.pats, wopts.opts) | 927 filematcher = _makenofollowfilematcher(repo, wopts.pats, wopts.opts) |
922 if filematcher is None: | 928 if filematcher is None: |
923 | 929 |