mercurial/cmdutil.py
changeset 2958 ff3ea21a981a
parent 2957 6e062d9b188f
child 3072 bc3fe3b5b785
equal deleted inserted replaced
2957:6e062d9b188f 2958:ff3ea21a981a
     6 # of the GNU General Public License, incorporated herein by reference.
     6 # of the GNU General Public License, incorporated herein by reference.
     7 
     7 
     8 from demandload import demandload
     8 from demandload import demandload
     9 from node import *
     9 from node import *
    10 from i18n import gettext as _
    10 from i18n import gettext as _
    11 demandload(globals(), 'util')
    11 demandload(globals(), 'mdiff util')
    12 demandload(globals(), 'os sys')
    12 demandload(globals(), 'os sys')
    13 
    13 
    14 def make_filename(repo, pat, node,
    14 def make_filename(repo, pat, node,
    15                   total=None, seqno=None, revwidth=None, pathname=None):
    15                   total=None, seqno=None, revwidth=None, pathname=None):
    16     node_expander = {
    16     node_expander = {
    91 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
    91 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
    92     files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
    92     files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
    93     for r in results:
    93     for r in results:
    94         yield r
    94         yield r
    95 
    95 
    96 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None):
    96 def findrenames(repo, added=None, removed=None, threshold=0.5):
       
    97     if added is None or removed is None:
       
    98         added, removed = repo.status()[1:3]
       
    99     changes = repo.changelog.read(repo.dirstate.parents()[0])
       
   100     mf = repo.manifest.read(changes[0])
       
   101     for a in added:
       
   102         aa = repo.wread(a)
       
   103         bestscore, bestname = None, None
       
   104         for r in removed:
       
   105             rr = repo.file(r).read(mf[r])
       
   106             delta = mdiff.textdiff(aa, rr)
       
   107             if len(delta) < len(aa):
       
   108                 myscore = 1.0 - (float(len(delta)) / len(aa))
       
   109                 if bestscore is None or myscore > bestscore:
       
   110                     bestscore, bestname = myscore, r
       
   111         if bestname and bestscore >= threshold:
       
   112             yield bestname, a, bestscore
       
   113 
       
   114 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
       
   115               similarity=None):
    97     if dry_run is None:
   116     if dry_run is None:
    98         dry_run = opts.get('dry_run')
   117         dry_run = opts.get('dry_run')
       
   118     if similarity is None:
       
   119         similarity = float(opts.get('similarity') or 0)
    99     add, remove = [], []
   120     add, remove = [], []
       
   121     mapping = {}
   100     for src, abs, rel, exact in walk(repo, pats, opts):
   122     for src, abs, rel, exact in walk(repo, pats, opts):
   101         if src == 'f' and repo.dirstate.state(abs) == '?':
   123         if src == 'f' and repo.dirstate.state(abs) == '?':
   102             add.append(abs)
   124             add.append(abs)
       
   125             mapping[abs] = rel, exact
   103             if repo.ui.verbose or not exact:
   126             if repo.ui.verbose or not exact:
   104                 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
   127                 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
   105         if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
   128         if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
   106             remove.append(abs)
   129             remove.append(abs)
       
   130             mapping[abs] = rel, exact
   107             if repo.ui.verbose or not exact:
   131             if repo.ui.verbose or not exact:
   108                 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
   132                 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
   109     if not dry_run:
   133     if not dry_run:
   110         repo.add(add, wlock=wlock)
   134         repo.add(add, wlock=wlock)
   111         repo.remove(remove, wlock=wlock)
   135         repo.remove(remove, wlock=wlock)
       
   136     if similarity > 0:
       
   137         for old, new, score in findrenames(repo, add, remove, similarity):
       
   138             oldrel, oldexact = mapping[old]
       
   139             newrel, newexact = mapping[new]
       
   140             if repo.ui.verbose or not oldexact or not newexact:
       
   141                 repo.ui.status(_('recording removal of %s as rename to %s '
       
   142                                  '(%d%% similar)\n') %
       
   143                                (oldrel, newrel, score * 100))
       
   144             if not dry_run:
       
   145                 repo.copy(old, new, wlock=wlock)