mercurial/cmdutil.py
changeset 41605 7068c6b0114b
parent 41597 9e545c9a4dfe
child 41625 93620a4ba88d
equal deleted inserted replaced
41604:e944cf4ce1a8 41605:7068c6b0114b
  2780 
  2780 
  2781     # `names` is a mapping for all elements in working copy and target revision
  2781     # `names` is a mapping for all elements in working copy and target revision
  2782     # The mapping is in the form:
  2782     # The mapping is in the form:
  2783     #   <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
  2783     #   <abs path in repo> -> (<path from CWD>, <exactly specified by matcher?>)
  2784     names = {}
  2784     names = {}
       
  2785     uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
  2785 
  2786 
  2786     with repo.wlock():
  2787     with repo.wlock():
  2787         ## filling of the `names` mapping
  2788         ## filling of the `names` mapping
  2788         # walk dirstate to fill `names`
  2789         # walk dirstate to fill `names`
  2789 
  2790 
  2795         targetsubs = sorted(s for s in wctx.substate if m(s))
  2796         targetsubs = sorted(s for s in wctx.substate if m(s))
  2796 
  2797 
  2797         if not m.always():
  2798         if not m.always():
  2798             matcher = matchmod.badmatch(m, lambda x, y: False)
  2799             matcher = matchmod.badmatch(m, lambda x, y: False)
  2799             for abs in wctx.walk(matcher):
  2800             for abs in wctx.walk(matcher):
  2800                 names[abs] = m.rel(abs), m.exact(abs)
  2801                 names[abs] = m.exact(abs)
  2801 
  2802 
  2802             # walk target manifest to fill `names`
  2803             # walk target manifest to fill `names`
  2803 
  2804 
  2804             def badfn(path, msg):
  2805             def badfn(path, msg):
  2805                 if path in names:
  2806                 if path in names:
  2812                         return
  2813                         return
  2813                 ui.warn("%s: %s\n" % (m.rel(path), msg))
  2814                 ui.warn("%s: %s\n" % (m.rel(path), msg))
  2814 
  2815 
  2815             for abs in ctx.walk(matchmod.badmatch(m, badfn)):
  2816             for abs in ctx.walk(matchmod.badmatch(m, badfn)):
  2816                 if abs not in names:
  2817                 if abs not in names:
  2817                     names[abs] = m.rel(abs), m.exact(abs)
  2818                     names[abs] = m.exact(abs)
  2818 
  2819 
  2819             # Find status of all file in `names`.
  2820             # Find status of all file in `names`.
  2820             m = scmutil.matchfiles(repo, names)
  2821             m = scmutil.matchfiles(repo, names)
  2821 
  2822 
  2822             changes = repo.status(node1=node, match=m,
  2823             changes = repo.status(node1=node, match=m,
  2823                                   unknown=True, ignored=True, clean=True)
  2824                                   unknown=True, ignored=True, clean=True)
  2824         else:
  2825         else:
  2825             changes = repo.status(node1=node, match=m)
  2826             changes = repo.status(node1=node, match=m)
  2826             for kind in changes:
  2827             for kind in changes:
  2827                 for abs in kind:
  2828                 for abs in kind:
  2828                     names[abs] = m.rel(abs), m.exact(abs)
  2829                     names[abs] = m.exact(abs)
  2829 
  2830 
  2830             m = scmutil.matchfiles(repo, names)
  2831             m = scmutil.matchfiles(repo, names)
  2831 
  2832 
  2832         modified = set(changes.modified)
  2833         modified = set(changes.modified)
  2833         added    = set(changes.added)
  2834         added    = set(changes.added)
  2885                     mergeadd.remove(path)
  2886                     mergeadd.remove(path)
  2886             dsadded |= mergeadd
  2887             dsadded |= mergeadd
  2887             dsmodified -= mergeadd
  2888             dsmodified -= mergeadd
  2888 
  2889 
  2889         # if f is a rename, update `names` to also revert the source
  2890         # if f is a rename, update `names` to also revert the source
  2890         cwd = repo.getcwd()
       
  2891         for f in localchanges:
  2891         for f in localchanges:
  2892             src = repo.dirstate.copied(f)
  2892             src = repo.dirstate.copied(f)
  2893             # XXX should we check for rename down to target node?
  2893             # XXX should we check for rename down to target node?
  2894             if src and src not in names and repo.dirstate[src] == 'r':
  2894             if src and src not in names and repo.dirstate[src] == 'r':
  2895                 dsremoved.add(src)
  2895                 dsremoved.add(src)
  2896                 names[src] = (repo.pathto(src, cwd), True)
  2896                 names[src] = True
  2897 
  2897 
  2898         # determine the exact nature of the deleted changesets
  2898         # determine the exact nature of the deleted changesets
  2899         deladded = set(_deleted)
  2899         deladded = set(_deleted)
  2900         for path in _deleted:
  2900         for path in _deleted:
  2901             if path in mf:
  2901             if path in mf:
  2998             (clean,         actions['noop'],     discard),
  2998             (clean,         actions['noop'],     discard),
  2999             # Existing file, not tracked anywhere
  2999             # Existing file, not tracked anywhere
  3000             (unknown,       actions['unknown'],  discard),
  3000             (unknown,       actions['unknown'],  discard),
  3001             )
  3001             )
  3002 
  3002 
  3003         for abs, (rel, exact) in sorted(names.items()):
  3003         for abs, exact in sorted(names.items()):
  3004             # target file to be touch on disk (relative to cwd)
  3004             # target file to be touch on disk (relative to cwd)
  3005             target = repo.wjoin(abs)
  3005             target = repo.wjoin(abs)
  3006             # search the entry in the dispatch table.
  3006             # search the entry in the dispatch table.
  3007             # if the file is in any of these sets, it was touched in the working
  3007             # if the file is in any of these sets, it was touched in the working
  3008             # directory parent and we are sure it needs to be reverted.
  3008             # directory parent and we are sure it needs to be reverted.
  3015                         # If in interactive mode, don't automatically create
  3015                         # If in interactive mode, don't automatically create
  3016                         # .orig files (issue4793)
  3016                         # .orig files (issue4793)
  3017                         if dobackup == backupinteractive:
  3017                         if dobackup == backupinteractive:
  3018                             tobackup.add(abs)
  3018                             tobackup.add(abs)
  3019                         elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
  3019                         elif (backup <= dobackup or wctx[abs].cmp(ctx[abs])):
  3020                             bakname = scmutil.backuppath(ui, repo, abs)
  3020                             absbakname = scmutil.backuppath(ui, repo, abs)
  3021                             relbakname = os.path.relpath(bakname)
  3021                             bakname = os.path.relpath(absbakname,
       
  3022                                                       start=repo.root)
  3022                             ui.note(_('saving current version of %s as %s\n') %
  3023                             ui.note(_('saving current version of %s as %s\n') %
  3023                                     (rel, relbakname))
  3024                                     (uipathfn(abs), uipathfn(bakname)))
  3024                             if not opts.get('dry_run'):
  3025                             if not opts.get('dry_run'):
  3025                                 if interactive:
  3026                                 if interactive:
  3026                                     util.copyfile(target, bakname)
  3027                                     util.copyfile(target, absbakname)
  3027                                 else:
  3028                                 else:
  3028                                     util.rename(target, bakname)
  3029                                     util.rename(target, absbakname)
  3029                     if opts.get('dry_run'):
  3030                     if opts.get('dry_run'):
  3030                         if ui.verbose or not exact:
  3031                         if ui.verbose or not exact:
  3031                             ui.status(msg % rel)
  3032                             ui.status(msg % uipathfn(abs))
  3032                 elif exact:
  3033                 elif exact:
  3033                     ui.warn(msg % rel)
  3034                     ui.warn(msg % uipathfn(abs))
  3034                 break
  3035                 break
  3035 
  3036 
  3036         if not opts.get('dry_run'):
  3037         if not opts.get('dry_run'):
  3037             needdata = ('revert', 'add', 'undelete')
  3038             needdata = ('revert', 'add', 'undelete')
  3038             oplist = [actions[name][0] for name in needdata]
  3039             oplist = [actions[name][0] for name in needdata]
  3039             prefetch = scmutil.prefetchfiles
  3040             prefetch = scmutil.prefetchfiles
  3040             matchfiles = scmutil.matchfiles
  3041             matchfiles = scmutil.matchfiles
  3041             prefetch(repo, [ctx.rev()],
  3042             prefetch(repo, [ctx.rev()],
  3042                      matchfiles(repo,
  3043                      matchfiles(repo,
  3043                                 [f for sublist in oplist for f in sublist]))
  3044                                 [f for sublist in oplist for f in sublist]))
  3044             _performrevert(repo, parents, ctx, names, actions, interactive,
  3045             _performrevert(repo, parents, ctx, names, uipathfn, actions,
  3045                            tobackup)
  3046                            interactive, tobackup)
  3046 
  3047 
  3047         if targetsubs:
  3048         if targetsubs:
  3048             # Revert the subrepos on the revert list
  3049             # Revert the subrepos on the revert list
  3049             for sub in targetsubs:
  3050             for sub in targetsubs:
  3050                 try:
  3051                 try:
  3052                                          **pycompat.strkwargs(opts))
  3053                                          **pycompat.strkwargs(opts))
  3053                 except KeyError:
  3054                 except KeyError:
  3054                     raise error.Abort("subrepository '%s' does not exist in %s!"
  3055                     raise error.Abort("subrepository '%s' does not exist in %s!"
  3055                                       % (sub, short(ctx.node())))
  3056                                       % (sub, short(ctx.node())))
  3056 
  3057 
  3057 def _performrevert(repo, parents, ctx, names, actions, interactive=False,
  3058 def _performrevert(repo, parents, ctx, names, uipathfn, actions,
  3058                    tobackup=None):
  3059                    interactive=False, tobackup=None):
  3059     """function that actually perform all the actions computed for revert
  3060     """function that actually perform all the actions computed for revert
  3060 
  3061 
  3061     This is an independent function to let extension to plug in and react to
  3062     This is an independent function to let extension to plug in and react to
  3062     the imminent revert.
  3063     the imminent revert.
  3063 
  3064 
  3078         except OSError:
  3079         except OSError:
  3079             pass
  3080             pass
  3080         repo.dirstate.remove(f)
  3081         repo.dirstate.remove(f)
  3081 
  3082 
  3082     def prntstatusmsg(action, f):
  3083     def prntstatusmsg(action, f):
  3083         rel, exact = names[f]
  3084         exact = names[f]
  3084         if repo.ui.verbose or not exact:
  3085         if repo.ui.verbose or not exact:
  3085             repo.ui.status(actions[action][1] % rel)
  3086             repo.ui.status(actions[action][1] % uipathfn(f))
  3086 
  3087 
  3087     audit_path = pathutil.pathauditor(repo.root, cached=True)
  3088     audit_path = pathutil.pathauditor(repo.root, cached=True)
  3088     for f in actions['forget'][0]:
  3089     for f in actions['forget'][0]:
  3089         if interactive:
  3090         if interactive:
  3090             choice = repo.ui.promptchoice(
  3091             choice = repo.ui.promptchoice(
  3091                 _("forget added file %s (Yn)?$$ &Yes $$ &No") % f)
  3092                 _("forget added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f))
  3092             if choice == 0:
  3093             if choice == 0:
  3093                 prntstatusmsg('forget', f)
  3094                 prntstatusmsg('forget', f)
  3094                 repo.dirstate.drop(f)
  3095                 repo.dirstate.drop(f)
  3095             else:
  3096             else:
  3096                 excluded_files.append(f)
  3097                 excluded_files.append(f)
  3099             repo.dirstate.drop(f)
  3100             repo.dirstate.drop(f)
  3100     for f in actions['remove'][0]:
  3101     for f in actions['remove'][0]:
  3101         audit_path(f)
  3102         audit_path(f)
  3102         if interactive:
  3103         if interactive:
  3103             choice = repo.ui.promptchoice(
  3104             choice = repo.ui.promptchoice(
  3104                 _("remove added file %s (Yn)?$$ &Yes $$ &No") % f)
  3105                 _("remove added file %s (Yn)?$$ &Yes $$ &No") % uipathfn(f))
  3105             if choice == 0:
  3106             if choice == 0:
  3106                 prntstatusmsg('remove', f)
  3107                 prntstatusmsg('remove', f)
  3107                 doremove(f)
  3108                 doremove(f)
  3108             else:
  3109             else:
  3109                 excluded_files.append(f)
  3110                 excluded_files.append(f)