comparison mercurial/cmdutil.py @ 2958:ff3ea21a981a

addremove: add -s/--similarity option progress on issue 295.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Fri, 18 Aug 2006 22:13:58 -0700
parents 6e062d9b188f
children bc3fe3b5b785
comparison
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)