Mercurial > public > mercurial-scm > hg
comparison mercurial/wdutil.py @ 14259:df9ccd39828c
patch: move updatedir() from cmdutil into patch
Also, create an artificial wdutil.py to avoid import cycles between patch.py
and cmdutil.py.
author | Patrick Mezard <pmezard@gmail.com> |
---|---|
date | Sun, 08 May 2011 17:48:30 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
14258:50e3fb2ab9fa | 14259:df9ccd39828c |
---|---|
1 # wdutil.py - working dir utilities | |
2 # | |
3 # Copyright 2011 Patrick Mezard <pmezard@gmail.com> | |
4 # | |
5 # This software may be used and distributed according to the terms of the | |
6 # GNU General Public License version 2 or any later version. | |
7 | |
8 import glob, os | |
9 import util, similar, scmutil | |
10 import match as matchmod | |
11 from i18n import _ | |
12 | |
13 def expandpats(pats): | |
14 if not util.expandglobs: | |
15 return list(pats) | |
16 ret = [] | |
17 for p in pats: | |
18 kind, name = matchmod._patsplit(p, None) | |
19 if kind is None: | |
20 try: | |
21 globbed = glob.glob(name) | |
22 except re.error: | |
23 globbed = [name] | |
24 if globbed: | |
25 ret.extend(globbed) | |
26 continue | |
27 ret.append(p) | |
28 return ret | |
29 | |
30 def match(repo, pats=[], opts={}, globbed=False, default='relpath'): | |
31 if pats == ("",): | |
32 pats = [] | |
33 if not globbed and default == 'relpath': | |
34 pats = expandpats(pats or []) | |
35 m = matchmod.match(repo.root, repo.getcwd(), pats, | |
36 opts.get('include'), opts.get('exclude'), default, | |
37 auditor=repo.auditor) | |
38 def badfn(f, msg): | |
39 repo.ui.warn("%s: %s\n" % (m.rel(f), msg)) | |
40 m.bad = badfn | |
41 return m | |
42 | |
43 def matchall(repo): | |
44 return matchmod.always(repo.root, repo.getcwd()) | |
45 | |
46 def matchfiles(repo, files): | |
47 return matchmod.exact(repo.root, repo.getcwd(), files) | |
48 | |
49 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None): | |
50 if dry_run is None: | |
51 dry_run = opts.get('dry_run') | |
52 if similarity is None: | |
53 similarity = float(opts.get('similarity') or 0) | |
54 # we'd use status here, except handling of symlinks and ignore is tricky | |
55 added, unknown, deleted, removed = [], [], [], [] | |
56 audit_path = scmutil.pathauditor(repo.root) | |
57 m = match(repo, pats, opts) | |
58 for abs in repo.walk(m): | |
59 target = repo.wjoin(abs) | |
60 good = True | |
61 try: | |
62 audit_path(abs) | |
63 except (OSError, util.Abort): | |
64 good = False | |
65 rel = m.rel(abs) | |
66 exact = m.exact(abs) | |
67 if good and abs not in repo.dirstate: | |
68 unknown.append(abs) | |
69 if repo.ui.verbose or not exact: | |
70 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs)) | |
71 elif repo.dirstate[abs] != 'r' and (not good or not os.path.lexists(target) | |
72 or (os.path.isdir(target) and not os.path.islink(target))): | |
73 deleted.append(abs) | |
74 if repo.ui.verbose or not exact: | |
75 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs)) | |
76 # for finding renames | |
77 elif repo.dirstate[abs] == 'r': | |
78 removed.append(abs) | |
79 elif repo.dirstate[abs] == 'a': | |
80 added.append(abs) | |
81 copies = {} | |
82 if similarity > 0: | |
83 for old, new, score in similar.findrenames(repo, | |
84 added + unknown, removed + deleted, similarity): | |
85 if repo.ui.verbose or not m.exact(old) or not m.exact(new): | |
86 repo.ui.status(_('recording removal of %s as rename to %s ' | |
87 '(%d%% similar)\n') % | |
88 (m.rel(old), m.rel(new), score * 100)) | |
89 copies[new] = old | |
90 | |
91 if not dry_run: | |
92 wctx = repo[None] | |
93 wlock = repo.wlock() | |
94 try: | |
95 wctx.remove(deleted) | |
96 wctx.add(unknown) | |
97 for new, old in copies.iteritems(): | |
98 wctx.copy(old, new) | |
99 finally: | |
100 wlock.release() | |
101 | |
102 def updatedir(ui, repo, patches, similarity=0): | |
103 '''Update dirstate after patch application according to metadata''' | |
104 if not patches: | |
105 return [] | |
106 copies = [] | |
107 removes = set() | |
108 cfiles = patches.keys() | |
109 cwd = repo.getcwd() | |
110 if cwd: | |
111 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()] | |
112 for f in patches: | |
113 gp = patches[f] | |
114 if not gp: | |
115 continue | |
116 if gp.op == 'RENAME': | |
117 copies.append((gp.oldpath, gp.path)) | |
118 removes.add(gp.oldpath) | |
119 elif gp.op == 'COPY': | |
120 copies.append((gp.oldpath, gp.path)) | |
121 elif gp.op == 'DELETE': | |
122 removes.add(gp.path) | |
123 | |
124 wctx = repo[None] | |
125 for src, dst in copies: | |
126 dirstatecopy(ui, repo, wctx, src, dst, cwd=cwd) | |
127 if (not similarity) and removes: | |
128 wctx.remove(sorted(removes), True) | |
129 | |
130 for f in patches: | |
131 gp = patches[f] | |
132 if gp and gp.mode: | |
133 islink, isexec = gp.mode | |
134 dst = repo.wjoin(gp.path) | |
135 # patch won't create empty files | |
136 if gp.op == 'ADD' and not os.path.lexists(dst): | |
137 flags = (isexec and 'x' or '') + (islink and 'l' or '') | |
138 repo.wwrite(gp.path, '', flags) | |
139 util.setflags(dst, islink, isexec) | |
140 addremove(repo, cfiles, similarity=similarity) | |
141 files = patches.keys() | |
142 files.extend([r for r in removes if r not in files]) | |
143 return sorted(files) | |
144 | |
145 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None): | |
146 """Update the dirstate to reflect the intent of copying src to dst. For | |
147 different reasons it might not end with dst being marked as copied from src. | |
148 """ | |
149 origsrc = repo.dirstate.copied(src) or src | |
150 if dst == origsrc: # copying back a copy? | |
151 if repo.dirstate[dst] not in 'mn' and not dryrun: | |
152 repo.dirstate.normallookup(dst) | |
153 else: | |
154 if repo.dirstate[origsrc] == 'a' and origsrc == src: | |
155 if not ui.quiet: | |
156 ui.warn(_("%s has not been committed yet, so no copy " | |
157 "data will be stored for %s.\n") | |
158 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd))) | |
159 if repo.dirstate[dst] in '?r' and not dryrun: | |
160 wctx.add([dst]) | |
161 elif not dryrun: | |
162 wctx.copy(origsrc, dst) |