Mercurial > hg > mercurial-crew-with-dirclash
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) |