##// END OF EJS Templates
Fix dirstate imports
mpm@selenic.com -
r1104:98988cc3 default
parent child Browse files
Show More
@@ -1,312 +1,312 b''
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
8 """
8 """
9
9
10 import struct, os
10 import struct, os
11 from node import *
11 from node import *
12 from demandload import *
12 from demandload import *
13 demandload(globals(), "time bisect stat util")
13 demandload(globals(), "time bisect stat util re")
14
14
15 class dirstate:
15 class dirstate:
16 def __init__(self, opener, ui, root):
16 def __init__(self, opener, ui, root):
17 self.opener = opener
17 self.opener = opener
18 self.root = root
18 self.root = root
19 self.dirty = 0
19 self.dirty = 0
20 self.ui = ui
20 self.ui = ui
21 self.map = None
21 self.map = None
22 self.pl = None
22 self.pl = None
23 self.copies = {}
23 self.copies = {}
24 self.ignorefunc = None
24 self.ignorefunc = None
25
25
26 def wjoin(self, f):
26 def wjoin(self, f):
27 return os.path.join(self.root, f)
27 return os.path.join(self.root, f)
28
28
29 def getcwd(self):
29 def getcwd(self):
30 cwd = os.getcwd()
30 cwd = os.getcwd()
31 if cwd == self.root: return ''
31 if cwd == self.root: return ''
32 return cwd[len(self.root) + 1:]
32 return cwd[len(self.root) + 1:]
33
33
34 def ignore(self, f):
34 def ignore(self, f):
35 if not self.ignorefunc:
35 if not self.ignorefunc:
36 bigpat = []
36 bigpat = []
37 try:
37 try:
38 l = file(self.wjoin(".hgignore"))
38 l = file(self.wjoin(".hgignore"))
39 for pat in l:
39 for pat in l:
40 p = pat.rstrip()
40 p = pat.rstrip()
41 if p:
41 if p:
42 try:
42 try:
43 re.compile(p)
43 re.compile(p)
44 except:
44 except:
45 self.ui.warn("ignoring invalid ignore"
45 self.ui.warn("ignoring invalid ignore"
46 + " regular expression '%s'\n" % p)
46 + " regular expression '%s'\n" % p)
47 else:
47 else:
48 bigpat.append(p)
48 bigpat.append(p)
49 except IOError: pass
49 except IOError: pass
50
50
51 if bigpat:
51 if bigpat:
52 s = "(?:%s)" % (")|(?:".join(bigpat))
52 s = "(?:%s)" % (")|(?:".join(bigpat))
53 r = re.compile(s)
53 r = re.compile(s)
54 self.ignorefunc = r.search
54 self.ignorefunc = r.search
55 else:
55 else:
56 self.ignorefunc = util.never
56 self.ignorefunc = util.never
57
57
58 return self.ignorefunc(f)
58 return self.ignorefunc(f)
59
59
60 def __del__(self):
60 def __del__(self):
61 if self.dirty:
61 if self.dirty:
62 self.write()
62 self.write()
63
63
64 def __getitem__(self, key):
64 def __getitem__(self, key):
65 try:
65 try:
66 return self.map[key]
66 return self.map[key]
67 except TypeError:
67 except TypeError:
68 self.read()
68 self.read()
69 return self[key]
69 return self[key]
70
70
71 def __contains__(self, key):
71 def __contains__(self, key):
72 if not self.map: self.read()
72 if not self.map: self.read()
73 return key in self.map
73 return key in self.map
74
74
75 def parents(self):
75 def parents(self):
76 if not self.pl:
76 if not self.pl:
77 self.read()
77 self.read()
78 return self.pl
78 return self.pl
79
79
80 def markdirty(self):
80 def markdirty(self):
81 if not self.dirty:
81 if not self.dirty:
82 self.dirty = 1
82 self.dirty = 1
83
83
84 def setparents(self, p1, p2=nullid):
84 def setparents(self, p1, p2=nullid):
85 self.markdirty()
85 self.markdirty()
86 self.pl = p1, p2
86 self.pl = p1, p2
87
87
88 def state(self, key):
88 def state(self, key):
89 try:
89 try:
90 return self[key][0]
90 return self[key][0]
91 except KeyError:
91 except KeyError:
92 return "?"
92 return "?"
93
93
94 def read(self):
94 def read(self):
95 if self.map is not None: return self.map
95 if self.map is not None: return self.map
96
96
97 self.map = {}
97 self.map = {}
98 self.pl = [nullid, nullid]
98 self.pl = [nullid, nullid]
99 try:
99 try:
100 st = self.opener("dirstate").read()
100 st = self.opener("dirstate").read()
101 if not st: return
101 if not st: return
102 except: return
102 except: return
103
103
104 self.pl = [st[:20], st[20: 40]]
104 self.pl = [st[:20], st[20: 40]]
105
105
106 pos = 40
106 pos = 40
107 while pos < len(st):
107 while pos < len(st):
108 e = struct.unpack(">cllll", st[pos:pos+17])
108 e = struct.unpack(">cllll", st[pos:pos+17])
109 l = e[4]
109 l = e[4]
110 pos += 17
110 pos += 17
111 f = st[pos:pos + l]
111 f = st[pos:pos + l]
112 if '\0' in f:
112 if '\0' in f:
113 f, c = f.split('\0')
113 f, c = f.split('\0')
114 self.copies[f] = c
114 self.copies[f] = c
115 self.map[f] = e[:4]
115 self.map[f] = e[:4]
116 pos += l
116 pos += l
117
117
118 def copy(self, source, dest):
118 def copy(self, source, dest):
119 self.read()
119 self.read()
120 self.markdirty()
120 self.markdirty()
121 self.copies[dest] = source
121 self.copies[dest] = source
122
122
123 def copied(self, file):
123 def copied(self, file):
124 return self.copies.get(file, None)
124 return self.copies.get(file, None)
125
125
126 def update(self, files, state, **kw):
126 def update(self, files, state, **kw):
127 ''' current states:
127 ''' current states:
128 n normal
128 n normal
129 m needs merging
129 m needs merging
130 r marked for removal
130 r marked for removal
131 a marked for addition'''
131 a marked for addition'''
132
132
133 if not files: return
133 if not files: return
134 self.read()
134 self.read()
135 self.markdirty()
135 self.markdirty()
136 for f in files:
136 for f in files:
137 if state == "r":
137 if state == "r":
138 self.map[f] = ('r', 0, 0, 0)
138 self.map[f] = ('r', 0, 0, 0)
139 else:
139 else:
140 s = os.stat(os.path.join(self.root, f))
140 s = os.stat(os.path.join(self.root, f))
141 st_size = kw.get('st_size', s.st_size)
141 st_size = kw.get('st_size', s.st_size)
142 st_mtime = kw.get('st_mtime', s.st_mtime)
142 st_mtime = kw.get('st_mtime', s.st_mtime)
143 self.map[f] = (state, s.st_mode, st_size, st_mtime)
143 self.map[f] = (state, s.st_mode, st_size, st_mtime)
144
144
145 def forget(self, files):
145 def forget(self, files):
146 if not files: return
146 if not files: return
147 self.read()
147 self.read()
148 self.markdirty()
148 self.markdirty()
149 for f in files:
149 for f in files:
150 try:
150 try:
151 del self.map[f]
151 del self.map[f]
152 except KeyError:
152 except KeyError:
153 self.ui.warn("not in dirstate: %s!\n" % f)
153 self.ui.warn("not in dirstate: %s!\n" % f)
154 pass
154 pass
155
155
156 def clear(self):
156 def clear(self):
157 self.map = {}
157 self.map = {}
158 self.markdirty()
158 self.markdirty()
159
159
160 def write(self):
160 def write(self):
161 st = self.opener("dirstate", "w")
161 st = self.opener("dirstate", "w")
162 st.write("".join(self.pl))
162 st.write("".join(self.pl))
163 for f, e in self.map.items():
163 for f, e in self.map.items():
164 c = self.copied(f)
164 c = self.copied(f)
165 if c:
165 if c:
166 f = f + "\0" + c
166 f = f + "\0" + c
167 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
167 e = struct.pack(">cllll", e[0], e[1], e[2], e[3], len(f))
168 st.write(e + f)
168 st.write(e + f)
169 self.dirty = 0
169 self.dirty = 0
170
170
171 def filterfiles(self, files):
171 def filterfiles(self, files):
172 ret = {}
172 ret = {}
173 unknown = []
173 unknown = []
174
174
175 for x in files:
175 for x in files:
176 if x is '.':
176 if x is '.':
177 return self.map.copy()
177 return self.map.copy()
178 if x not in self.map:
178 if x not in self.map:
179 unknown.append(x)
179 unknown.append(x)
180 else:
180 else:
181 ret[x] = self.map[x]
181 ret[x] = self.map[x]
182
182
183 if not unknown:
183 if not unknown:
184 return ret
184 return ret
185
185
186 b = self.map.keys()
186 b = self.map.keys()
187 b.sort()
187 b.sort()
188 blen = len(b)
188 blen = len(b)
189
189
190 for x in unknown:
190 for x in unknown:
191 bs = bisect.bisect(b, x)
191 bs = bisect.bisect(b, x)
192 if bs != 0 and b[bs-1] == x:
192 if bs != 0 and b[bs-1] == x:
193 ret[x] = self.map[x]
193 ret[x] = self.map[x]
194 continue
194 continue
195 while bs < blen:
195 while bs < blen:
196 s = b[bs]
196 s = b[bs]
197 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
197 if len(s) > len(x) and s.startswith(x) and s[len(x)] == '/':
198 ret[s] = self.map[s]
198 ret[s] = self.map[s]
199 else:
199 else:
200 break
200 break
201 bs += 1
201 bs += 1
202 return ret
202 return ret
203
203
204 def walk(self, files=None, match=util.always, dc=None):
204 def walk(self, files=None, match=util.always, dc=None):
205 self.read()
205 self.read()
206
206
207 # walk all files by default
207 # walk all files by default
208 if not files:
208 if not files:
209 files = [self.root]
209 files = [self.root]
210 if not dc:
210 if not dc:
211 dc = self.map.copy()
211 dc = self.map.copy()
212 elif not dc:
212 elif not dc:
213 dc = self.filterfiles(files)
213 dc = self.filterfiles(files)
214
214
215 known = {'.hg': 1}
215 known = {'.hg': 1}
216 def seen(fn):
216 def seen(fn):
217 if fn in known: return True
217 if fn in known: return True
218 known[fn] = 1
218 known[fn] = 1
219 def traverse():
219 def traverse():
220 for ff in util.unique(files):
220 for ff in util.unique(files):
221 f = os.path.join(self.root, ff)
221 f = os.path.join(self.root, ff)
222 try:
222 try:
223 st = os.stat(f)
223 st = os.stat(f)
224 except OSError, inst:
224 except OSError, inst:
225 if ff not in dc: self.ui.warn('%s: %s\n' % (
225 if ff not in dc: self.ui.warn('%s: %s\n' % (
226 util.pathto(self.getcwd(), ff),
226 util.pathto(self.getcwd(), ff),
227 inst.strerror))
227 inst.strerror))
228 continue
228 continue
229 if stat.S_ISDIR(st.st_mode):
229 if stat.S_ISDIR(st.st_mode):
230 for dir, subdirs, fl in os.walk(f):
230 for dir, subdirs, fl in os.walk(f):
231 d = dir[len(self.root) + 1:]
231 d = dir[len(self.root) + 1:]
232 nd = util.normpath(d)
232 nd = util.normpath(d)
233 if nd == '.': nd = ''
233 if nd == '.': nd = ''
234 if seen(nd):
234 if seen(nd):
235 subdirs[:] = []
235 subdirs[:] = []
236 continue
236 continue
237 for sd in subdirs:
237 for sd in subdirs:
238 ds = os.path.join(nd, sd +'/')
238 ds = os.path.join(nd, sd +'/')
239 if self.ignore(ds) or not match(ds):
239 if self.ignore(ds) or not match(ds):
240 subdirs.remove(sd)
240 subdirs.remove(sd)
241 subdirs.sort()
241 subdirs.sort()
242 fl.sort()
242 fl.sort()
243 for fn in fl:
243 for fn in fl:
244 fn = util.pconvert(os.path.join(d, fn))
244 fn = util.pconvert(os.path.join(d, fn))
245 yield 'f', fn
245 yield 'f', fn
246 elif stat.S_ISREG(st.st_mode):
246 elif stat.S_ISREG(st.st_mode):
247 yield 'f', ff
247 yield 'f', ff
248 else:
248 else:
249 kind = 'unknown'
249 kind = 'unknown'
250 if stat.S_ISCHR(st.st_mode): kind = 'character device'
250 if stat.S_ISCHR(st.st_mode): kind = 'character device'
251 elif stat.S_ISBLK(st.st_mode): kind = 'block device'
251 elif stat.S_ISBLK(st.st_mode): kind = 'block device'
252 elif stat.S_ISFIFO(st.st_mode): kind = 'fifo'
252 elif stat.S_ISFIFO(st.st_mode): kind = 'fifo'
253 elif stat.S_ISLNK(st.st_mode): kind = 'symbolic link'
253 elif stat.S_ISLNK(st.st_mode): kind = 'symbolic link'
254 elif stat.S_ISSOCK(st.st_mode): kind = 'socket'
254 elif stat.S_ISSOCK(st.st_mode): kind = 'socket'
255 self.ui.warn('%s: unsupported file type (type is %s)\n' % (
255 self.ui.warn('%s: unsupported file type (type is %s)\n' % (
256 util.pathto(self.getcwd(), ff),
256 util.pathto(self.getcwd(), ff),
257 kind))
257 kind))
258
258
259 ks = dc.keys()
259 ks = dc.keys()
260 ks.sort()
260 ks.sort()
261 for k in ks:
261 for k in ks:
262 yield 'm', k
262 yield 'm', k
263
263
264 # yield only files that match: all in dirstate, others only if
264 # yield only files that match: all in dirstate, others only if
265 # not in .hgignore
265 # not in .hgignore
266
266
267 for src, fn in util.unique(traverse()):
267 for src, fn in util.unique(traverse()):
268 fn = util.normpath(fn)
268 fn = util.normpath(fn)
269 if seen(fn): continue
269 if seen(fn): continue
270 if fn not in dc and self.ignore(fn):
270 if fn not in dc and self.ignore(fn):
271 continue
271 continue
272 if match(fn):
272 if match(fn):
273 yield src, fn
273 yield src, fn
274
274
275 def changes(self, files=None, match=util.always):
275 def changes(self, files=None, match=util.always):
276 self.read()
276 self.read()
277 if not files:
277 if not files:
278 dc = self.map.copy()
278 dc = self.map.copy()
279 else:
279 else:
280 dc = self.filterfiles(files)
280 dc = self.filterfiles(files)
281 lookup, modified, added, unknown = [], [], [], []
281 lookup, modified, added, unknown = [], [], [], []
282 removed, deleted = [], []
282 removed, deleted = [], []
283
283
284 for src, fn in self.walk(files, match, dc=dc):
284 for src, fn in self.walk(files, match, dc=dc):
285 try:
285 try:
286 s = os.stat(os.path.join(self.root, fn))
286 s = os.stat(os.path.join(self.root, fn))
287 except OSError:
287 except OSError:
288 continue
288 continue
289 if not stat.S_ISREG(s.st_mode):
289 if not stat.S_ISREG(s.st_mode):
290 continue
290 continue
291 c = dc.get(fn)
291 c = dc.get(fn)
292 if c:
292 if c:
293 del dc[fn]
293 del dc[fn]
294 if c[0] == 'm':
294 if c[0] == 'm':
295 modified.append(fn)
295 modified.append(fn)
296 elif c[0] == 'a':
296 elif c[0] == 'a':
297 added.append(fn)
297 added.append(fn)
298 elif c[0] == 'r':
298 elif c[0] == 'r':
299 unknown.append(fn)
299 unknown.append(fn)
300 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
300 elif c[2] != s.st_size or (c[1] ^ s.st_mode) & 0100:
301 modified.append(fn)
301 modified.append(fn)
302 elif c[3] != s.st_mtime:
302 elif c[3] != s.st_mtime:
303 lookup.append(fn)
303 lookup.append(fn)
304 else:
304 else:
305 unknown.append(fn)
305 unknown.append(fn)
306
306
307 for fn, c in [(fn, c) for fn, c in dc.items() if match(fn)]:
307 for fn, c in [(fn, c) for fn, c in dc.items() if match(fn)]:
308 if c[0] == 'r':
308 if c[0] == 'r':
309 removed.append(fn)
309 removed.append(fn)
310 else:
310 else:
311 deleted.append(fn)
311 deleted.append(fn)
312 return (lookup, modified, added, removed + deleted, unknown)
312 return (lookup, modified, added, removed + deleted, unknown)
General Comments 0
You need to be logged in to leave comments. Login now