##// END OF EJS Templates
dirstate: use absolute_import
Gregory Szorc -
r27503:0f459662 default
parent child Browse files
Show More
@@ -1,1180 +1,1193
1 # dirstate.py - working directory tracking for mercurial
1 # dirstate.py - working directory tracking for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
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.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import nullid
8 from __future__ import absolute_import
9 from i18n import _
9
10 import scmutil, util, osutil, parsers, encoding, pathutil, error
10 import errno
11 import os, stat, errno
11 import os
12 import match as matchmod
12 import stat
13
14 from .i18n import _
15 from .node import nullid
16 from . import (
17 encoding,
18 error,
19 match as matchmod,
20 osutil,
21 parsers,
22 pathutil,
23 scmutil,
24 util,
25 )
13
26
14 propertycache = util.propertycache
27 propertycache = util.propertycache
15 filecache = scmutil.filecache
28 filecache = scmutil.filecache
16 _rangemask = 0x7fffffff
29 _rangemask = 0x7fffffff
17
30
18 dirstatetuple = parsers.dirstatetuple
31 dirstatetuple = parsers.dirstatetuple
19
32
20 class repocache(filecache):
33 class repocache(filecache):
21 """filecache for files in .hg/"""
34 """filecache for files in .hg/"""
22 def join(self, obj, fname):
35 def join(self, obj, fname):
23 return obj._opener.join(fname)
36 return obj._opener.join(fname)
24
37
25 class rootcache(filecache):
38 class rootcache(filecache):
26 """filecache for files in the repository root"""
39 """filecache for files in the repository root"""
27 def join(self, obj, fname):
40 def join(self, obj, fname):
28 return obj._join(fname)
41 return obj._join(fname)
29
42
30 def _getfsnow(vfs):
43 def _getfsnow(vfs):
31 '''Get "now" timestamp on filesystem'''
44 '''Get "now" timestamp on filesystem'''
32 tmpfd, tmpname = vfs.mkstemp()
45 tmpfd, tmpname = vfs.mkstemp()
33 try:
46 try:
34 return os.fstat(tmpfd).st_mtime
47 return os.fstat(tmpfd).st_mtime
35 finally:
48 finally:
36 os.close(tmpfd)
49 os.close(tmpfd)
37 vfs.unlink(tmpname)
50 vfs.unlink(tmpname)
38
51
39 def _trypending(root, vfs, filename):
52 def _trypending(root, vfs, filename):
40 '''Open file to be read according to HG_PENDING environment variable
53 '''Open file to be read according to HG_PENDING environment variable
41
54
42 This opens '.pending' of specified 'filename' only when HG_PENDING
55 This opens '.pending' of specified 'filename' only when HG_PENDING
43 is equal to 'root'.
56 is equal to 'root'.
44
57
45 This returns '(fp, is_pending_opened)' tuple.
58 This returns '(fp, is_pending_opened)' tuple.
46 '''
59 '''
47 if root == os.environ.get('HG_PENDING'):
60 if root == os.environ.get('HG_PENDING'):
48 try:
61 try:
49 return (vfs('%s.pending' % filename), True)
62 return (vfs('%s.pending' % filename), True)
50 except IOError as inst:
63 except IOError as inst:
51 if inst.errno != errno.ENOENT:
64 if inst.errno != errno.ENOENT:
52 raise
65 raise
53 return (vfs(filename), False)
66 return (vfs(filename), False)
54
67
55 class dirstate(object):
68 class dirstate(object):
56
69
57 def __init__(self, opener, ui, root, validate):
70 def __init__(self, opener, ui, root, validate):
58 '''Create a new dirstate object.
71 '''Create a new dirstate object.
59
72
60 opener is an open()-like callable that can be used to open the
73 opener is an open()-like callable that can be used to open the
61 dirstate file; root is the root of the directory tracked by
74 dirstate file; root is the root of the directory tracked by
62 the dirstate.
75 the dirstate.
63 '''
76 '''
64 self._opener = opener
77 self._opener = opener
65 self._validate = validate
78 self._validate = validate
66 self._root = root
79 self._root = root
67 # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
80 # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
68 # UNC path pointing to root share (issue4557)
81 # UNC path pointing to root share (issue4557)
69 self._rootdir = pathutil.normasprefix(root)
82 self._rootdir = pathutil.normasprefix(root)
70 # internal config: ui.forcecwd
83 # internal config: ui.forcecwd
71 forcecwd = ui.config('ui', 'forcecwd')
84 forcecwd = ui.config('ui', 'forcecwd')
72 if forcecwd:
85 if forcecwd:
73 self._cwd = forcecwd
86 self._cwd = forcecwd
74 self._dirty = False
87 self._dirty = False
75 self._dirtypl = False
88 self._dirtypl = False
76 self._lastnormaltime = 0
89 self._lastnormaltime = 0
77 self._ui = ui
90 self._ui = ui
78 self._filecache = {}
91 self._filecache = {}
79 self._parentwriters = 0
92 self._parentwriters = 0
80 self._filename = 'dirstate'
93 self._filename = 'dirstate'
81 self._pendingfilename = '%s.pending' % self._filename
94 self._pendingfilename = '%s.pending' % self._filename
82
95
83 # for consistent view between _pl() and _read() invocations
96 # for consistent view between _pl() and _read() invocations
84 self._pendingmode = None
97 self._pendingmode = None
85
98
86 def beginparentchange(self):
99 def beginparentchange(self):
87 '''Marks the beginning of a set of changes that involve changing
100 '''Marks the beginning of a set of changes that involve changing
88 the dirstate parents. If there is an exception during this time,
101 the dirstate parents. If there is an exception during this time,
89 the dirstate will not be written when the wlock is released. This
102 the dirstate will not be written when the wlock is released. This
90 prevents writing an incoherent dirstate where the parent doesn't
103 prevents writing an incoherent dirstate where the parent doesn't
91 match the contents.
104 match the contents.
92 '''
105 '''
93 self._parentwriters += 1
106 self._parentwriters += 1
94
107
95 def endparentchange(self):
108 def endparentchange(self):
96 '''Marks the end of a set of changes that involve changing the
109 '''Marks the end of a set of changes that involve changing the
97 dirstate parents. Once all parent changes have been marked done,
110 dirstate parents. Once all parent changes have been marked done,
98 the wlock will be free to write the dirstate on release.
111 the wlock will be free to write the dirstate on release.
99 '''
112 '''
100 if self._parentwriters > 0:
113 if self._parentwriters > 0:
101 self._parentwriters -= 1
114 self._parentwriters -= 1
102
115
103 def pendingparentchange(self):
116 def pendingparentchange(self):
104 '''Returns true if the dirstate is in the middle of a set of changes
117 '''Returns true if the dirstate is in the middle of a set of changes
105 that modify the dirstate parent.
118 that modify the dirstate parent.
106 '''
119 '''
107 return self._parentwriters > 0
120 return self._parentwriters > 0
108
121
109 @propertycache
122 @propertycache
110 def _map(self):
123 def _map(self):
111 '''Return the dirstate contents as a map from filename to
124 '''Return the dirstate contents as a map from filename to
112 (state, mode, size, time).'''
125 (state, mode, size, time).'''
113 self._read()
126 self._read()
114 return self._map
127 return self._map
115
128
116 @propertycache
129 @propertycache
117 def _copymap(self):
130 def _copymap(self):
118 self._read()
131 self._read()
119 return self._copymap
132 return self._copymap
120
133
121 @propertycache
134 @propertycache
122 def _filefoldmap(self):
135 def _filefoldmap(self):
123 try:
136 try:
124 makefilefoldmap = parsers.make_file_foldmap
137 makefilefoldmap = parsers.make_file_foldmap
125 except AttributeError:
138 except AttributeError:
126 pass
139 pass
127 else:
140 else:
128 return makefilefoldmap(self._map, util.normcasespec,
141 return makefilefoldmap(self._map, util.normcasespec,
129 util.normcasefallback)
142 util.normcasefallback)
130
143
131 f = {}
144 f = {}
132 normcase = util.normcase
145 normcase = util.normcase
133 for name, s in self._map.iteritems():
146 for name, s in self._map.iteritems():
134 if s[0] != 'r':
147 if s[0] != 'r':
135 f[normcase(name)] = name
148 f[normcase(name)] = name
136 f['.'] = '.' # prevents useless util.fspath() invocation
149 f['.'] = '.' # prevents useless util.fspath() invocation
137 return f
150 return f
138
151
139 @propertycache
152 @propertycache
140 def _dirfoldmap(self):
153 def _dirfoldmap(self):
141 f = {}
154 f = {}
142 normcase = util.normcase
155 normcase = util.normcase
143 for name in self._dirs:
156 for name in self._dirs:
144 f[normcase(name)] = name
157 f[normcase(name)] = name
145 return f
158 return f
146
159
147 @repocache('branch')
160 @repocache('branch')
148 def _branch(self):
161 def _branch(self):
149 try:
162 try:
150 return self._opener.read("branch").strip() or "default"
163 return self._opener.read("branch").strip() or "default"
151 except IOError as inst:
164 except IOError as inst:
152 if inst.errno != errno.ENOENT:
165 if inst.errno != errno.ENOENT:
153 raise
166 raise
154 return "default"
167 return "default"
155
168
156 @propertycache
169 @propertycache
157 def _pl(self):
170 def _pl(self):
158 try:
171 try:
159 fp = self._opendirstatefile()
172 fp = self._opendirstatefile()
160 st = fp.read(40)
173 st = fp.read(40)
161 fp.close()
174 fp.close()
162 l = len(st)
175 l = len(st)
163 if l == 40:
176 if l == 40:
164 return st[:20], st[20:40]
177 return st[:20], st[20:40]
165 elif l > 0 and l < 40:
178 elif l > 0 and l < 40:
166 raise error.Abort(_('working directory state appears damaged!'))
179 raise error.Abort(_('working directory state appears damaged!'))
167 except IOError as err:
180 except IOError as err:
168 if err.errno != errno.ENOENT:
181 if err.errno != errno.ENOENT:
169 raise
182 raise
170 return [nullid, nullid]
183 return [nullid, nullid]
171
184
172 @propertycache
185 @propertycache
173 def _dirs(self):
186 def _dirs(self):
174 return util.dirs(self._map, 'r')
187 return util.dirs(self._map, 'r')
175
188
176 def dirs(self):
189 def dirs(self):
177 return self._dirs
190 return self._dirs
178
191
179 @rootcache('.hgignore')
192 @rootcache('.hgignore')
180 def _ignore(self):
193 def _ignore(self):
181 files = []
194 files = []
182 if os.path.exists(self._join('.hgignore')):
195 if os.path.exists(self._join('.hgignore')):
183 files.append(self._join('.hgignore'))
196 files.append(self._join('.hgignore'))
184 for name, path in self._ui.configitems("ui"):
197 for name, path in self._ui.configitems("ui"):
185 if name == 'ignore' or name.startswith('ignore.'):
198 if name == 'ignore' or name.startswith('ignore.'):
186 # we need to use os.path.join here rather than self._join
199 # we need to use os.path.join here rather than self._join
187 # because path is arbitrary and user-specified
200 # because path is arbitrary and user-specified
188 files.append(os.path.join(self._rootdir, util.expandpath(path)))
201 files.append(os.path.join(self._rootdir, util.expandpath(path)))
189
202
190 if not files:
203 if not files:
191 return util.never
204 return util.never
192
205
193 pats = ['include:%s' % f for f in files]
206 pats = ['include:%s' % f for f in files]
194 return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
207 return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
195
208
196 @propertycache
209 @propertycache
197 def _slash(self):
210 def _slash(self):
198 return self._ui.configbool('ui', 'slash') and os.sep != '/'
211 return self._ui.configbool('ui', 'slash') and os.sep != '/'
199
212
200 @propertycache
213 @propertycache
201 def _checklink(self):
214 def _checklink(self):
202 return util.checklink(self._root)
215 return util.checklink(self._root)
203
216
204 @propertycache
217 @propertycache
205 def _checkexec(self):
218 def _checkexec(self):
206 return util.checkexec(self._root)
219 return util.checkexec(self._root)
207
220
208 @propertycache
221 @propertycache
209 def _checkcase(self):
222 def _checkcase(self):
210 return not util.checkcase(self._join('.hg'))
223 return not util.checkcase(self._join('.hg'))
211
224
212 def _join(self, f):
225 def _join(self, f):
213 # much faster than os.path.join()
226 # much faster than os.path.join()
214 # it's safe because f is always a relative path
227 # it's safe because f is always a relative path
215 return self._rootdir + f
228 return self._rootdir + f
216
229
217 def flagfunc(self, buildfallback):
230 def flagfunc(self, buildfallback):
218 if self._checklink and self._checkexec:
231 if self._checklink and self._checkexec:
219 def f(x):
232 def f(x):
220 try:
233 try:
221 st = os.lstat(self._join(x))
234 st = os.lstat(self._join(x))
222 if util.statislink(st):
235 if util.statislink(st):
223 return 'l'
236 return 'l'
224 if util.statisexec(st):
237 if util.statisexec(st):
225 return 'x'
238 return 'x'
226 except OSError:
239 except OSError:
227 pass
240 pass
228 return ''
241 return ''
229 return f
242 return f
230
243
231 fallback = buildfallback()
244 fallback = buildfallback()
232 if self._checklink:
245 if self._checklink:
233 def f(x):
246 def f(x):
234 if os.path.islink(self._join(x)):
247 if os.path.islink(self._join(x)):
235 return 'l'
248 return 'l'
236 if 'x' in fallback(x):
249 if 'x' in fallback(x):
237 return 'x'
250 return 'x'
238 return ''
251 return ''
239 return f
252 return f
240 if self._checkexec:
253 if self._checkexec:
241 def f(x):
254 def f(x):
242 if 'l' in fallback(x):
255 if 'l' in fallback(x):
243 return 'l'
256 return 'l'
244 if util.isexec(self._join(x)):
257 if util.isexec(self._join(x)):
245 return 'x'
258 return 'x'
246 return ''
259 return ''
247 return f
260 return f
248 else:
261 else:
249 return fallback
262 return fallback
250
263
251 @propertycache
264 @propertycache
252 def _cwd(self):
265 def _cwd(self):
253 return os.getcwd()
266 return os.getcwd()
254
267
255 def getcwd(self):
268 def getcwd(self):
256 '''Return the path from which a canonical path is calculated.
269 '''Return the path from which a canonical path is calculated.
257
270
258 This path should be used to resolve file patterns or to convert
271 This path should be used to resolve file patterns or to convert
259 canonical paths back to file paths for display. It shouldn't be
272 canonical paths back to file paths for display. It shouldn't be
260 used to get real file paths. Use vfs functions instead.
273 used to get real file paths. Use vfs functions instead.
261 '''
274 '''
262 cwd = self._cwd
275 cwd = self._cwd
263 if cwd == self._root:
276 if cwd == self._root:
264 return ''
277 return ''
265 # self._root ends with a path separator if self._root is '/' or 'C:\'
278 # self._root ends with a path separator if self._root is '/' or 'C:\'
266 rootsep = self._root
279 rootsep = self._root
267 if not util.endswithsep(rootsep):
280 if not util.endswithsep(rootsep):
268 rootsep += os.sep
281 rootsep += os.sep
269 if cwd.startswith(rootsep):
282 if cwd.startswith(rootsep):
270 return cwd[len(rootsep):]
283 return cwd[len(rootsep):]
271 else:
284 else:
272 # we're outside the repo. return an absolute path.
285 # we're outside the repo. return an absolute path.
273 return cwd
286 return cwd
274
287
275 def pathto(self, f, cwd=None):
288 def pathto(self, f, cwd=None):
276 if cwd is None:
289 if cwd is None:
277 cwd = self.getcwd()
290 cwd = self.getcwd()
278 path = util.pathto(self._root, cwd, f)
291 path = util.pathto(self._root, cwd, f)
279 if self._slash:
292 if self._slash:
280 return util.pconvert(path)
293 return util.pconvert(path)
281 return path
294 return path
282
295
283 def __getitem__(self, key):
296 def __getitem__(self, key):
284 '''Return the current state of key (a filename) in the dirstate.
297 '''Return the current state of key (a filename) in the dirstate.
285
298
286 States are:
299 States are:
287 n normal
300 n normal
288 m needs merging
301 m needs merging
289 r marked for removal
302 r marked for removal
290 a marked for addition
303 a marked for addition
291 ? not tracked
304 ? not tracked
292 '''
305 '''
293 return self._map.get(key, ("?",))[0]
306 return self._map.get(key, ("?",))[0]
294
307
295 def __contains__(self, key):
308 def __contains__(self, key):
296 return key in self._map
309 return key in self._map
297
310
298 def __iter__(self):
311 def __iter__(self):
299 for x in sorted(self._map):
312 for x in sorted(self._map):
300 yield x
313 yield x
301
314
302 def iteritems(self):
315 def iteritems(self):
303 return self._map.iteritems()
316 return self._map.iteritems()
304
317
305 def parents(self):
318 def parents(self):
306 return [self._validate(p) for p in self._pl]
319 return [self._validate(p) for p in self._pl]
307
320
308 def p1(self):
321 def p1(self):
309 return self._validate(self._pl[0])
322 return self._validate(self._pl[0])
310
323
311 def p2(self):
324 def p2(self):
312 return self._validate(self._pl[1])
325 return self._validate(self._pl[1])
313
326
314 def branch(self):
327 def branch(self):
315 return encoding.tolocal(self._branch)
328 return encoding.tolocal(self._branch)
316
329
317 def setparents(self, p1, p2=nullid):
330 def setparents(self, p1, p2=nullid):
318 """Set dirstate parents to p1 and p2.
331 """Set dirstate parents to p1 and p2.
319
332
320 When moving from two parents to one, 'm' merged entries a
333 When moving from two parents to one, 'm' merged entries a
321 adjusted to normal and previous copy records discarded and
334 adjusted to normal and previous copy records discarded and
322 returned by the call.
335 returned by the call.
323
336
324 See localrepo.setparents()
337 See localrepo.setparents()
325 """
338 """
326 if self._parentwriters == 0:
339 if self._parentwriters == 0:
327 raise ValueError("cannot set dirstate parent without "
340 raise ValueError("cannot set dirstate parent without "
328 "calling dirstate.beginparentchange")
341 "calling dirstate.beginparentchange")
329
342
330 self._dirty = self._dirtypl = True
343 self._dirty = self._dirtypl = True
331 oldp2 = self._pl[1]
344 oldp2 = self._pl[1]
332 self._pl = p1, p2
345 self._pl = p1, p2
333 copies = {}
346 copies = {}
334 if oldp2 != nullid and p2 == nullid:
347 if oldp2 != nullid and p2 == nullid:
335 for f, s in self._map.iteritems():
348 for f, s in self._map.iteritems():
336 # Discard 'm' markers when moving away from a merge state
349 # Discard 'm' markers when moving away from a merge state
337 if s[0] == 'm':
350 if s[0] == 'm':
338 if f in self._copymap:
351 if f in self._copymap:
339 copies[f] = self._copymap[f]
352 copies[f] = self._copymap[f]
340 self.normallookup(f)
353 self.normallookup(f)
341 # Also fix up otherparent markers
354 # Also fix up otherparent markers
342 elif s[0] == 'n' and s[2] == -2:
355 elif s[0] == 'n' and s[2] == -2:
343 if f in self._copymap:
356 if f in self._copymap:
344 copies[f] = self._copymap[f]
357 copies[f] = self._copymap[f]
345 self.add(f)
358 self.add(f)
346 return copies
359 return copies
347
360
348 def setbranch(self, branch):
361 def setbranch(self, branch):
349 self._branch = encoding.fromlocal(branch)
362 self._branch = encoding.fromlocal(branch)
350 f = self._opener('branch', 'w', atomictemp=True)
363 f = self._opener('branch', 'w', atomictemp=True)
351 try:
364 try:
352 f.write(self._branch + '\n')
365 f.write(self._branch + '\n')
353 f.close()
366 f.close()
354
367
355 # make sure filecache has the correct stat info for _branch after
368 # make sure filecache has the correct stat info for _branch after
356 # replacing the underlying file
369 # replacing the underlying file
357 ce = self._filecache['_branch']
370 ce = self._filecache['_branch']
358 if ce:
371 if ce:
359 ce.refresh()
372 ce.refresh()
360 except: # re-raises
373 except: # re-raises
361 f.discard()
374 f.discard()
362 raise
375 raise
363
376
364 def _opendirstatefile(self):
377 def _opendirstatefile(self):
365 fp, mode = _trypending(self._root, self._opener, self._filename)
378 fp, mode = _trypending(self._root, self._opener, self._filename)
366 if self._pendingmode is not None and self._pendingmode != mode:
379 if self._pendingmode is not None and self._pendingmode != mode:
367 fp.close()
380 fp.close()
368 raise error.Abort(_('working directory state may be '
381 raise error.Abort(_('working directory state may be '
369 'changed parallelly'))
382 'changed parallelly'))
370 self._pendingmode = mode
383 self._pendingmode = mode
371 return fp
384 return fp
372
385
373 def _read(self):
386 def _read(self):
374 self._map = {}
387 self._map = {}
375 self._copymap = {}
388 self._copymap = {}
376 try:
389 try:
377 fp = self._opendirstatefile()
390 fp = self._opendirstatefile()
378 try:
391 try:
379 st = fp.read()
392 st = fp.read()
380 finally:
393 finally:
381 fp.close()
394 fp.close()
382 except IOError as err:
395 except IOError as err:
383 if err.errno != errno.ENOENT:
396 if err.errno != errno.ENOENT:
384 raise
397 raise
385 return
398 return
386 if not st:
399 if not st:
387 return
400 return
388
401
389 if util.safehasattr(parsers, 'dict_new_presized'):
402 if util.safehasattr(parsers, 'dict_new_presized'):
390 # Make an estimate of the number of files in the dirstate based on
403 # Make an estimate of the number of files in the dirstate based on
391 # its size. From a linear regression on a set of real-world repos,
404 # its size. From a linear regression on a set of real-world repos,
392 # all over 10,000 files, the size of a dirstate entry is 85
405 # all over 10,000 files, the size of a dirstate entry is 85
393 # bytes. The cost of resizing is significantly higher than the cost
406 # bytes. The cost of resizing is significantly higher than the cost
394 # of filling in a larger presized dict, so subtract 20% from the
407 # of filling in a larger presized dict, so subtract 20% from the
395 # size.
408 # size.
396 #
409 #
397 # This heuristic is imperfect in many ways, so in a future dirstate
410 # This heuristic is imperfect in many ways, so in a future dirstate
398 # format update it makes sense to just record the number of entries
411 # format update it makes sense to just record the number of entries
399 # on write.
412 # on write.
400 self._map = parsers.dict_new_presized(len(st) / 71)
413 self._map = parsers.dict_new_presized(len(st) / 71)
401
414
402 # Python's garbage collector triggers a GC each time a certain number
415 # Python's garbage collector triggers a GC each time a certain number
403 # of container objects (the number being defined by
416 # of container objects (the number being defined by
404 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
417 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
405 # for each file in the dirstate. The C version then immediately marks
418 # for each file in the dirstate. The C version then immediately marks
406 # them as not to be tracked by the collector. However, this has no
419 # them as not to be tracked by the collector. However, this has no
407 # effect on when GCs are triggered, only on what objects the GC looks
420 # effect on when GCs are triggered, only on what objects the GC looks
408 # into. This means that O(number of files) GCs are unavoidable.
421 # into. This means that O(number of files) GCs are unavoidable.
409 # Depending on when in the process's lifetime the dirstate is parsed,
422 # Depending on when in the process's lifetime the dirstate is parsed,
410 # this can get very expensive. As a workaround, disable GC while
423 # this can get very expensive. As a workaround, disable GC while
411 # parsing the dirstate.
424 # parsing the dirstate.
412 #
425 #
413 # (we cannot decorate the function directly since it is in a C module)
426 # (we cannot decorate the function directly since it is in a C module)
414 parse_dirstate = util.nogc(parsers.parse_dirstate)
427 parse_dirstate = util.nogc(parsers.parse_dirstate)
415 p = parse_dirstate(self._map, self._copymap, st)
428 p = parse_dirstate(self._map, self._copymap, st)
416 if not self._dirtypl:
429 if not self._dirtypl:
417 self._pl = p
430 self._pl = p
418
431
419 def invalidate(self):
432 def invalidate(self):
420 for a in ("_map", "_copymap", "_filefoldmap", "_dirfoldmap", "_branch",
433 for a in ("_map", "_copymap", "_filefoldmap", "_dirfoldmap", "_branch",
421 "_pl", "_dirs", "_ignore"):
434 "_pl", "_dirs", "_ignore"):
422 if a in self.__dict__:
435 if a in self.__dict__:
423 delattr(self, a)
436 delattr(self, a)
424 self._lastnormaltime = 0
437 self._lastnormaltime = 0
425 self._dirty = False
438 self._dirty = False
426 self._parentwriters = 0
439 self._parentwriters = 0
427
440
428 def copy(self, source, dest):
441 def copy(self, source, dest):
429 """Mark dest as a copy of source. Unmark dest if source is None."""
442 """Mark dest as a copy of source. Unmark dest if source is None."""
430 if source == dest:
443 if source == dest:
431 return
444 return
432 self._dirty = True
445 self._dirty = True
433 if source is not None:
446 if source is not None:
434 self._copymap[dest] = source
447 self._copymap[dest] = source
435 elif dest in self._copymap:
448 elif dest in self._copymap:
436 del self._copymap[dest]
449 del self._copymap[dest]
437
450
438 def copied(self, file):
451 def copied(self, file):
439 return self._copymap.get(file, None)
452 return self._copymap.get(file, None)
440
453
441 def copies(self):
454 def copies(self):
442 return self._copymap
455 return self._copymap
443
456
444 def _droppath(self, f):
457 def _droppath(self, f):
445 if self[f] not in "?r" and "_dirs" in self.__dict__:
458 if self[f] not in "?r" and "_dirs" in self.__dict__:
446 self._dirs.delpath(f)
459 self._dirs.delpath(f)
447
460
448 if "_filefoldmap" in self.__dict__:
461 if "_filefoldmap" in self.__dict__:
449 normed = util.normcase(f)
462 normed = util.normcase(f)
450 if normed in self._filefoldmap:
463 if normed in self._filefoldmap:
451 del self._filefoldmap[normed]
464 del self._filefoldmap[normed]
452
465
453 def _addpath(self, f, state, mode, size, mtime):
466 def _addpath(self, f, state, mode, size, mtime):
454 oldstate = self[f]
467 oldstate = self[f]
455 if state == 'a' or oldstate == 'r':
468 if state == 'a' or oldstate == 'r':
456 scmutil.checkfilename(f)
469 scmutil.checkfilename(f)
457 if f in self._dirs:
470 if f in self._dirs:
458 raise error.Abort(_('directory %r already in dirstate') % f)
471 raise error.Abort(_('directory %r already in dirstate') % f)
459 # shadows
472 # shadows
460 for d in util.finddirs(f):
473 for d in util.finddirs(f):
461 if d in self._dirs:
474 if d in self._dirs:
462 break
475 break
463 if d in self._map and self[d] != 'r':
476 if d in self._map and self[d] != 'r':
464 raise error.Abort(
477 raise error.Abort(
465 _('file %r in dirstate clashes with %r') % (d, f))
478 _('file %r in dirstate clashes with %r') % (d, f))
466 if oldstate in "?r" and "_dirs" in self.__dict__:
479 if oldstate in "?r" and "_dirs" in self.__dict__:
467 self._dirs.addpath(f)
480 self._dirs.addpath(f)
468 self._dirty = True
481 self._dirty = True
469 self._map[f] = dirstatetuple(state, mode, size, mtime)
482 self._map[f] = dirstatetuple(state, mode, size, mtime)
470
483
471 def normal(self, f):
484 def normal(self, f):
472 '''Mark a file normal and clean.'''
485 '''Mark a file normal and clean.'''
473 s = os.lstat(self._join(f))
486 s = os.lstat(self._join(f))
474 mtime = s.st_mtime
487 mtime = s.st_mtime
475 self._addpath(f, 'n', s.st_mode,
488 self._addpath(f, 'n', s.st_mode,
476 s.st_size & _rangemask, mtime & _rangemask)
489 s.st_size & _rangemask, mtime & _rangemask)
477 if f in self._copymap:
490 if f in self._copymap:
478 del self._copymap[f]
491 del self._copymap[f]
479 if mtime > self._lastnormaltime:
492 if mtime > self._lastnormaltime:
480 # Remember the most recent modification timeslot for status(),
493 # Remember the most recent modification timeslot for status(),
481 # to make sure we won't miss future size-preserving file content
494 # to make sure we won't miss future size-preserving file content
482 # modifications that happen within the same timeslot.
495 # modifications that happen within the same timeslot.
483 self._lastnormaltime = mtime
496 self._lastnormaltime = mtime
484
497
485 def normallookup(self, f):
498 def normallookup(self, f):
486 '''Mark a file normal, but possibly dirty.'''
499 '''Mark a file normal, but possibly dirty.'''
487 if self._pl[1] != nullid and f in self._map:
500 if self._pl[1] != nullid and f in self._map:
488 # if there is a merge going on and the file was either
501 # if there is a merge going on and the file was either
489 # in state 'm' (-1) or coming from other parent (-2) before
502 # in state 'm' (-1) or coming from other parent (-2) before
490 # being removed, restore that state.
503 # being removed, restore that state.
491 entry = self._map[f]
504 entry = self._map[f]
492 if entry[0] == 'r' and entry[2] in (-1, -2):
505 if entry[0] == 'r' and entry[2] in (-1, -2):
493 source = self._copymap.get(f)
506 source = self._copymap.get(f)
494 if entry[2] == -1:
507 if entry[2] == -1:
495 self.merge(f)
508 self.merge(f)
496 elif entry[2] == -2:
509 elif entry[2] == -2:
497 self.otherparent(f)
510 self.otherparent(f)
498 if source:
511 if source:
499 self.copy(source, f)
512 self.copy(source, f)
500 return
513 return
501 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
514 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
502 return
515 return
503 self._addpath(f, 'n', 0, -1, -1)
516 self._addpath(f, 'n', 0, -1, -1)
504 if f in self._copymap:
517 if f in self._copymap:
505 del self._copymap[f]
518 del self._copymap[f]
506
519
507 def otherparent(self, f):
520 def otherparent(self, f):
508 '''Mark as coming from the other parent, always dirty.'''
521 '''Mark as coming from the other parent, always dirty.'''
509 if self._pl[1] == nullid:
522 if self._pl[1] == nullid:
510 raise error.Abort(_("setting %r to other parent "
523 raise error.Abort(_("setting %r to other parent "
511 "only allowed in merges") % f)
524 "only allowed in merges") % f)
512 if f in self and self[f] == 'n':
525 if f in self and self[f] == 'n':
513 # merge-like
526 # merge-like
514 self._addpath(f, 'm', 0, -2, -1)
527 self._addpath(f, 'm', 0, -2, -1)
515 else:
528 else:
516 # add-like
529 # add-like
517 self._addpath(f, 'n', 0, -2, -1)
530 self._addpath(f, 'n', 0, -2, -1)
518
531
519 if f in self._copymap:
532 if f in self._copymap:
520 del self._copymap[f]
533 del self._copymap[f]
521
534
522 def add(self, f):
535 def add(self, f):
523 '''Mark a file added.'''
536 '''Mark a file added.'''
524 self._addpath(f, 'a', 0, -1, -1)
537 self._addpath(f, 'a', 0, -1, -1)
525 if f in self._copymap:
538 if f in self._copymap:
526 del self._copymap[f]
539 del self._copymap[f]
527
540
528 def remove(self, f):
541 def remove(self, f):
529 '''Mark a file removed.'''
542 '''Mark a file removed.'''
530 self._dirty = True
543 self._dirty = True
531 self._droppath(f)
544 self._droppath(f)
532 size = 0
545 size = 0
533 if self._pl[1] != nullid and f in self._map:
546 if self._pl[1] != nullid and f in self._map:
534 # backup the previous state
547 # backup the previous state
535 entry = self._map[f]
548 entry = self._map[f]
536 if entry[0] == 'm': # merge
549 if entry[0] == 'm': # merge
537 size = -1
550 size = -1
538 elif entry[0] == 'n' and entry[2] == -2: # other parent
551 elif entry[0] == 'n' and entry[2] == -2: # other parent
539 size = -2
552 size = -2
540 self._map[f] = dirstatetuple('r', 0, size, 0)
553 self._map[f] = dirstatetuple('r', 0, size, 0)
541 if size == 0 and f in self._copymap:
554 if size == 0 and f in self._copymap:
542 del self._copymap[f]
555 del self._copymap[f]
543
556
544 def merge(self, f):
557 def merge(self, f):
545 '''Mark a file merged.'''
558 '''Mark a file merged.'''
546 if self._pl[1] == nullid:
559 if self._pl[1] == nullid:
547 return self.normallookup(f)
560 return self.normallookup(f)
548 return self.otherparent(f)
561 return self.otherparent(f)
549
562
550 def drop(self, f):
563 def drop(self, f):
551 '''Drop a file from the dirstate'''
564 '''Drop a file from the dirstate'''
552 if f in self._map:
565 if f in self._map:
553 self._dirty = True
566 self._dirty = True
554 self._droppath(f)
567 self._droppath(f)
555 del self._map[f]
568 del self._map[f]
556
569
557 def _discoverpath(self, path, normed, ignoremissing, exists, storemap):
570 def _discoverpath(self, path, normed, ignoremissing, exists, storemap):
558 if exists is None:
571 if exists is None:
559 exists = os.path.lexists(os.path.join(self._root, path))
572 exists = os.path.lexists(os.path.join(self._root, path))
560 if not exists:
573 if not exists:
561 # Maybe a path component exists
574 # Maybe a path component exists
562 if not ignoremissing and '/' in path:
575 if not ignoremissing and '/' in path:
563 d, f = path.rsplit('/', 1)
576 d, f = path.rsplit('/', 1)
564 d = self._normalize(d, False, ignoremissing, None)
577 d = self._normalize(d, False, ignoremissing, None)
565 folded = d + "/" + f
578 folded = d + "/" + f
566 else:
579 else:
567 # No path components, preserve original case
580 # No path components, preserve original case
568 folded = path
581 folded = path
569 else:
582 else:
570 # recursively normalize leading directory components
583 # recursively normalize leading directory components
571 # against dirstate
584 # against dirstate
572 if '/' in normed:
585 if '/' in normed:
573 d, f = normed.rsplit('/', 1)
586 d, f = normed.rsplit('/', 1)
574 d = self._normalize(d, False, ignoremissing, True)
587 d = self._normalize(d, False, ignoremissing, True)
575 r = self._root + "/" + d
588 r = self._root + "/" + d
576 folded = d + "/" + util.fspath(f, r)
589 folded = d + "/" + util.fspath(f, r)
577 else:
590 else:
578 folded = util.fspath(normed, self._root)
591 folded = util.fspath(normed, self._root)
579 storemap[normed] = folded
592 storemap[normed] = folded
580
593
581 return folded
594 return folded
582
595
583 def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
596 def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
584 normed = util.normcase(path)
597 normed = util.normcase(path)
585 folded = self._filefoldmap.get(normed, None)
598 folded = self._filefoldmap.get(normed, None)
586 if folded is None:
599 if folded is None:
587 if isknown:
600 if isknown:
588 folded = path
601 folded = path
589 else:
602 else:
590 folded = self._discoverpath(path, normed, ignoremissing, exists,
603 folded = self._discoverpath(path, normed, ignoremissing, exists,
591 self._filefoldmap)
604 self._filefoldmap)
592 return folded
605 return folded
593
606
594 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
607 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
595 normed = util.normcase(path)
608 normed = util.normcase(path)
596 folded = self._filefoldmap.get(normed, None)
609 folded = self._filefoldmap.get(normed, None)
597 if folded is None:
610 if folded is None:
598 folded = self._dirfoldmap.get(normed, None)
611 folded = self._dirfoldmap.get(normed, None)
599 if folded is None:
612 if folded is None:
600 if isknown:
613 if isknown:
601 folded = path
614 folded = path
602 else:
615 else:
603 # store discovered result in dirfoldmap so that future
616 # store discovered result in dirfoldmap so that future
604 # normalizefile calls don't start matching directories
617 # normalizefile calls don't start matching directories
605 folded = self._discoverpath(path, normed, ignoremissing, exists,
618 folded = self._discoverpath(path, normed, ignoremissing, exists,
606 self._dirfoldmap)
619 self._dirfoldmap)
607 return folded
620 return folded
608
621
609 def normalize(self, path, isknown=False, ignoremissing=False):
622 def normalize(self, path, isknown=False, ignoremissing=False):
610 '''
623 '''
611 normalize the case of a pathname when on a casefolding filesystem
624 normalize the case of a pathname when on a casefolding filesystem
612
625
613 isknown specifies whether the filename came from walking the
626 isknown specifies whether the filename came from walking the
614 disk, to avoid extra filesystem access.
627 disk, to avoid extra filesystem access.
615
628
616 If ignoremissing is True, missing path are returned
629 If ignoremissing is True, missing path are returned
617 unchanged. Otherwise, we try harder to normalize possibly
630 unchanged. Otherwise, we try harder to normalize possibly
618 existing path components.
631 existing path components.
619
632
620 The normalized case is determined based on the following precedence:
633 The normalized case is determined based on the following precedence:
621
634
622 - version of name already stored in the dirstate
635 - version of name already stored in the dirstate
623 - version of name stored on disk
636 - version of name stored on disk
624 - version provided via command arguments
637 - version provided via command arguments
625 '''
638 '''
626
639
627 if self._checkcase:
640 if self._checkcase:
628 return self._normalize(path, isknown, ignoremissing)
641 return self._normalize(path, isknown, ignoremissing)
629 return path
642 return path
630
643
631 def clear(self):
644 def clear(self):
632 self._map = {}
645 self._map = {}
633 if "_dirs" in self.__dict__:
646 if "_dirs" in self.__dict__:
634 delattr(self, "_dirs")
647 delattr(self, "_dirs")
635 self._copymap = {}
648 self._copymap = {}
636 self._pl = [nullid, nullid]
649 self._pl = [nullid, nullid]
637 self._lastnormaltime = 0
650 self._lastnormaltime = 0
638 self._dirty = True
651 self._dirty = True
639
652
640 def rebuild(self, parent, allfiles, changedfiles=None):
653 def rebuild(self, parent, allfiles, changedfiles=None):
641 if changedfiles is None:
654 if changedfiles is None:
642 # Rebuild entire dirstate
655 # Rebuild entire dirstate
643 changedfiles = allfiles
656 changedfiles = allfiles
644 lastnormaltime = self._lastnormaltime
657 lastnormaltime = self._lastnormaltime
645 self.clear()
658 self.clear()
646 self._lastnormaltime = lastnormaltime
659 self._lastnormaltime = lastnormaltime
647
660
648 for f in changedfiles:
661 for f in changedfiles:
649 mode = 0o666
662 mode = 0o666
650 if f in allfiles and 'x' in allfiles.flags(f):
663 if f in allfiles and 'x' in allfiles.flags(f):
651 mode = 0o777
664 mode = 0o777
652
665
653 if f in allfiles:
666 if f in allfiles:
654 self._map[f] = dirstatetuple('n', mode, -1, 0)
667 self._map[f] = dirstatetuple('n', mode, -1, 0)
655 else:
668 else:
656 self._map.pop(f, None)
669 self._map.pop(f, None)
657
670
658 self._pl = (parent, nullid)
671 self._pl = (parent, nullid)
659 self._dirty = True
672 self._dirty = True
660
673
661 def write(self, tr=False):
674 def write(self, tr=False):
662 if not self._dirty:
675 if not self._dirty:
663 return
676 return
664
677
665 filename = self._filename
678 filename = self._filename
666 if tr is False: # not explicitly specified
679 if tr is False: # not explicitly specified
667 if (self._ui.configbool('devel', 'all-warnings')
680 if (self._ui.configbool('devel', 'all-warnings')
668 or self._ui.configbool('devel', 'check-dirstate-write')):
681 or self._ui.configbool('devel', 'check-dirstate-write')):
669 self._ui.develwarn('use dirstate.write with '
682 self._ui.develwarn('use dirstate.write with '
670 'repo.currenttransaction()')
683 'repo.currenttransaction()')
671
684
672 if self._opener.lexists(self._pendingfilename):
685 if self._opener.lexists(self._pendingfilename):
673 # if pending file already exists, in-memory changes
686 # if pending file already exists, in-memory changes
674 # should be written into it, because it has priority
687 # should be written into it, because it has priority
675 # to '.hg/dirstate' at reading under HG_PENDING mode
688 # to '.hg/dirstate' at reading under HG_PENDING mode
676 filename = self._pendingfilename
689 filename = self._pendingfilename
677 elif tr:
690 elif tr:
678 # 'dirstate.write()' is not only for writing in-memory
691 # 'dirstate.write()' is not only for writing in-memory
679 # changes out, but also for dropping ambiguous timestamp.
692 # changes out, but also for dropping ambiguous timestamp.
680 # delayed writing re-raise "ambiguous timestamp issue".
693 # delayed writing re-raise "ambiguous timestamp issue".
681 # See also the wiki page below for detail:
694 # See also the wiki page below for detail:
682 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan
695 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan
683
696
684 # emulate dropping timestamp in 'parsers.pack_dirstate'
697 # emulate dropping timestamp in 'parsers.pack_dirstate'
685 now = _getfsnow(self._opener)
698 now = _getfsnow(self._opener)
686 dmap = self._map
699 dmap = self._map
687 for f, e in dmap.iteritems():
700 for f, e in dmap.iteritems():
688 if e[0] == 'n' and e[3] == now:
701 if e[0] == 'n' and e[3] == now:
689 dmap[f] = dirstatetuple(e[0], e[1], e[2], -1)
702 dmap[f] = dirstatetuple(e[0], e[1], e[2], -1)
690
703
691 # emulate that all 'dirstate.normal' results are written out
704 # emulate that all 'dirstate.normal' results are written out
692 self._lastnormaltime = 0
705 self._lastnormaltime = 0
693
706
694 # delay writing in-memory changes out
707 # delay writing in-memory changes out
695 tr.addfilegenerator('dirstate', (self._filename,),
708 tr.addfilegenerator('dirstate', (self._filename,),
696 self._writedirstate, location='plain')
709 self._writedirstate, location='plain')
697 return
710 return
698
711
699 st = self._opener(filename, "w", atomictemp=True)
712 st = self._opener(filename, "w", atomictemp=True)
700 self._writedirstate(st)
713 self._writedirstate(st)
701
714
702 def _writedirstate(self, st):
715 def _writedirstate(self, st):
703 # use the modification time of the newly created temporary file as the
716 # use the modification time of the newly created temporary file as the
704 # filesystem's notion of 'now'
717 # filesystem's notion of 'now'
705 now = util.fstat(st).st_mtime & _rangemask
718 now = util.fstat(st).st_mtime & _rangemask
706
719
707 # enough 'delaywrite' prevents 'pack_dirstate' from dropping
720 # enough 'delaywrite' prevents 'pack_dirstate' from dropping
708 # timestamp of each entries in dirstate, because of 'now > mtime'
721 # timestamp of each entries in dirstate, because of 'now > mtime'
709 delaywrite = self._ui.configint('debug', 'dirstate.delaywrite', 0)
722 delaywrite = self._ui.configint('debug', 'dirstate.delaywrite', 0)
710 if delaywrite > 0:
723 if delaywrite > 0:
711 # do we have any files to delay for?
724 # do we have any files to delay for?
712 for f, e in self._map.iteritems():
725 for f, e in self._map.iteritems():
713 if e[0] == 'n' and e[3] == now:
726 if e[0] == 'n' and e[3] == now:
714 import time # to avoid useless import
727 import time # to avoid useless import
715 # rather than sleep n seconds, sleep until the next
728 # rather than sleep n seconds, sleep until the next
716 # multiple of n seconds
729 # multiple of n seconds
717 clock = time.time()
730 clock = time.time()
718 start = int(clock) - (int(clock) % delaywrite)
731 start = int(clock) - (int(clock) % delaywrite)
719 end = start + delaywrite
732 end = start + delaywrite
720 time.sleep(end - clock)
733 time.sleep(end - clock)
721 break
734 break
722
735
723 st.write(parsers.pack_dirstate(self._map, self._copymap, self._pl, now))
736 st.write(parsers.pack_dirstate(self._map, self._copymap, self._pl, now))
724 st.close()
737 st.close()
725 self._lastnormaltime = 0
738 self._lastnormaltime = 0
726 self._dirty = self._dirtypl = False
739 self._dirty = self._dirtypl = False
727
740
728 def _dirignore(self, f):
741 def _dirignore(self, f):
729 if f == '.':
742 if f == '.':
730 return False
743 return False
731 if self._ignore(f):
744 if self._ignore(f):
732 return True
745 return True
733 for p in util.finddirs(f):
746 for p in util.finddirs(f):
734 if self._ignore(p):
747 if self._ignore(p):
735 return True
748 return True
736 return False
749 return False
737
750
738 def _walkexplicit(self, match, subrepos):
751 def _walkexplicit(self, match, subrepos):
739 '''Get stat data about the files explicitly specified by match.
752 '''Get stat data about the files explicitly specified by match.
740
753
741 Return a triple (results, dirsfound, dirsnotfound).
754 Return a triple (results, dirsfound, dirsnotfound).
742 - results is a mapping from filename to stat result. It also contains
755 - results is a mapping from filename to stat result. It also contains
743 listings mapping subrepos and .hg to None.
756 listings mapping subrepos and .hg to None.
744 - dirsfound is a list of files found to be directories.
757 - dirsfound is a list of files found to be directories.
745 - dirsnotfound is a list of files that the dirstate thinks are
758 - dirsnotfound is a list of files that the dirstate thinks are
746 directories and that were not found.'''
759 directories and that were not found.'''
747
760
748 def badtype(mode):
761 def badtype(mode):
749 kind = _('unknown')
762 kind = _('unknown')
750 if stat.S_ISCHR(mode):
763 if stat.S_ISCHR(mode):
751 kind = _('character device')
764 kind = _('character device')
752 elif stat.S_ISBLK(mode):
765 elif stat.S_ISBLK(mode):
753 kind = _('block device')
766 kind = _('block device')
754 elif stat.S_ISFIFO(mode):
767 elif stat.S_ISFIFO(mode):
755 kind = _('fifo')
768 kind = _('fifo')
756 elif stat.S_ISSOCK(mode):
769 elif stat.S_ISSOCK(mode):
757 kind = _('socket')
770 kind = _('socket')
758 elif stat.S_ISDIR(mode):
771 elif stat.S_ISDIR(mode):
759 kind = _('directory')
772 kind = _('directory')
760 return _('unsupported file type (type is %s)') % kind
773 return _('unsupported file type (type is %s)') % kind
761
774
762 matchedir = match.explicitdir
775 matchedir = match.explicitdir
763 badfn = match.bad
776 badfn = match.bad
764 dmap = self._map
777 dmap = self._map
765 lstat = os.lstat
778 lstat = os.lstat
766 getkind = stat.S_IFMT
779 getkind = stat.S_IFMT
767 dirkind = stat.S_IFDIR
780 dirkind = stat.S_IFDIR
768 regkind = stat.S_IFREG
781 regkind = stat.S_IFREG
769 lnkkind = stat.S_IFLNK
782 lnkkind = stat.S_IFLNK
770 join = self._join
783 join = self._join
771 dirsfound = []
784 dirsfound = []
772 foundadd = dirsfound.append
785 foundadd = dirsfound.append
773 dirsnotfound = []
786 dirsnotfound = []
774 notfoundadd = dirsnotfound.append
787 notfoundadd = dirsnotfound.append
775
788
776 if not match.isexact() and self._checkcase:
789 if not match.isexact() and self._checkcase:
777 normalize = self._normalize
790 normalize = self._normalize
778 else:
791 else:
779 normalize = None
792 normalize = None
780
793
781 files = sorted(match.files())
794 files = sorted(match.files())
782 subrepos.sort()
795 subrepos.sort()
783 i, j = 0, 0
796 i, j = 0, 0
784 while i < len(files) and j < len(subrepos):
797 while i < len(files) and j < len(subrepos):
785 subpath = subrepos[j] + "/"
798 subpath = subrepos[j] + "/"
786 if files[i] < subpath:
799 if files[i] < subpath:
787 i += 1
800 i += 1
788 continue
801 continue
789 while i < len(files) and files[i].startswith(subpath):
802 while i < len(files) and files[i].startswith(subpath):
790 del files[i]
803 del files[i]
791 j += 1
804 j += 1
792
805
793 if not files or '.' in files:
806 if not files or '.' in files:
794 files = ['.']
807 files = ['.']
795 results = dict.fromkeys(subrepos)
808 results = dict.fromkeys(subrepos)
796 results['.hg'] = None
809 results['.hg'] = None
797
810
798 alldirs = None
811 alldirs = None
799 for ff in files:
812 for ff in files:
800 # constructing the foldmap is expensive, so don't do it for the
813 # constructing the foldmap is expensive, so don't do it for the
801 # common case where files is ['.']
814 # common case where files is ['.']
802 if normalize and ff != '.':
815 if normalize and ff != '.':
803 nf = normalize(ff, False, True)
816 nf = normalize(ff, False, True)
804 else:
817 else:
805 nf = ff
818 nf = ff
806 if nf in results:
819 if nf in results:
807 continue
820 continue
808
821
809 try:
822 try:
810 st = lstat(join(nf))
823 st = lstat(join(nf))
811 kind = getkind(st.st_mode)
824 kind = getkind(st.st_mode)
812 if kind == dirkind:
825 if kind == dirkind:
813 if nf in dmap:
826 if nf in dmap:
814 # file replaced by dir on disk but still in dirstate
827 # file replaced by dir on disk but still in dirstate
815 results[nf] = None
828 results[nf] = None
816 if matchedir:
829 if matchedir:
817 matchedir(nf)
830 matchedir(nf)
818 foundadd((nf, ff))
831 foundadd((nf, ff))
819 elif kind == regkind or kind == lnkkind:
832 elif kind == regkind or kind == lnkkind:
820 results[nf] = st
833 results[nf] = st
821 else:
834 else:
822 badfn(ff, badtype(kind))
835 badfn(ff, badtype(kind))
823 if nf in dmap:
836 if nf in dmap:
824 results[nf] = None
837 results[nf] = None
825 except OSError as inst: # nf not found on disk - it is dirstate only
838 except OSError as inst: # nf not found on disk - it is dirstate only
826 if nf in dmap: # does it exactly match a missing file?
839 if nf in dmap: # does it exactly match a missing file?
827 results[nf] = None
840 results[nf] = None
828 else: # does it match a missing directory?
841 else: # does it match a missing directory?
829 if alldirs is None:
842 if alldirs is None:
830 alldirs = util.dirs(dmap)
843 alldirs = util.dirs(dmap)
831 if nf in alldirs:
844 if nf in alldirs:
832 if matchedir:
845 if matchedir:
833 matchedir(nf)
846 matchedir(nf)
834 notfoundadd(nf)
847 notfoundadd(nf)
835 else:
848 else:
836 badfn(ff, inst.strerror)
849 badfn(ff, inst.strerror)
837
850
838 # Case insensitive filesystems cannot rely on lstat() failing to detect
851 # Case insensitive filesystems cannot rely on lstat() failing to detect
839 # a case-only rename. Prune the stat object for any file that does not
852 # a case-only rename. Prune the stat object for any file that does not
840 # match the case in the filesystem, if there are multiple files that
853 # match the case in the filesystem, if there are multiple files that
841 # normalize to the same path.
854 # normalize to the same path.
842 if match.isexact() and self._checkcase:
855 if match.isexact() and self._checkcase:
843 normed = {}
856 normed = {}
844
857
845 for f, st in results.iteritems():
858 for f, st in results.iteritems():
846 if st is None:
859 if st is None:
847 continue
860 continue
848
861
849 nc = util.normcase(f)
862 nc = util.normcase(f)
850 paths = normed.get(nc)
863 paths = normed.get(nc)
851
864
852 if paths is None:
865 if paths is None:
853 paths = set()
866 paths = set()
854 normed[nc] = paths
867 normed[nc] = paths
855
868
856 paths.add(f)
869 paths.add(f)
857
870
858 for norm, paths in normed.iteritems():
871 for norm, paths in normed.iteritems():
859 if len(paths) > 1:
872 if len(paths) > 1:
860 for path in paths:
873 for path in paths:
861 folded = self._discoverpath(path, norm, True, None,
874 folded = self._discoverpath(path, norm, True, None,
862 self._dirfoldmap)
875 self._dirfoldmap)
863 if path != folded:
876 if path != folded:
864 results[path] = None
877 results[path] = None
865
878
866 return results, dirsfound, dirsnotfound
879 return results, dirsfound, dirsnotfound
867
880
868 def walk(self, match, subrepos, unknown, ignored, full=True):
881 def walk(self, match, subrepos, unknown, ignored, full=True):
869 '''
882 '''
870 Walk recursively through the directory tree, finding all files
883 Walk recursively through the directory tree, finding all files
871 matched by match.
884 matched by match.
872
885
873 If full is False, maybe skip some known-clean files.
886 If full is False, maybe skip some known-clean files.
874
887
875 Return a dict mapping filename to stat-like object (either
888 Return a dict mapping filename to stat-like object (either
876 mercurial.osutil.stat instance or return value of os.stat()).
889 mercurial.osutil.stat instance or return value of os.stat()).
877
890
878 '''
891 '''
879 # full is a flag that extensions that hook into walk can use -- this
892 # full is a flag that extensions that hook into walk can use -- this
880 # implementation doesn't use it at all. This satisfies the contract
893 # implementation doesn't use it at all. This satisfies the contract
881 # because we only guarantee a "maybe".
894 # because we only guarantee a "maybe".
882
895
883 if ignored:
896 if ignored:
884 ignore = util.never
897 ignore = util.never
885 dirignore = util.never
898 dirignore = util.never
886 elif unknown:
899 elif unknown:
887 ignore = self._ignore
900 ignore = self._ignore
888 dirignore = self._dirignore
901 dirignore = self._dirignore
889 else:
902 else:
890 # if not unknown and not ignored, drop dir recursion and step 2
903 # if not unknown and not ignored, drop dir recursion and step 2
891 ignore = util.always
904 ignore = util.always
892 dirignore = util.always
905 dirignore = util.always
893
906
894 matchfn = match.matchfn
907 matchfn = match.matchfn
895 matchalways = match.always()
908 matchalways = match.always()
896 matchtdir = match.traversedir
909 matchtdir = match.traversedir
897 dmap = self._map
910 dmap = self._map
898 listdir = osutil.listdir
911 listdir = osutil.listdir
899 lstat = os.lstat
912 lstat = os.lstat
900 dirkind = stat.S_IFDIR
913 dirkind = stat.S_IFDIR
901 regkind = stat.S_IFREG
914 regkind = stat.S_IFREG
902 lnkkind = stat.S_IFLNK
915 lnkkind = stat.S_IFLNK
903 join = self._join
916 join = self._join
904
917
905 exact = skipstep3 = False
918 exact = skipstep3 = False
906 if match.isexact(): # match.exact
919 if match.isexact(): # match.exact
907 exact = True
920 exact = True
908 dirignore = util.always # skip step 2
921 dirignore = util.always # skip step 2
909 elif match.prefix(): # match.match, no patterns
922 elif match.prefix(): # match.match, no patterns
910 skipstep3 = True
923 skipstep3 = True
911
924
912 if not exact and self._checkcase:
925 if not exact and self._checkcase:
913 normalize = self._normalize
926 normalize = self._normalize
914 normalizefile = self._normalizefile
927 normalizefile = self._normalizefile
915 skipstep3 = False
928 skipstep3 = False
916 else:
929 else:
917 normalize = self._normalize
930 normalize = self._normalize
918 normalizefile = None
931 normalizefile = None
919
932
920 # step 1: find all explicit files
933 # step 1: find all explicit files
921 results, work, dirsnotfound = self._walkexplicit(match, subrepos)
934 results, work, dirsnotfound = self._walkexplicit(match, subrepos)
922
935
923 skipstep3 = skipstep3 and not (work or dirsnotfound)
936 skipstep3 = skipstep3 and not (work or dirsnotfound)
924 work = [d for d in work if not dirignore(d[0])]
937 work = [d for d in work if not dirignore(d[0])]
925
938
926 # step 2: visit subdirectories
939 # step 2: visit subdirectories
927 def traverse(work, alreadynormed):
940 def traverse(work, alreadynormed):
928 wadd = work.append
941 wadd = work.append
929 while work:
942 while work:
930 nd = work.pop()
943 nd = work.pop()
931 skip = None
944 skip = None
932 if nd == '.':
945 if nd == '.':
933 nd = ''
946 nd = ''
934 else:
947 else:
935 skip = '.hg'
948 skip = '.hg'
936 try:
949 try:
937 entries = listdir(join(nd), stat=True, skip=skip)
950 entries = listdir(join(nd), stat=True, skip=skip)
938 except OSError as inst:
951 except OSError as inst:
939 if inst.errno in (errno.EACCES, errno.ENOENT):
952 if inst.errno in (errno.EACCES, errno.ENOENT):
940 match.bad(self.pathto(nd), inst.strerror)
953 match.bad(self.pathto(nd), inst.strerror)
941 continue
954 continue
942 raise
955 raise
943 for f, kind, st in entries:
956 for f, kind, st in entries:
944 if normalizefile:
957 if normalizefile:
945 # even though f might be a directory, we're only
958 # even though f might be a directory, we're only
946 # interested in comparing it to files currently in the
959 # interested in comparing it to files currently in the
947 # dmap -- therefore normalizefile is enough
960 # dmap -- therefore normalizefile is enough
948 nf = normalizefile(nd and (nd + "/" + f) or f, True,
961 nf = normalizefile(nd and (nd + "/" + f) or f, True,
949 True)
962 True)
950 else:
963 else:
951 nf = nd and (nd + "/" + f) or f
964 nf = nd and (nd + "/" + f) or f
952 if nf not in results:
965 if nf not in results:
953 if kind == dirkind:
966 if kind == dirkind:
954 if not ignore(nf):
967 if not ignore(nf):
955 if matchtdir:
968 if matchtdir:
956 matchtdir(nf)
969 matchtdir(nf)
957 wadd(nf)
970 wadd(nf)
958 if nf in dmap and (matchalways or matchfn(nf)):
971 if nf in dmap and (matchalways or matchfn(nf)):
959 results[nf] = None
972 results[nf] = None
960 elif kind == regkind or kind == lnkkind:
973 elif kind == regkind or kind == lnkkind:
961 if nf in dmap:
974 if nf in dmap:
962 if matchalways or matchfn(nf):
975 if matchalways or matchfn(nf):
963 results[nf] = st
976 results[nf] = st
964 elif ((matchalways or matchfn(nf))
977 elif ((matchalways or matchfn(nf))
965 and not ignore(nf)):
978 and not ignore(nf)):
966 # unknown file -- normalize if necessary
979 # unknown file -- normalize if necessary
967 if not alreadynormed:
980 if not alreadynormed:
968 nf = normalize(nf, False, True)
981 nf = normalize(nf, False, True)
969 results[nf] = st
982 results[nf] = st
970 elif nf in dmap and (matchalways or matchfn(nf)):
983 elif nf in dmap and (matchalways or matchfn(nf)):
971 results[nf] = None
984 results[nf] = None
972
985
973 for nd, d in work:
986 for nd, d in work:
974 # alreadynormed means that processwork doesn't have to do any
987 # alreadynormed means that processwork doesn't have to do any
975 # expensive directory normalization
988 # expensive directory normalization
976 alreadynormed = not normalize or nd == d
989 alreadynormed = not normalize or nd == d
977 traverse([d], alreadynormed)
990 traverse([d], alreadynormed)
978
991
979 for s in subrepos:
992 for s in subrepos:
980 del results[s]
993 del results[s]
981 del results['.hg']
994 del results['.hg']
982
995
983 # step 3: visit remaining files from dmap
996 # step 3: visit remaining files from dmap
984 if not skipstep3 and not exact:
997 if not skipstep3 and not exact:
985 # If a dmap file is not in results yet, it was either
998 # If a dmap file is not in results yet, it was either
986 # a) not matching matchfn b) ignored, c) missing, or d) under a
999 # a) not matching matchfn b) ignored, c) missing, or d) under a
987 # symlink directory.
1000 # symlink directory.
988 if not results and matchalways:
1001 if not results and matchalways:
989 visit = dmap.keys()
1002 visit = dmap.keys()
990 else:
1003 else:
991 visit = [f for f in dmap if f not in results and matchfn(f)]
1004 visit = [f for f in dmap if f not in results and matchfn(f)]
992 visit.sort()
1005 visit.sort()
993
1006
994 if unknown:
1007 if unknown:
995 # unknown == True means we walked all dirs under the roots
1008 # unknown == True means we walked all dirs under the roots
996 # that wasn't ignored, and everything that matched was stat'ed
1009 # that wasn't ignored, and everything that matched was stat'ed
997 # and is already in results.
1010 # and is already in results.
998 # The rest must thus be ignored or under a symlink.
1011 # The rest must thus be ignored or under a symlink.
999 audit_path = pathutil.pathauditor(self._root)
1012 audit_path = pathutil.pathauditor(self._root)
1000
1013
1001 for nf in iter(visit):
1014 for nf in iter(visit):
1002 # If a stat for the same file was already added with a
1015 # If a stat for the same file was already added with a
1003 # different case, don't add one for this, since that would
1016 # different case, don't add one for this, since that would
1004 # make it appear as if the file exists under both names
1017 # make it appear as if the file exists under both names
1005 # on disk.
1018 # on disk.
1006 if (normalizefile and
1019 if (normalizefile and
1007 normalizefile(nf, True, True) in results):
1020 normalizefile(nf, True, True) in results):
1008 results[nf] = None
1021 results[nf] = None
1009 # Report ignored items in the dmap as long as they are not
1022 # Report ignored items in the dmap as long as they are not
1010 # under a symlink directory.
1023 # under a symlink directory.
1011 elif audit_path.check(nf):
1024 elif audit_path.check(nf):
1012 try:
1025 try:
1013 results[nf] = lstat(join(nf))
1026 results[nf] = lstat(join(nf))
1014 # file was just ignored, no links, and exists
1027 # file was just ignored, no links, and exists
1015 except OSError:
1028 except OSError:
1016 # file doesn't exist
1029 # file doesn't exist
1017 results[nf] = None
1030 results[nf] = None
1018 else:
1031 else:
1019 # It's either missing or under a symlink directory
1032 # It's either missing or under a symlink directory
1020 # which we in this case report as missing
1033 # which we in this case report as missing
1021 results[nf] = None
1034 results[nf] = None
1022 else:
1035 else:
1023 # We may not have walked the full directory tree above,
1036 # We may not have walked the full directory tree above,
1024 # so stat and check everything we missed.
1037 # so stat and check everything we missed.
1025 nf = iter(visit).next
1038 nf = iter(visit).next
1026 for st in util.statfiles([join(i) for i in visit]):
1039 for st in util.statfiles([join(i) for i in visit]):
1027 results[nf()] = st
1040 results[nf()] = st
1028 return results
1041 return results
1029
1042
1030 def status(self, match, subrepos, ignored, clean, unknown):
1043 def status(self, match, subrepos, ignored, clean, unknown):
1031 '''Determine the status of the working copy relative to the
1044 '''Determine the status of the working copy relative to the
1032 dirstate and return a pair of (unsure, status), where status is of type
1045 dirstate and return a pair of (unsure, status), where status is of type
1033 scmutil.status and:
1046 scmutil.status and:
1034
1047
1035 unsure:
1048 unsure:
1036 files that might have been modified since the dirstate was
1049 files that might have been modified since the dirstate was
1037 written, but need to be read to be sure (size is the same
1050 written, but need to be read to be sure (size is the same
1038 but mtime differs)
1051 but mtime differs)
1039 status.modified:
1052 status.modified:
1040 files that have definitely been modified since the dirstate
1053 files that have definitely been modified since the dirstate
1041 was written (different size or mode)
1054 was written (different size or mode)
1042 status.clean:
1055 status.clean:
1043 files that have definitely not been modified since the
1056 files that have definitely not been modified since the
1044 dirstate was written
1057 dirstate was written
1045 '''
1058 '''
1046 listignored, listclean, listunknown = ignored, clean, unknown
1059 listignored, listclean, listunknown = ignored, clean, unknown
1047 lookup, modified, added, unknown, ignored = [], [], [], [], []
1060 lookup, modified, added, unknown, ignored = [], [], [], [], []
1048 removed, deleted, clean = [], [], []
1061 removed, deleted, clean = [], [], []
1049
1062
1050 dmap = self._map
1063 dmap = self._map
1051 ladd = lookup.append # aka "unsure"
1064 ladd = lookup.append # aka "unsure"
1052 madd = modified.append
1065 madd = modified.append
1053 aadd = added.append
1066 aadd = added.append
1054 uadd = unknown.append
1067 uadd = unknown.append
1055 iadd = ignored.append
1068 iadd = ignored.append
1056 radd = removed.append
1069 radd = removed.append
1057 dadd = deleted.append
1070 dadd = deleted.append
1058 cadd = clean.append
1071 cadd = clean.append
1059 mexact = match.exact
1072 mexact = match.exact
1060 dirignore = self._dirignore
1073 dirignore = self._dirignore
1061 checkexec = self._checkexec
1074 checkexec = self._checkexec
1062 copymap = self._copymap
1075 copymap = self._copymap
1063 lastnormaltime = self._lastnormaltime
1076 lastnormaltime = self._lastnormaltime
1064
1077
1065 # We need to do full walks when either
1078 # We need to do full walks when either
1066 # - we're listing all clean files, or
1079 # - we're listing all clean files, or
1067 # - match.traversedir does something, because match.traversedir should
1080 # - match.traversedir does something, because match.traversedir should
1068 # be called for every dir in the working dir
1081 # be called for every dir in the working dir
1069 full = listclean or match.traversedir is not None
1082 full = listclean or match.traversedir is not None
1070 for fn, st in self.walk(match, subrepos, listunknown, listignored,
1083 for fn, st in self.walk(match, subrepos, listunknown, listignored,
1071 full=full).iteritems():
1084 full=full).iteritems():
1072 if fn not in dmap:
1085 if fn not in dmap:
1073 if (listignored or mexact(fn)) and dirignore(fn):
1086 if (listignored or mexact(fn)) and dirignore(fn):
1074 if listignored:
1087 if listignored:
1075 iadd(fn)
1088 iadd(fn)
1076 else:
1089 else:
1077 uadd(fn)
1090 uadd(fn)
1078 continue
1091 continue
1079
1092
1080 # This is equivalent to 'state, mode, size, time = dmap[fn]' but not
1093 # This is equivalent to 'state, mode, size, time = dmap[fn]' but not
1081 # written like that for performance reasons. dmap[fn] is not a
1094 # written like that for performance reasons. dmap[fn] is not a
1082 # Python tuple in compiled builds. The CPython UNPACK_SEQUENCE
1095 # Python tuple in compiled builds. The CPython UNPACK_SEQUENCE
1083 # opcode has fast paths when the value to be unpacked is a tuple or
1096 # opcode has fast paths when the value to be unpacked is a tuple or
1084 # a list, but falls back to creating a full-fledged iterator in
1097 # a list, but falls back to creating a full-fledged iterator in
1085 # general. That is much slower than simply accessing and storing the
1098 # general. That is much slower than simply accessing and storing the
1086 # tuple members one by one.
1099 # tuple members one by one.
1087 t = dmap[fn]
1100 t = dmap[fn]
1088 state = t[0]
1101 state = t[0]
1089 mode = t[1]
1102 mode = t[1]
1090 size = t[2]
1103 size = t[2]
1091 time = t[3]
1104 time = t[3]
1092
1105
1093 if not st and state in "nma":
1106 if not st and state in "nma":
1094 dadd(fn)
1107 dadd(fn)
1095 elif state == 'n':
1108 elif state == 'n':
1096 if (size >= 0 and
1109 if (size >= 0 and
1097 ((size != st.st_size and size != st.st_size & _rangemask)
1110 ((size != st.st_size and size != st.st_size & _rangemask)
1098 or ((mode ^ st.st_mode) & 0o100 and checkexec))
1111 or ((mode ^ st.st_mode) & 0o100 and checkexec))
1099 or size == -2 # other parent
1112 or size == -2 # other parent
1100 or fn in copymap):
1113 or fn in copymap):
1101 madd(fn)
1114 madd(fn)
1102 elif time != st.st_mtime and time != st.st_mtime & _rangemask:
1115 elif time != st.st_mtime and time != st.st_mtime & _rangemask:
1103 ladd(fn)
1116 ladd(fn)
1104 elif st.st_mtime == lastnormaltime:
1117 elif st.st_mtime == lastnormaltime:
1105 # fn may have just been marked as normal and it may have
1118 # fn may have just been marked as normal and it may have
1106 # changed in the same second without changing its size.
1119 # changed in the same second without changing its size.
1107 # This can happen if we quickly do multiple commits.
1120 # This can happen if we quickly do multiple commits.
1108 # Force lookup, so we don't miss such a racy file change.
1121 # Force lookup, so we don't miss such a racy file change.
1109 ladd(fn)
1122 ladd(fn)
1110 elif listclean:
1123 elif listclean:
1111 cadd(fn)
1124 cadd(fn)
1112 elif state == 'm':
1125 elif state == 'm':
1113 madd(fn)
1126 madd(fn)
1114 elif state == 'a':
1127 elif state == 'a':
1115 aadd(fn)
1128 aadd(fn)
1116 elif state == 'r':
1129 elif state == 'r':
1117 radd(fn)
1130 radd(fn)
1118
1131
1119 return (lookup, scmutil.status(modified, added, removed, deleted,
1132 return (lookup, scmutil.status(modified, added, removed, deleted,
1120 unknown, ignored, clean))
1133 unknown, ignored, clean))
1121
1134
1122 def matches(self, match):
1135 def matches(self, match):
1123 '''
1136 '''
1124 return files in the dirstate (in whatever state) filtered by match
1137 return files in the dirstate (in whatever state) filtered by match
1125 '''
1138 '''
1126 dmap = self._map
1139 dmap = self._map
1127 if match.always():
1140 if match.always():
1128 return dmap.keys()
1141 return dmap.keys()
1129 files = match.files()
1142 files = match.files()
1130 if match.isexact():
1143 if match.isexact():
1131 # fast path -- filter the other way around, since typically files is
1144 # fast path -- filter the other way around, since typically files is
1132 # much smaller than dmap
1145 # much smaller than dmap
1133 return [f for f in files if f in dmap]
1146 return [f for f in files if f in dmap]
1134 if match.prefix() and all(fn in dmap for fn in files):
1147 if match.prefix() and all(fn in dmap for fn in files):
1135 # fast path -- all the values are known to be files, so just return
1148 # fast path -- all the values are known to be files, so just return
1136 # that
1149 # that
1137 return list(files)
1150 return list(files)
1138 return [f for f in dmap if match(f)]
1151 return [f for f in dmap if match(f)]
1139
1152
1140 def _actualfilename(self, tr):
1153 def _actualfilename(self, tr):
1141 if tr:
1154 if tr:
1142 return self._pendingfilename
1155 return self._pendingfilename
1143 else:
1156 else:
1144 return self._filename
1157 return self._filename
1145
1158
1146 def _savebackup(self, tr, suffix):
1159 def _savebackup(self, tr, suffix):
1147 '''Save current dirstate into backup file with suffix'''
1160 '''Save current dirstate into backup file with suffix'''
1148 filename = self._actualfilename(tr)
1161 filename = self._actualfilename(tr)
1149
1162
1150 # use '_writedirstate' instead of 'write' to write changes certainly,
1163 # use '_writedirstate' instead of 'write' to write changes certainly,
1151 # because the latter omits writing out if transaction is running.
1164 # because the latter omits writing out if transaction is running.
1152 # output file will be used to create backup of dirstate at this point.
1165 # output file will be used to create backup of dirstate at this point.
1153 self._writedirstate(self._opener(filename, "w", atomictemp=True))
1166 self._writedirstate(self._opener(filename, "w", atomictemp=True))
1154
1167
1155 if tr:
1168 if tr:
1156 # ensure that subsequent tr.writepending returns True for
1169 # ensure that subsequent tr.writepending returns True for
1157 # changes written out above, even if dirstate is never
1170 # changes written out above, even if dirstate is never
1158 # changed after this
1171 # changed after this
1159 tr.addfilegenerator('dirstate', (self._filename,),
1172 tr.addfilegenerator('dirstate', (self._filename,),
1160 self._writedirstate, location='plain')
1173 self._writedirstate, location='plain')
1161
1174
1162 # ensure that pending file written above is unlinked at
1175 # ensure that pending file written above is unlinked at
1163 # failure, even if tr.writepending isn't invoked until the
1176 # failure, even if tr.writepending isn't invoked until the
1164 # end of this transaction
1177 # end of this transaction
1165 tr.registertmp(filename, location='plain')
1178 tr.registertmp(filename, location='plain')
1166
1179
1167 self._opener.write(filename + suffix, self._opener.tryread(filename))
1180 self._opener.write(filename + suffix, self._opener.tryread(filename))
1168
1181
1169 def _restorebackup(self, tr, suffix):
1182 def _restorebackup(self, tr, suffix):
1170 '''Restore dirstate by backup file with suffix'''
1183 '''Restore dirstate by backup file with suffix'''
1171 # this "invalidate()" prevents "wlock.release()" from writing
1184 # this "invalidate()" prevents "wlock.release()" from writing
1172 # changes of dirstate out after restoring from backup file
1185 # changes of dirstate out after restoring from backup file
1173 self.invalidate()
1186 self.invalidate()
1174 filename = self._actualfilename(tr)
1187 filename = self._actualfilename(tr)
1175 self._opener.rename(filename + suffix, filename)
1188 self._opener.rename(filename + suffix, filename)
1176
1189
1177 def _clearbackup(self, tr, suffix):
1190 def _clearbackup(self, tr, suffix):
1178 '''Clear backup file with suffix'''
1191 '''Clear backup file with suffix'''
1179 filename = self._actualfilename(tr)
1192 filename = self._actualfilename(tr)
1180 self._opener.unlink(filename + suffix)
1193 self._opener.unlink(filename + suffix)
@@ -1,197 +1,196
1 #require test-repo
1 #require test-repo
2
2
3 $ cd "$TESTDIR"/..
3 $ cd "$TESTDIR"/..
4
4
5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
5 $ hg files 'set:(**.py)' | sed 's|\\|/|g' | xargs python contrib/check-py3-compat.py
6 contrib/casesmash.py not using absolute_import
6 contrib/casesmash.py not using absolute_import
7 contrib/check-code.py not using absolute_import
7 contrib/check-code.py not using absolute_import
8 contrib/check-code.py requires print_function
8 contrib/check-code.py requires print_function
9 contrib/check-config.py not using absolute_import
9 contrib/check-config.py not using absolute_import
10 contrib/check-config.py requires print_function
10 contrib/check-config.py requires print_function
11 contrib/debugcmdserver.py not using absolute_import
11 contrib/debugcmdserver.py not using absolute_import
12 contrib/debugcmdserver.py requires print_function
12 contrib/debugcmdserver.py requires print_function
13 contrib/debugshell.py not using absolute_import
13 contrib/debugshell.py not using absolute_import
14 contrib/fixpax.py not using absolute_import
14 contrib/fixpax.py not using absolute_import
15 contrib/fixpax.py requires print_function
15 contrib/fixpax.py requires print_function
16 contrib/hgclient.py not using absolute_import
16 contrib/hgclient.py not using absolute_import
17 contrib/hgclient.py requires print_function
17 contrib/hgclient.py requires print_function
18 contrib/hgfixes/fix_bytes.py not using absolute_import
18 contrib/hgfixes/fix_bytes.py not using absolute_import
19 contrib/hgfixes/fix_bytesmod.py not using absolute_import
19 contrib/hgfixes/fix_bytesmod.py not using absolute_import
20 contrib/hgfixes/fix_leftover_imports.py not using absolute_import
20 contrib/hgfixes/fix_leftover_imports.py not using absolute_import
21 contrib/import-checker.py not using absolute_import
21 contrib/import-checker.py not using absolute_import
22 contrib/import-checker.py requires print_function
22 contrib/import-checker.py requires print_function
23 contrib/memory.py not using absolute_import
23 contrib/memory.py not using absolute_import
24 contrib/perf.py not using absolute_import
24 contrib/perf.py not using absolute_import
25 contrib/python-hook-examples.py not using absolute_import
25 contrib/python-hook-examples.py not using absolute_import
26 contrib/revsetbenchmarks.py not using absolute_import
26 contrib/revsetbenchmarks.py not using absolute_import
27 contrib/revsetbenchmarks.py requires print_function
27 contrib/revsetbenchmarks.py requires print_function
28 contrib/showstack.py not using absolute_import
28 contrib/showstack.py not using absolute_import
29 contrib/synthrepo.py not using absolute_import
29 contrib/synthrepo.py not using absolute_import
30 contrib/win32/hgwebdir_wsgi.py not using absolute_import
30 contrib/win32/hgwebdir_wsgi.py not using absolute_import
31 doc/check-seclevel.py not using absolute_import
31 doc/check-seclevel.py not using absolute_import
32 doc/gendoc.py not using absolute_import
32 doc/gendoc.py not using absolute_import
33 doc/hgmanpage.py not using absolute_import
33 doc/hgmanpage.py not using absolute_import
34 hgext/__init__.py not using absolute_import
34 hgext/__init__.py not using absolute_import
35 hgext/acl.py not using absolute_import
35 hgext/acl.py not using absolute_import
36 hgext/blackbox.py not using absolute_import
36 hgext/blackbox.py not using absolute_import
37 hgext/bugzilla.py not using absolute_import
37 hgext/bugzilla.py not using absolute_import
38 hgext/censor.py not using absolute_import
38 hgext/censor.py not using absolute_import
39 hgext/children.py not using absolute_import
39 hgext/children.py not using absolute_import
40 hgext/churn.py not using absolute_import
40 hgext/churn.py not using absolute_import
41 hgext/clonebundles.py not using absolute_import
41 hgext/clonebundles.py not using absolute_import
42 hgext/color.py not using absolute_import
42 hgext/color.py not using absolute_import
43 hgext/convert/__init__.py not using absolute_import
43 hgext/convert/__init__.py not using absolute_import
44 hgext/convert/bzr.py not using absolute_import
44 hgext/convert/bzr.py not using absolute_import
45 hgext/convert/common.py not using absolute_import
45 hgext/convert/common.py not using absolute_import
46 hgext/convert/convcmd.py not using absolute_import
46 hgext/convert/convcmd.py not using absolute_import
47 hgext/convert/cvs.py not using absolute_import
47 hgext/convert/cvs.py not using absolute_import
48 hgext/convert/cvsps.py not using absolute_import
48 hgext/convert/cvsps.py not using absolute_import
49 hgext/convert/darcs.py not using absolute_import
49 hgext/convert/darcs.py not using absolute_import
50 hgext/convert/filemap.py not using absolute_import
50 hgext/convert/filemap.py not using absolute_import
51 hgext/convert/git.py not using absolute_import
51 hgext/convert/git.py not using absolute_import
52 hgext/convert/gnuarch.py not using absolute_import
52 hgext/convert/gnuarch.py not using absolute_import
53 hgext/convert/hg.py not using absolute_import
53 hgext/convert/hg.py not using absolute_import
54 hgext/convert/monotone.py not using absolute_import
54 hgext/convert/monotone.py not using absolute_import
55 hgext/convert/p4.py not using absolute_import
55 hgext/convert/p4.py not using absolute_import
56 hgext/convert/subversion.py not using absolute_import
56 hgext/convert/subversion.py not using absolute_import
57 hgext/convert/transport.py not using absolute_import
57 hgext/convert/transport.py not using absolute_import
58 hgext/eol.py not using absolute_import
58 hgext/eol.py not using absolute_import
59 hgext/extdiff.py not using absolute_import
59 hgext/extdiff.py not using absolute_import
60 hgext/factotum.py not using absolute_import
60 hgext/factotum.py not using absolute_import
61 hgext/fetch.py not using absolute_import
61 hgext/fetch.py not using absolute_import
62 hgext/gpg.py not using absolute_import
62 hgext/gpg.py not using absolute_import
63 hgext/graphlog.py not using absolute_import
63 hgext/graphlog.py not using absolute_import
64 hgext/hgcia.py not using absolute_import
64 hgext/hgcia.py not using absolute_import
65 hgext/hgk.py not using absolute_import
65 hgext/hgk.py not using absolute_import
66 hgext/highlight/__init__.py not using absolute_import
66 hgext/highlight/__init__.py not using absolute_import
67 hgext/highlight/highlight.py not using absolute_import
67 hgext/highlight/highlight.py not using absolute_import
68 hgext/histedit.py not using absolute_import
68 hgext/histedit.py not using absolute_import
69 hgext/keyword.py not using absolute_import
69 hgext/keyword.py not using absolute_import
70 hgext/largefiles/__init__.py not using absolute_import
70 hgext/largefiles/__init__.py not using absolute_import
71 hgext/largefiles/basestore.py not using absolute_import
71 hgext/largefiles/basestore.py not using absolute_import
72 hgext/largefiles/lfcommands.py not using absolute_import
72 hgext/largefiles/lfcommands.py not using absolute_import
73 hgext/largefiles/lfutil.py not using absolute_import
73 hgext/largefiles/lfutil.py not using absolute_import
74 hgext/largefiles/localstore.py not using absolute_import
74 hgext/largefiles/localstore.py not using absolute_import
75 hgext/largefiles/overrides.py not using absolute_import
75 hgext/largefiles/overrides.py not using absolute_import
76 hgext/largefiles/proto.py not using absolute_import
76 hgext/largefiles/proto.py not using absolute_import
77 hgext/largefiles/remotestore.py not using absolute_import
77 hgext/largefiles/remotestore.py not using absolute_import
78 hgext/largefiles/reposetup.py not using absolute_import
78 hgext/largefiles/reposetup.py not using absolute_import
79 hgext/largefiles/uisetup.py not using absolute_import
79 hgext/largefiles/uisetup.py not using absolute_import
80 hgext/largefiles/wirestore.py not using absolute_import
80 hgext/largefiles/wirestore.py not using absolute_import
81 hgext/mq.py not using absolute_import
81 hgext/mq.py not using absolute_import
82 hgext/notify.py not using absolute_import
82 hgext/notify.py not using absolute_import
83 hgext/pager.py not using absolute_import
83 hgext/pager.py not using absolute_import
84 hgext/patchbomb.py not using absolute_import
84 hgext/patchbomb.py not using absolute_import
85 hgext/purge.py not using absolute_import
85 hgext/purge.py not using absolute_import
86 hgext/rebase.py not using absolute_import
86 hgext/rebase.py not using absolute_import
87 hgext/record.py not using absolute_import
87 hgext/record.py not using absolute_import
88 hgext/relink.py not using absolute_import
88 hgext/relink.py not using absolute_import
89 hgext/schemes.py not using absolute_import
89 hgext/schemes.py not using absolute_import
90 hgext/share.py not using absolute_import
90 hgext/share.py not using absolute_import
91 hgext/shelve.py not using absolute_import
91 hgext/shelve.py not using absolute_import
92 hgext/strip.py not using absolute_import
92 hgext/strip.py not using absolute_import
93 hgext/transplant.py not using absolute_import
93 hgext/transplant.py not using absolute_import
94 hgext/win32mbcs.py not using absolute_import
94 hgext/win32mbcs.py not using absolute_import
95 hgext/win32text.py not using absolute_import
95 hgext/win32text.py not using absolute_import
96 hgext/zeroconf/Zeroconf.py not using absolute_import
96 hgext/zeroconf/Zeroconf.py not using absolute_import
97 hgext/zeroconf/Zeroconf.py requires print_function
97 hgext/zeroconf/Zeroconf.py requires print_function
98 hgext/zeroconf/__init__.py not using absolute_import
98 hgext/zeroconf/__init__.py not using absolute_import
99 i18n/check-translation.py not using absolute_import
99 i18n/check-translation.py not using absolute_import
100 i18n/polib.py not using absolute_import
100 i18n/polib.py not using absolute_import
101 mercurial/byterange.py not using absolute_import
101 mercurial/byterange.py not using absolute_import
102 mercurial/cmdutil.py not using absolute_import
102 mercurial/cmdutil.py not using absolute_import
103 mercurial/commands.py not using absolute_import
103 mercurial/commands.py not using absolute_import
104 mercurial/context.py not using absolute_import
104 mercurial/context.py not using absolute_import
105 mercurial/dirstate.py not using absolute_import
106 mercurial/dispatch.py requires print_function
105 mercurial/dispatch.py requires print_function
107 mercurial/exchange.py not using absolute_import
106 mercurial/exchange.py not using absolute_import
108 mercurial/httpclient/__init__.py not using absolute_import
107 mercurial/httpclient/__init__.py not using absolute_import
109 mercurial/httpclient/_readers.py not using absolute_import
108 mercurial/httpclient/_readers.py not using absolute_import
110 mercurial/httpclient/socketutil.py not using absolute_import
109 mercurial/httpclient/socketutil.py not using absolute_import
111 mercurial/httpconnection.py not using absolute_import
110 mercurial/httpconnection.py not using absolute_import
112 mercurial/keepalive.py not using absolute_import
111 mercurial/keepalive.py not using absolute_import
113 mercurial/keepalive.py requires print_function
112 mercurial/keepalive.py requires print_function
114 mercurial/localrepo.py not using absolute_import
113 mercurial/localrepo.py not using absolute_import
115 mercurial/lsprof.py requires print_function
114 mercurial/lsprof.py requires print_function
116 mercurial/lsprofcalltree.py not using absolute_import
115 mercurial/lsprofcalltree.py not using absolute_import
117 mercurial/lsprofcalltree.py requires print_function
116 mercurial/lsprofcalltree.py requires print_function
118 mercurial/mail.py requires print_function
117 mercurial/mail.py requires print_function
119 setup.py not using absolute_import
118 setup.py not using absolute_import
120 tests/filterpyflakes.py requires print_function
119 tests/filterpyflakes.py requires print_function
121 tests/generate-working-copy-states.py requires print_function
120 tests/generate-working-copy-states.py requires print_function
122 tests/get-with-headers.py requires print_function
121 tests/get-with-headers.py requires print_function
123 tests/heredoctest.py requires print_function
122 tests/heredoctest.py requires print_function
124 tests/hypothesishelpers.py not using absolute_import
123 tests/hypothesishelpers.py not using absolute_import
125 tests/hypothesishelpers.py requires print_function
124 tests/hypothesishelpers.py requires print_function
126 tests/killdaemons.py not using absolute_import
125 tests/killdaemons.py not using absolute_import
127 tests/md5sum.py not using absolute_import
126 tests/md5sum.py not using absolute_import
128 tests/mockblackbox.py not using absolute_import
127 tests/mockblackbox.py not using absolute_import
129 tests/printenv.py not using absolute_import
128 tests/printenv.py not using absolute_import
130 tests/readlink.py not using absolute_import
129 tests/readlink.py not using absolute_import
131 tests/readlink.py requires print_function
130 tests/readlink.py requires print_function
132 tests/revlog-formatv0.py not using absolute_import
131 tests/revlog-formatv0.py not using absolute_import
133 tests/run-tests.py not using absolute_import
132 tests/run-tests.py not using absolute_import
134 tests/seq.py not using absolute_import
133 tests/seq.py not using absolute_import
135 tests/seq.py requires print_function
134 tests/seq.py requires print_function
136 tests/silenttestrunner.py not using absolute_import
135 tests/silenttestrunner.py not using absolute_import
137 tests/silenttestrunner.py requires print_function
136 tests/silenttestrunner.py requires print_function
138 tests/sitecustomize.py not using absolute_import
137 tests/sitecustomize.py not using absolute_import
139 tests/svn-safe-append.py not using absolute_import
138 tests/svn-safe-append.py not using absolute_import
140 tests/svnxml.py not using absolute_import
139 tests/svnxml.py not using absolute_import
141 tests/test-ancestor.py requires print_function
140 tests/test-ancestor.py requires print_function
142 tests/test-atomictempfile.py not using absolute_import
141 tests/test-atomictempfile.py not using absolute_import
143 tests/test-batching.py not using absolute_import
142 tests/test-batching.py not using absolute_import
144 tests/test-batching.py requires print_function
143 tests/test-batching.py requires print_function
145 tests/test-bdiff.py not using absolute_import
144 tests/test-bdiff.py not using absolute_import
146 tests/test-bdiff.py requires print_function
145 tests/test-bdiff.py requires print_function
147 tests/test-context.py not using absolute_import
146 tests/test-context.py not using absolute_import
148 tests/test-context.py requires print_function
147 tests/test-context.py requires print_function
149 tests/test-demandimport.py not using absolute_import
148 tests/test-demandimport.py not using absolute_import
150 tests/test-demandimport.py requires print_function
149 tests/test-demandimport.py requires print_function
151 tests/test-dispatch.py not using absolute_import
150 tests/test-dispatch.py not using absolute_import
152 tests/test-dispatch.py requires print_function
151 tests/test-dispatch.py requires print_function
153 tests/test-doctest.py not using absolute_import
152 tests/test-doctest.py not using absolute_import
154 tests/test-duplicateoptions.py not using absolute_import
153 tests/test-duplicateoptions.py not using absolute_import
155 tests/test-duplicateoptions.py requires print_function
154 tests/test-duplicateoptions.py requires print_function
156 tests/test-filecache.py not using absolute_import
155 tests/test-filecache.py not using absolute_import
157 tests/test-filecache.py requires print_function
156 tests/test-filecache.py requires print_function
158 tests/test-filelog.py not using absolute_import
157 tests/test-filelog.py not using absolute_import
159 tests/test-filelog.py requires print_function
158 tests/test-filelog.py requires print_function
160 tests/test-hg-parseurl.py not using absolute_import
159 tests/test-hg-parseurl.py not using absolute_import
161 tests/test-hg-parseurl.py requires print_function
160 tests/test-hg-parseurl.py requires print_function
162 tests/test-hgweb-auth.py not using absolute_import
161 tests/test-hgweb-auth.py not using absolute_import
163 tests/test-hgweb-auth.py requires print_function
162 tests/test-hgweb-auth.py requires print_function
164 tests/test-hgwebdir-paths.py not using absolute_import
163 tests/test-hgwebdir-paths.py not using absolute_import
165 tests/test-hybridencode.py not using absolute_import
164 tests/test-hybridencode.py not using absolute_import
166 tests/test-hybridencode.py requires print_function
165 tests/test-hybridencode.py requires print_function
167 tests/test-lrucachedict.py not using absolute_import
166 tests/test-lrucachedict.py not using absolute_import
168 tests/test-lrucachedict.py requires print_function
167 tests/test-lrucachedict.py requires print_function
169 tests/test-manifest.py not using absolute_import
168 tests/test-manifest.py not using absolute_import
170 tests/test-minirst.py not using absolute_import
169 tests/test-minirst.py not using absolute_import
171 tests/test-minirst.py requires print_function
170 tests/test-minirst.py requires print_function
172 tests/test-parseindex2.py not using absolute_import
171 tests/test-parseindex2.py not using absolute_import
173 tests/test-parseindex2.py requires print_function
172 tests/test-parseindex2.py requires print_function
174 tests/test-pathencode.py not using absolute_import
173 tests/test-pathencode.py not using absolute_import
175 tests/test-pathencode.py requires print_function
174 tests/test-pathencode.py requires print_function
176 tests/test-propertycache.py not using absolute_import
175 tests/test-propertycache.py not using absolute_import
177 tests/test-propertycache.py requires print_function
176 tests/test-propertycache.py requires print_function
178 tests/test-revlog-ancestry.py not using absolute_import
177 tests/test-revlog-ancestry.py not using absolute_import
179 tests/test-revlog-ancestry.py requires print_function
178 tests/test-revlog-ancestry.py requires print_function
180 tests/test-run-tests.py not using absolute_import
179 tests/test-run-tests.py not using absolute_import
181 tests/test-simplemerge.py not using absolute_import
180 tests/test-simplemerge.py not using absolute_import
182 tests/test-status-inprocess.py not using absolute_import
181 tests/test-status-inprocess.py not using absolute_import
183 tests/test-status-inprocess.py requires print_function
182 tests/test-status-inprocess.py requires print_function
184 tests/test-symlink-os-yes-fs-no.py not using absolute_import
183 tests/test-symlink-os-yes-fs-no.py not using absolute_import
185 tests/test-trusted.py not using absolute_import
184 tests/test-trusted.py not using absolute_import
186 tests/test-trusted.py requires print_function
185 tests/test-trusted.py requires print_function
187 tests/test-ui-color.py not using absolute_import
186 tests/test-ui-color.py not using absolute_import
188 tests/test-ui-color.py requires print_function
187 tests/test-ui-color.py requires print_function
189 tests/test-ui-config.py not using absolute_import
188 tests/test-ui-config.py not using absolute_import
190 tests/test-ui-config.py requires print_function
189 tests/test-ui-config.py requires print_function
191 tests/test-ui-verbosity.py not using absolute_import
190 tests/test-ui-verbosity.py not using absolute_import
192 tests/test-ui-verbosity.py requires print_function
191 tests/test-ui-verbosity.py requires print_function
193 tests/test-url.py not using absolute_import
192 tests/test-url.py not using absolute_import
194 tests/test-url.py requires print_function
193 tests/test-url.py requires print_function
195 tests/test-walkrepo.py requires print_function
194 tests/test-walkrepo.py requires print_function
196 tests/test-wireproto.py requires print_function
195 tests/test-wireproto.py requires print_function
197 tests/tinyproxy.py requires print_function
196 tests/tinyproxy.py requires print_function
General Comments 0
You need to be logged in to leave comments. Login now