Mercurial > public > mercurial-scm > hg
annotate mercurial/dirstate.py @ 1276:25e5b1086624
Fix dirstate.changes for ignored directories.
Do a second walking pass to examine any leftover files in the dirstate
map that are in the .hgignore file but match our search criteria.
This fixes the case of entire directories never being examined due to
their presence in the .hgignore file, and should hopefully not add any
significant overhead.
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Sun, 18 Sep 2005 15:03:07 -0700 |
parents | 9ab14ca22e37 |
children | 32d8068b3e36 |
rev | line source |
---|---|
1089 | 1 """ |
2 dirstate.py - working directory tracking for mercurial | |
3 | |
4 Copyright 2005 Matt Mackall <mpm@selenic.com> | |
5 | |
6 This software may be used and distributed according to the terms | |
7 of the GNU General Public License, incorporated herein by reference. | |
8 """ | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
9 |
1094 | 10 import struct, os |
11 from node import * | |
262 | 12 from demandload import * |
1104 | 13 demandload(globals(), "time bisect stat util re") |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
14 |
220 | 15 class dirstate: |
244 | 16 def __init__(self, opener, ui, root): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
17 self.opener = opener |
244 | 18 self.root = root |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
19 self.dirty = 0 |
20 | 20 self.ui = ui |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
21 self.map = None |
227 | 22 self.pl = None |
363 | 23 self.copies = {} |
723 | 24 self.ignorefunc = None |
1183 | 25 self.blockignore = False |
723 | 26 |
27 def wjoin(self, f): | |
28 return os.path.join(self.root, f) | |
29 | |
870
a82eae840447
Teach walk code about absolute paths.
Bryan O'Sullivan <bos@serpentine.com>
parents:
839
diff
changeset
|
30 def getcwd(self): |
a82eae840447
Teach walk code about absolute paths.
Bryan O'Sullivan <bos@serpentine.com>
parents:
839
diff
changeset
|
31 cwd = os.getcwd() |
a82eae840447
Teach walk code about absolute paths.
Bryan O'Sullivan <bos@serpentine.com>
parents:
839
diff
changeset
|
32 if cwd == self.root: return '' |
a82eae840447
Teach walk code about absolute paths.
Bryan O'Sullivan <bos@serpentine.com>
parents:
839
diff
changeset
|
33 return cwd[len(self.root) + 1:] |
a82eae840447
Teach walk code about absolute paths.
Bryan O'Sullivan <bos@serpentine.com>
parents:
839
diff
changeset
|
34 |
1270
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
35 def hgignore(self): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
36 '''return the contents of .hgignore as a list of patterns. |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
37 |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
38 trailing white space is dropped. |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
39 the escape character is backslash. |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
40 comments start with #. |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
41 empty lines are skipped. |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
42 |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
43 lines can be of the following formats: |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
44 |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
45 syntax: regexp # defaults following lines to non-rooted regexps |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
46 syntax: glob # defaults following lines to non-rooted globs |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
47 re:pattern # non-rooted regular expression |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
48 glob:pattern # non-rooted glob |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
49 pattern # pattern of the current default type''' |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
50 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'} |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
51 def parselines(fp): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
52 for line in fp: |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
53 escape = False |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
54 for i in xrange(len(line)): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
55 if escape: escape = False |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
56 elif line[i] == '\\': escape = True |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
57 elif line[i] == '#': break |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
58 line = line[:i].rstrip() |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
59 if line: yield line |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
60 pats = [] |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
61 try: |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
62 fp = open(self.wjoin('.hgignore')) |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
63 syntax = 'relre:' |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
64 for line in parselines(fp): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
65 if line.startswith('syntax:'): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
66 s = line[7:].strip() |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
67 try: |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
68 syntax = syntaxes[s] |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
69 except KeyError: |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
70 self.ui.warn("ignoring invalid syntax '%s'\n" % s) |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
71 continue |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
72 pat = syntax + line |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
73 for s in syntaxes.values(): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
74 if line.startswith(s): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
75 pat = line |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
76 break |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
77 pats.append(pat) |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
78 except IOError: pass |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
79 return pats |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
80 |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
81 def ignore(self, fn): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
82 '''default match function used by dirstate and localrepository. |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
83 this honours the .hgignore file, and nothing more.''' |
1183 | 84 if self.blockignore: |
85 return False | |
723 | 86 if not self.ignorefunc: |
1271
9ab14ca22e37
Fix ignore regression.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1270
diff
changeset
|
87 ignore = self.hgignore() |
9ab14ca22e37
Fix ignore regression.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1270
diff
changeset
|
88 if ignore: |
9ab14ca22e37
Fix ignore regression.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1270
diff
changeset
|
89 files, self.ignorefunc, anypats = util.matcher(self.root, |
9ab14ca22e37
Fix ignore regression.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1270
diff
changeset
|
90 inc=ignore) |
9ab14ca22e37
Fix ignore regression.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1270
diff
changeset
|
91 else: |
9ab14ca22e37
Fix ignore regression.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1270
diff
changeset
|
92 self.ignorefunc = util.never |
1270
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
93 return self.ignorefunc(fn) |
220 | 94 |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
95 def __del__(self): |
220 | 96 if self.dirty: |
97 self.write() | |
98 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
99 def __getitem__(self, key): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
100 try: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
101 return self.map[key] |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
102 except TypeError: |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
103 self.read() |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
104 return self[key] |
220 | 105 |
106 def __contains__(self, key): | |
107 if not self.map: self.read() | |
108 return key in self.map | |
109 | |
227 | 110 def parents(self): |
111 if not self.pl: | |
112 self.read() | |
113 return self.pl | |
114 | |
723 | 115 def markdirty(self): |
116 if not self.dirty: | |
117 self.dirty = 1 | |
118 | |
1062 | 119 def setparents(self, p1, p2=nullid): |
723 | 120 self.markdirty() |
227 | 121 self.pl = p1, p2 |
122 | |
220 | 123 def state(self, key): |
124 try: | |
125 return self[key][0] | |
126 except KeyError: | |
127 return "?" | |
128 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
129 def read(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
130 if self.map is not None: return self.map |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
131 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
132 self.map = {} |
227 | 133 self.pl = [nullid, nullid] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
134 try: |
220 | 135 st = self.opener("dirstate").read() |
311 | 136 if not st: return |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
137 except: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
138 |
227 | 139 self.pl = [st[:20], st[20: 40]] |
140 | |
141 pos = 40 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
142 while pos < len(st): |
220 | 143 e = struct.unpack(">cllll", st[pos:pos+17]) |
144 l = e[4] | |
145 pos += 17 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
146 f = st[pos:pos + l] |
515 | 147 if '\0' in f: |
363 | 148 f, c = f.split('\0') |
149 self.copies[f] = c | |
220 | 150 self.map[f] = e[:4] |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
151 pos += l |
363 | 152 |
153 def copy(self, source, dest): | |
154 self.read() | |
723 | 155 self.markdirty() |
363 | 156 self.copies[dest] = source |
157 | |
158 def copied(self, file): | |
159 return self.copies.get(file, None) | |
515 | 160 |
862
d70c1c31fd45
Fix 3-way-merge of original parent, workdir and new parent.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
861
diff
changeset
|
161 def update(self, files, state, **kw): |
220 | 162 ''' current states: |
163 n normal | |
231 | 164 m needs merging |
220 | 165 r marked for removal |
166 a marked for addition''' | |
167 | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
168 if not files: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
169 self.read() |
723 | 170 self.markdirty() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
171 for f in files: |
220 | 172 if state == "r": |
173 self.map[f] = ('r', 0, 0, 0) | |
174 else: | |
1230 | 175 s = os.lstat(os.path.join(self.root, f)) |
862
d70c1c31fd45
Fix 3-way-merge of original parent, workdir and new parent.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
861
diff
changeset
|
176 st_size = kw.get('st_size', s.st_size) |
d70c1c31fd45
Fix 3-way-merge of original parent, workdir and new parent.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
861
diff
changeset
|
177 st_mtime = kw.get('st_mtime', s.st_mtime) |
865
2d2fee33ec68
Cleanup after previous changes:
Thomas Arendsen Hein <thomas@intevation.de>
parents:
863
diff
changeset
|
178 self.map[f] = (state, s.st_mode, st_size, st_mtime) |
1117 | 179 if self.copies.has_key(f): |
180 del self.copies[f] | |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
181 |
220 | 182 def forget(self, files): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
183 if not files: return |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
184 self.read() |
723 | 185 self.markdirty() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
186 for f in files: |
20 | 187 try: |
188 del self.map[f] | |
189 except KeyError: | |
220 | 190 self.ui.warn("not in dirstate: %s!\n" % f) |
20 | 191 pass |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
192 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
193 def clear(self): |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
194 self.map = {} |
723 | 195 self.markdirty() |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
196 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
197 def write(self): |
220 | 198 st = self.opener("dirstate", "w") |
227 | 199 st.write("".join(self.pl)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
200 for f, e in self.map.items(): |
363 | 201 c = self.copied(f) |
202 if c: | |
203 f = f + "\0" + c | |
220 | 204 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f)) |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
205 st.write(e + f) |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
206 self.dirty = 0 |
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
207 |
879 | 208 def filterfiles(self, files): |
209 ret = {} | |
210 unknown = [] | |
211 | |
212 for x in files: | |
213 if x is '.': | |
214 return self.map.copy() | |
215 if x not in self.map: | |
216 unknown.append(x) | |
217 else: | |
218 ret[x] = self.map[x] | |
919 | 219 |
879 | 220 if not unknown: |
221 return ret | |
222 | |
223 b = self.map.keys() | |
224 b.sort() | |
225 blen = len(b) | |
226 | |
227 for x in unknown: | |
228 bs = bisect.bisect(b, x) | |
919 | 229 if bs != 0 and b[bs-1] == x: |
879 | 230 ret[x] = self.map[x] |
231 continue | |
232 while bs < blen: | |
233 s = b[bs] | |
234 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/': | |
235 ret[s] = self.map[s] | |
236 else: | |
237 break | |
238 bs += 1 | |
239 return ret | |
240 | |
1062 | 241 def walk(self, files=None, match=util.always, dc=None): |
0
9117c6561b0b
Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff
changeset
|
242 self.read() |
879 | 243 |
723 | 244 # walk all files by default |
879 | 245 if not files: |
246 files = [self.root] | |
247 if not dc: | |
248 dc = self.map.copy() | |
249 elif not dc: | |
250 dc = self.filterfiles(files) | |
919 | 251 |
1183 | 252 def statmatch(file, stat): |
1224
cc61d366bc3b
Fix Windows status problem from new dirstate walk code
mpm@selenic.com
parents:
1183
diff
changeset
|
253 file = util.pconvert(file) |
1183 | 254 if file not in dc and self.ignore(file): |
255 return False | |
256 return match(file) | |
1224
cc61d366bc3b
Fix Windows status problem from new dirstate walk code
mpm@selenic.com
parents:
1183
diff
changeset
|
257 |
1183 | 258 return self.walkhelper(files=files, statmatch=statmatch, dc=dc) |
259 | |
260 # walk recursively through the directory tree, finding all files | |
261 # matched by the statmatch function | |
1224
cc61d366bc3b
Fix Windows status problem from new dirstate walk code
mpm@selenic.com
parents:
1183
diff
changeset
|
262 # |
1183 | 263 # results are yielded in a tuple (src, filename), where src is one of: |
264 # 'f' the file was found in the directory tree | |
265 # 'm' the file was only in the dirstate and not in the tree | |
266 # | |
267 # dc is an optional arg for the current dirstate. dc is not modified | |
268 # directly by this function, but might be modified by your statmatch call. | |
269 # | |
270 def walkhelper(self, files, statmatch, dc): | |
271 # recursion free walker, faster than os.walk. | |
272 def findfiles(s): | |
273 retfiles = [] | |
274 work = [s] | |
275 while work: | |
276 top = work.pop() | |
277 names = os.listdir(top) | |
278 names.sort() | |
279 # nd is the top of the repository dir tree | |
280 nd = util.normpath(top[len(self.root) + 1:]) | |
281 if nd == '.': nd = '' | |
282 for f in names: | |
283 np = os.path.join(nd, f) | |
284 if seen(np): | |
285 continue | |
286 p = os.path.join(top, f) | |
1228
db950da49539
Fix dangling symlink bug in dirstate walk code
mpm@selenic.com
parents:
1224
diff
changeset
|
287 # don't trip over symlinks |
db950da49539
Fix dangling symlink bug in dirstate walk code
mpm@selenic.com
parents:
1224
diff
changeset
|
288 st = os.lstat(p) |
1183 | 289 if stat.S_ISDIR(st.st_mode): |
290 ds = os.path.join(nd, f +'/') | |
291 if statmatch(ds, st): | |
292 work.append(p) | |
293 else: | |
294 if statmatch(np, st): | |
1245
d0a960b437a8
Files not getting added appropiately
Chris Mason <mason@suse.com>
parents:
1230
diff
changeset
|
295 yield util.pconvert(np) |
1183 | 296 |
821
72d9bd4841f3
Ensure that dirstate.walk only yields names once.
Bryan O'Sullivan <bos@serpentine.com>
parents:
820
diff
changeset
|
297 known = {'.hg': 1} |
72d9bd4841f3
Ensure that dirstate.walk only yields names once.
Bryan O'Sullivan <bos@serpentine.com>
parents:
820
diff
changeset
|
298 def seen(fn): |
72d9bd4841f3
Ensure that dirstate.walk only yields names once.
Bryan O'Sullivan <bos@serpentine.com>
parents:
820
diff
changeset
|
299 if fn in known: return True |
72d9bd4841f3
Ensure that dirstate.walk only yields names once.
Bryan O'Sullivan <bos@serpentine.com>
parents:
820
diff
changeset
|
300 known[fn] = 1 |
1183 | 301 |
302 # step one, find all files that match our criteria | |
303 files.sort() | |
304 for ff in util.unique(files): | |
305 f = os.path.join(self.root, ff) | |
306 try: | |
1230 | 307 st = os.lstat(f) |
1183 | 308 except OSError, inst: |
309 if ff not in dc: self.ui.warn('%s: %s\n' % ( | |
310 util.pathto(self.getcwd(), ff), | |
311 inst.strerror)) | |
312 continue | |
313 if stat.S_ISDIR(st.st_mode): | |
314 sorted = [ x for x in findfiles(f) ] | |
315 sorted.sort() | |
316 for fl in sorted: | |
317 yield 'f', fl | |
318 elif stat.S_ISREG(st.st_mode): | |
319 ff = util.normpath(ff) | |
320 if seen(ff): | |
884
087771ebe2e6
Fix walk code for files that do not exist anywhere, and unhandled types.
Bryan O'Sullivan <bos@serpentine.com>
parents:
883
diff
changeset
|
321 continue |
1183 | 322 found = False |
323 self.blockignore = True | |
324 if statmatch(ff, st): | |
325 found = True | |
326 self.blockignore = False | |
327 if found: | |
884
087771ebe2e6
Fix walk code for files that do not exist anywhere, and unhandled types.
Bryan O'Sullivan <bos@serpentine.com>
parents:
883
diff
changeset
|
328 yield 'f', ff |
1183 | 329 else: |
330 kind = 'unknown' | |
331 if stat.S_ISCHR(st.st_mode): kind = 'character device' | |
332 elif stat.S_ISBLK(st.st_mode): kind = 'block device' | |
333 elif stat.S_ISFIFO(st.st_mode): kind = 'fifo' | |
334 elif stat.S_ISLNK(st.st_mode): kind = 'symbolic link' | |
335 elif stat.S_ISSOCK(st.st_mode): kind = 'socket' | |
336 self.ui.warn('%s: unsupported file type (type is %s)\n' % ( | |
337 util.pathto(self.getcwd(), ff), | |
338 kind)) | |
536 | 339 |
1183 | 340 # step two run through anything left in the dc hash and yield |
341 # if we haven't already seen it | |
342 ks = dc.keys() | |
343 ks.sort() | |
344 for k in ks: | |
345 if not seen(k) and (statmatch(k, None)): | |
726
809a870a0e73
Add a source designator to the walk methods.
Bryan O'Sullivan <bos@serpentine.com>
parents:
725
diff
changeset
|
346 yield 'm', k |
669
8aa2a282eda4
.hgignore speedups patch incorporating Matt's feedback.
mwilli2@localhost.localdomain
parents:
667
diff
changeset
|
347 |
861
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
348 def changes(self, files=None, match=util.always): |
723 | 349 self.read() |
879 | 350 if not files: |
1183 | 351 files = [self.root] |
879 | 352 dc = self.map.copy() |
353 else: | |
354 dc = self.filterfiles(files) | |
861
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
355 lookup, modified, added, unknown = [], [], [], [] |
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
356 removed, deleted = [], [] |
723 | 357 |
1183 | 358 # statmatch function to eliminate entries from the dirstate copy |
359 # and put files into the appropriate array. This gets passed | |
360 # to the walking code | |
361 def statmatch(fn, s): | |
1224
cc61d366bc3b
Fix Windows status problem from new dirstate walk code
mpm@selenic.com
parents:
1183
diff
changeset
|
362 fn = util.pconvert(fn) |
1183 | 363 def checkappend(l, fn): |
364 if match is util.always or match(fn): | |
365 l.append(fn) | |
1224
cc61d366bc3b
Fix Windows status problem from new dirstate walk code
mpm@selenic.com
parents:
1183
diff
changeset
|
366 |
1183 | 367 if not s or stat.S_ISDIR(s.st_mode): |
1268
c631f26346ca
Fix performance of dirstate.changes with ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1245
diff
changeset
|
368 if self.ignore(fn): return False |
c631f26346ca
Fix performance of dirstate.changes with ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1245
diff
changeset
|
369 return match(fn) |
1183 | 370 |
861
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
371 if not stat.S_ISREG(s.st_mode): |
1183 | 372 return False |
373 c = dc.pop(fn, None) | |
861
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
374 if c: |
1183 | 375 type, mode, size, time = c |
376 # check the common case first | |
377 if type == 'n': | |
378 if size != s.st_size or (mode ^ s.st_mode) & 0100: | |
379 checkappend(modified, fn) | |
380 elif time != s.st_mtime: | |
381 checkappend(lookup, fn) | |
382 elif type == 'm': | |
383 checkappend(modified, fn) | |
384 elif type == 'a': | |
385 checkappend(added, fn) | |
386 elif type == 'r': | |
387 checkappend(unknown, fn) | |
1270
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
388 elif not self.ignore(fn) and match(fn): |
fc3b41570082
Switch to new syntax for .hgignore files.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1268
diff
changeset
|
389 unknown.append(fn) |
1183 | 390 # return false because we've already handled all cases above. |
391 # there's no need for the walking code to process the file | |
392 # any further. | |
393 return False | |
536 | 394 |
1183 | 395 # because our statmatch always returns false, self.walk will only |
396 # return files in the dirstate map that are not present in the FS. | |
397 # But, we still need to iterate through the results to force the | |
398 # walk to complete | |
399 for src, fn in self.walkhelper(files, statmatch, dc): | |
400 pass | |
401 | |
1276
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
402 # there may be patterns in the .hgignore file that prevent us |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
403 # from examining entire directories in the dirstate map, so we |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
404 # go back and explicitly examine any matching files we've |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
405 # ignored |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
406 unexamined = [fn for fn in dc.iterkeys() |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
407 if self.ignore(fn) and match(fn)] |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
408 |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
409 for src, fn in self.walkhelper(unexamined, statmatch, dc): |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
410 pass |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
411 |
1183 | 412 # anything left in dc didn't exist in the filesystem |
1276
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
413 for fn, c in dc.iteritems(): |
25e5b1086624
Fix dirstate.changes for ignored directories.
Bryan O'Sullivan <bos@serpentine.com>
parents:
1271
diff
changeset
|
414 if not match(fn): continue |
861
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
415 if c[0] == 'r': |
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
416 removed.append(fn) |
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
417 else: |
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
418 deleted.append(fn) |
cbe5c4d016b7
dirstate.changes() now distinguishes 'hg remove'd or just deleted files.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
856
diff
changeset
|
419 return (lookup, modified, added, removed + deleted, unknown) |