##// END OF EJS Templates
kill makewalk function
Matt Mackall -
r3528:39011927 default
parent child Browse files
Show More
@@ -1,204 +1,197 b''
1 # cmdutil.py - help for command processing in mercurial
1 # cmdutil.py - help for command processing in mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
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(), 'mdiff util')
11 demandload(globals(), 'mdiff util')
12 demandload(globals(), 'os sys')
12 demandload(globals(), 'os sys')
13
13
14 revrangesep = ':'
14 revrangesep = ':'
15
15
16 def revpair(ui, repo, revs):
16 def revpair(ui, repo, revs):
17 '''return pair of nodes, given list of revisions. second item can
17 '''return pair of nodes, given list of revisions. second item can
18 be None, meaning use working dir.'''
18 be None, meaning use working dir.'''
19
19
20 def revfix(repo, val, defval):
20 def revfix(repo, val, defval):
21 if not val and val != 0:
21 if not val and val != 0:
22 val = defval
22 val = defval
23 return repo.lookup(val)
23 return repo.lookup(val)
24
24
25 if not revs:
25 if not revs:
26 return repo.dirstate.parents()[0], None
26 return repo.dirstate.parents()[0], None
27 end = None
27 end = None
28 if len(revs) == 1:
28 if len(revs) == 1:
29 if revrangesep in revs[0]:
29 if revrangesep in revs[0]:
30 start, end = revs[0].split(revrangesep, 1)
30 start, end = revs[0].split(revrangesep, 1)
31 start = revfix(repo, start, 0)
31 start = revfix(repo, start, 0)
32 end = revfix(repo, end, repo.changelog.count() - 1)
32 end = revfix(repo, end, repo.changelog.count() - 1)
33 else:
33 else:
34 start = revfix(repo, revs[0], None)
34 start = revfix(repo, revs[0], None)
35 elif len(revs) == 2:
35 elif len(revs) == 2:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
36 if revrangesep in revs[0] or revrangesep in revs[1]:
37 raise util.Abort(_('too many revisions specified'))
37 raise util.Abort(_('too many revisions specified'))
38 start = revfix(repo, revs[0], None)
38 start = revfix(repo, revs[0], None)
39 end = revfix(repo, revs[1], None)
39 end = revfix(repo, revs[1], None)
40 else:
40 else:
41 raise util.Abort(_('too many revisions specified'))
41 raise util.Abort(_('too many revisions specified'))
42 return start, end
42 return start, end
43
43
44 def revrange(ui, repo, revs):
44 def revrange(ui, repo, revs):
45 """Yield revision as strings from a list of revision specifications."""
45 """Yield revision as strings from a list of revision specifications."""
46
46
47 def revfix(repo, val, defval):
47 def revfix(repo, val, defval):
48 if not val and val != 0:
48 if not val and val != 0:
49 return defval
49 return defval
50 return repo.changelog.rev(repo.lookup(val))
50 return repo.changelog.rev(repo.lookup(val))
51
51
52 seen, l = {}, []
52 seen, l = {}, []
53 for spec in revs:
53 for spec in revs:
54 if revrangesep in spec:
54 if revrangesep in spec:
55 start, end = spec.split(revrangesep, 1)
55 start, end = spec.split(revrangesep, 1)
56 start = revfix(repo, start, 0)
56 start = revfix(repo, start, 0)
57 end = revfix(repo, end, repo.changelog.count() - 1)
57 end = revfix(repo, end, repo.changelog.count() - 1)
58 step = start > end and -1 or 1
58 step = start > end and -1 or 1
59 for rev in xrange(start, end+step, step):
59 for rev in xrange(start, end+step, step):
60 if rev in seen:
60 if rev in seen:
61 continue
61 continue
62 seen[rev] = 1
62 seen[rev] = 1
63 l.append(rev)
63 l.append(rev)
64 else:
64 else:
65 rev = revfix(repo, spec, None)
65 rev = revfix(repo, spec, None)
66 if rev in seen:
66 if rev in seen:
67 continue
67 continue
68 seen[rev] = 1
68 seen[rev] = 1
69 l.append(rev)
69 l.append(rev)
70
70
71 return l
71 return l
72
72
73 def make_filename(repo, pat, node,
73 def make_filename(repo, pat, node,
74 total=None, seqno=None, revwidth=None, pathname=None):
74 total=None, seqno=None, revwidth=None, pathname=None):
75 node_expander = {
75 node_expander = {
76 'H': lambda: hex(node),
76 'H': lambda: hex(node),
77 'R': lambda: str(repo.changelog.rev(node)),
77 'R': lambda: str(repo.changelog.rev(node)),
78 'h': lambda: short(node),
78 'h': lambda: short(node),
79 }
79 }
80 expander = {
80 expander = {
81 '%': lambda: '%',
81 '%': lambda: '%',
82 'b': lambda: os.path.basename(repo.root),
82 'b': lambda: os.path.basename(repo.root),
83 }
83 }
84
84
85 try:
85 try:
86 if node:
86 if node:
87 expander.update(node_expander)
87 expander.update(node_expander)
88 if node and revwidth is not None:
88 if node and revwidth is not None:
89 expander['r'] = (lambda:
89 expander['r'] = (lambda:
90 str(repo.changelog.rev(node)).zfill(revwidth))
90 str(repo.changelog.rev(node)).zfill(revwidth))
91 if total is not None:
91 if total is not None:
92 expander['N'] = lambda: str(total)
92 expander['N'] = lambda: str(total)
93 if seqno is not None:
93 if seqno is not None:
94 expander['n'] = lambda: str(seqno)
94 expander['n'] = lambda: str(seqno)
95 if total is not None and seqno is not None:
95 if total is not None and seqno is not None:
96 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
96 expander['n'] = lambda:str(seqno).zfill(len(str(total)))
97 if pathname is not None:
97 if pathname is not None:
98 expander['s'] = lambda: os.path.basename(pathname)
98 expander['s'] = lambda: os.path.basename(pathname)
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
99 expander['d'] = lambda: os.path.dirname(pathname) or '.'
100 expander['p'] = lambda: pathname
100 expander['p'] = lambda: pathname
101
101
102 newname = []
102 newname = []
103 patlen = len(pat)
103 patlen = len(pat)
104 i = 0
104 i = 0
105 while i < patlen:
105 while i < patlen:
106 c = pat[i]
106 c = pat[i]
107 if c == '%':
107 if c == '%':
108 i += 1
108 i += 1
109 c = pat[i]
109 c = pat[i]
110 c = expander[c]()
110 c = expander[c]()
111 newname.append(c)
111 newname.append(c)
112 i += 1
112 i += 1
113 return ''.join(newname)
113 return ''.join(newname)
114 except KeyError, inst:
114 except KeyError, inst:
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
115 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
116 inst.args[0])
116 inst.args[0])
117
117
118 def make_file(repo, pat, node=None,
118 def make_file(repo, pat, node=None,
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
119 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
120 if not pat or pat == '-':
120 if not pat or pat == '-':
121 return 'w' in mode and sys.stdout or sys.stdin
121 return 'w' in mode and sys.stdout or sys.stdin
122 if hasattr(pat, 'write') and 'w' in mode:
122 if hasattr(pat, 'write') and 'w' in mode:
123 return pat
123 return pat
124 if hasattr(pat, 'read') and 'r' in mode:
124 if hasattr(pat, 'read') and 'r' in mode:
125 return pat
125 return pat
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
126 return open(make_filename(repo, pat, node, total, seqno, revwidth,
127 pathname),
127 pathname),
128 mode)
128 mode)
129
129
130 def matchpats(repo, pats=[], opts={}, head=''):
130 def matchpats(repo, pats=[], opts={}, head=''):
131 cwd = repo.getcwd()
131 cwd = repo.getcwd()
132 if not pats and cwd:
132 if not pats and cwd:
133 opts['include'] = [os.path.join(cwd, i)
133 opts['include'] = [os.path.join(cwd, i)
134 for i in opts.get('include', [])]
134 for i in opts.get('include', [])]
135 opts['exclude'] = [os.path.join(cwd, x)
135 opts['exclude'] = [os.path.join(cwd, x)
136 for x in opts.get('exclude', [])]
136 for x in opts.get('exclude', [])]
137 cwd = ''
137 cwd = ''
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
138 return util.cmdmatcher(repo.root, cwd, pats or ['.'], opts.get('include'),
139 opts.get('exclude'), head)
139 opts.get('exclude'), head)
140
140
141 def makewalk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
141 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
142 files, matchfn, anypats = matchpats(repo, pats, opts, head)
142 files, matchfn, anypats = matchpats(repo, pats, opts, head)
143 exact = dict(zip(files, files))
143 exact = dict(zip(files, files))
144 def walk():
144 for src, fn in repo.walk(node=node, files=files, match=matchfn,
145 for src, fn in repo.walk(node=node, files=files, match=matchfn,
145 badmatch=badmatch):
146 badmatch=badmatch):
146 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
147 yield src, fn, util.pathto(repo.getcwd(), fn), fn in exact
148 return files, matchfn, walk()
149
150 def walk(repo, pats=[], opts={}, node=None, head='', badmatch=None):
151 files, matchfn, results = makewalk(repo, pats, opts, node, head, badmatch)
152 for r in results:
153 yield r
154
147
155 def findrenames(repo, added=None, removed=None, threshold=0.5):
148 def findrenames(repo, added=None, removed=None, threshold=0.5):
156 if added is None or removed is None:
149 if added is None or removed is None:
157 added, removed = repo.status()[1:3]
150 added, removed = repo.status()[1:3]
158 changes = repo.changelog.read(repo.dirstate.parents()[0])
151 changes = repo.changelog.read(repo.dirstate.parents()[0])
159 mf = repo.manifest.read(changes[0])
152 mf = repo.manifest.read(changes[0])
160 for a in added:
153 for a in added:
161 aa = repo.wread(a)
154 aa = repo.wread(a)
162 bestscore, bestname = None, None
155 bestscore, bestname = None, None
163 for r in removed:
156 for r in removed:
164 rr = repo.file(r).read(mf[r])
157 rr = repo.file(r).read(mf[r])
165 delta = mdiff.textdiff(aa, rr)
158 delta = mdiff.textdiff(aa, rr)
166 if len(delta) < len(aa):
159 if len(delta) < len(aa):
167 myscore = 1.0 - (float(len(delta)) / len(aa))
160 myscore = 1.0 - (float(len(delta)) / len(aa))
168 if bestscore is None or myscore > bestscore:
161 if bestscore is None or myscore > bestscore:
169 bestscore, bestname = myscore, r
162 bestscore, bestname = myscore, r
170 if bestname and bestscore >= threshold:
163 if bestname and bestscore >= threshold:
171 yield bestname, a, bestscore
164 yield bestname, a, bestscore
172
165
173 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
166 def addremove(repo, pats=[], opts={}, wlock=None, dry_run=None,
174 similarity=None):
167 similarity=None):
175 if dry_run is None:
168 if dry_run is None:
176 dry_run = opts.get('dry_run')
169 dry_run = opts.get('dry_run')
177 if similarity is None:
170 if similarity is None:
178 similarity = float(opts.get('similarity') or 0)
171 similarity = float(opts.get('similarity') or 0)
179 add, remove = [], []
172 add, remove = [], []
180 mapping = {}
173 mapping = {}
181 for src, abs, rel, exact in walk(repo, pats, opts):
174 for src, abs, rel, exact in walk(repo, pats, opts):
182 if src == 'f' and repo.dirstate.state(abs) == '?':
175 if src == 'f' and repo.dirstate.state(abs) == '?':
183 add.append(abs)
176 add.append(abs)
184 mapping[abs] = rel, exact
177 mapping[abs] = rel, exact
185 if repo.ui.verbose or not exact:
178 if repo.ui.verbose or not exact:
186 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
179 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
187 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
180 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel):
188 remove.append(abs)
181 remove.append(abs)
189 mapping[abs] = rel, exact
182 mapping[abs] = rel, exact
190 if repo.ui.verbose or not exact:
183 if repo.ui.verbose or not exact:
191 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
184 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
192 if not dry_run:
185 if not dry_run:
193 repo.add(add, wlock=wlock)
186 repo.add(add, wlock=wlock)
194 repo.remove(remove, wlock=wlock)
187 repo.remove(remove, wlock=wlock)
195 if similarity > 0:
188 if similarity > 0:
196 for old, new, score in findrenames(repo, add, remove, similarity):
189 for old, new, score in findrenames(repo, add, remove, similarity):
197 oldrel, oldexact = mapping[old]
190 oldrel, oldexact = mapping[old]
198 newrel, newexact = mapping[new]
191 newrel, newexact = mapping[new]
199 if repo.ui.verbose or not oldexact or not newexact:
192 if repo.ui.verbose or not oldexact or not newexact:
200 repo.ui.status(_('recording removal of %s as rename to %s '
193 repo.ui.status(_('recording removal of %s as rename to %s '
201 '(%d%% similar)\n') %
194 '(%d%% similar)\n') %
202 (oldrel, newrel, score * 100))
195 (oldrel, newrel, score * 100))
203 if not dry_run:
196 if not dry_run:
204 repo.copy(old, new, wlock=wlock)
197 repo.copy(old, new, wlock=wlock)
General Comments 0
You need to be logged in to leave comments. Login now