##// END OF EJS Templates
dirstate: prevent useless util.fspath() invocation for '.'...
FUJIWARA Katsunori -
r15668:8e020155 stable
parent child Browse files
Show More
@@ -1,725 +1,726 b''
1 1 # dirstate.py - working directory tracking for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import nullid
9 9 from i18n import _
10 10 import scmutil, util, ignore, osutil, parsers, encoding
11 11 import struct, os, stat, errno
12 12 import cStringIO
13 13
14 14 _format = ">cllll"
15 15 propertycache = util.propertycache
16 16
17 17 def _finddirs(path):
18 18 pos = path.rfind('/')
19 19 while pos != -1:
20 20 yield path[:pos]
21 21 pos = path.rfind('/', 0, pos)
22 22
23 23 def _incdirs(dirs, path):
24 24 for base in _finddirs(path):
25 25 if base in dirs:
26 26 dirs[base] += 1
27 27 return
28 28 dirs[base] = 1
29 29
30 30 def _decdirs(dirs, path):
31 31 for base in _finddirs(path):
32 32 if dirs[base] > 1:
33 33 dirs[base] -= 1
34 34 return
35 35 del dirs[base]
36 36
37 37 class dirstate(object):
38 38
39 39 def __init__(self, opener, ui, root, validate):
40 40 '''Create a new dirstate object.
41 41
42 42 opener is an open()-like callable that can be used to open the
43 43 dirstate file; root is the root of the directory tracked by
44 44 the dirstate.
45 45 '''
46 46 self._opener = opener
47 47 self._validate = validate
48 48 self._root = root
49 49 self._rootdir = os.path.join(root, '')
50 50 self._dirty = False
51 51 self._dirtypl = False
52 52 self._lastnormaltime = None
53 53 self._ui = ui
54 54
55 55 @propertycache
56 56 def _map(self):
57 57 '''Return the dirstate contents as a map from filename to
58 58 (state, mode, size, time).'''
59 59 self._read()
60 60 return self._map
61 61
62 62 @propertycache
63 63 def _copymap(self):
64 64 self._read()
65 65 return self._copymap
66 66
67 67 @propertycache
68 68 def _foldmap(self):
69 69 f = {}
70 70 for name in self._map:
71 71 f[util.normcase(name)] = name
72 f['.'] = '.' # prevents useless util.fspath() invocation
72 73 return f
73 74
74 75 @propertycache
75 76 def _branch(self):
76 77 try:
77 78 return self._opener.read("branch").strip() or "default"
78 79 except IOError:
79 80 return "default"
80 81
81 82 @propertycache
82 83 def _pl(self):
83 84 try:
84 85 fp = self._opener("dirstate")
85 86 st = fp.read(40)
86 87 fp.close()
87 88 l = len(st)
88 89 if l == 40:
89 90 return st[:20], st[20:40]
90 91 elif l > 0 and l < 40:
91 92 raise util.Abort(_('working directory state appears damaged!'))
92 93 except IOError, err:
93 94 if err.errno != errno.ENOENT:
94 95 raise
95 96 return [nullid, nullid]
96 97
97 98 @propertycache
98 99 def _dirs(self):
99 100 dirs = {}
100 101 for f, s in self._map.iteritems():
101 102 if s[0] != 'r':
102 103 _incdirs(dirs, f)
103 104 return dirs
104 105
105 106 @propertycache
106 107 def _ignore(self):
107 108 files = [self._join('.hgignore')]
108 109 for name, path in self._ui.configitems("ui"):
109 110 if name == 'ignore' or name.startswith('ignore.'):
110 111 files.append(util.expandpath(path))
111 112 return ignore.ignore(self._root, files, self._ui.warn)
112 113
113 114 @propertycache
114 115 def _slash(self):
115 116 return self._ui.configbool('ui', 'slash') and os.sep != '/'
116 117
117 118 @propertycache
118 119 def _checklink(self):
119 120 return util.checklink(self._root)
120 121
121 122 @propertycache
122 123 def _checkexec(self):
123 124 return util.checkexec(self._root)
124 125
125 126 @propertycache
126 127 def _checkcase(self):
127 128 return not util.checkcase(self._join('.hg'))
128 129
129 130 def _join(self, f):
130 131 # much faster than os.path.join()
131 132 # it's safe because f is always a relative path
132 133 return self._rootdir + f
133 134
134 135 def flagfunc(self, buildfallback):
135 136 if self._checklink and self._checkexec:
136 137 def f(x):
137 138 p = self._join(x)
138 139 if os.path.islink(p):
139 140 return 'l'
140 141 if util.isexec(p):
141 142 return 'x'
142 143 return ''
143 144 return f
144 145
145 146 fallback = buildfallback()
146 147 if self._checklink:
147 148 def f(x):
148 149 if os.path.islink(self._join(x)):
149 150 return 'l'
150 151 if 'x' in fallback(x):
151 152 return 'x'
152 153 return ''
153 154 return f
154 155 if self._checkexec:
155 156 def f(x):
156 157 if 'l' in fallback(x):
157 158 return 'l'
158 159 if util.isexec(self._join(x)):
159 160 return 'x'
160 161 return ''
161 162 return f
162 163 else:
163 164 return fallback
164 165
165 166 def getcwd(self):
166 167 cwd = os.getcwd()
167 168 if cwd == self._root:
168 169 return ''
169 170 # self._root ends with a path separator if self._root is '/' or 'C:\'
170 171 rootsep = self._root
171 172 if not util.endswithsep(rootsep):
172 173 rootsep += os.sep
173 174 if cwd.startswith(rootsep):
174 175 return cwd[len(rootsep):]
175 176 else:
176 177 # we're outside the repo. return an absolute path.
177 178 return cwd
178 179
179 180 def pathto(self, f, cwd=None):
180 181 if cwd is None:
181 182 cwd = self.getcwd()
182 183 path = util.pathto(self._root, cwd, f)
183 184 if self._slash:
184 185 return util.normpath(path)
185 186 return path
186 187
187 188 def __getitem__(self, key):
188 189 '''Return the current state of key (a filename) in the dirstate.
189 190
190 191 States are:
191 192 n normal
192 193 m needs merging
193 194 r marked for removal
194 195 a marked for addition
195 196 ? not tracked
196 197 '''
197 198 return self._map.get(key, ("?",))[0]
198 199
199 200 def __contains__(self, key):
200 201 return key in self._map
201 202
202 203 def __iter__(self):
203 204 for x in sorted(self._map):
204 205 yield x
205 206
206 207 def parents(self):
207 208 return [self._validate(p) for p in self._pl]
208 209
209 210 def p1(self):
210 211 return self._validate(self._pl[0])
211 212
212 213 def p2(self):
213 214 return self._validate(self._pl[1])
214 215
215 216 def branch(self):
216 217 return encoding.tolocal(self._branch)
217 218
218 219 def setparents(self, p1, p2=nullid):
219 220 self._dirty = self._dirtypl = True
220 221 self._pl = p1, p2
221 222
222 223 def setbranch(self, branch):
223 224 if branch in ['tip', '.', 'null']:
224 225 raise util.Abort(_('the name \'%s\' is reserved') % branch)
225 226 self._branch = encoding.fromlocal(branch)
226 227 self._opener.write("branch", self._branch + '\n')
227 228
228 229 def _read(self):
229 230 self._map = {}
230 231 self._copymap = {}
231 232 try:
232 233 st = self._opener.read("dirstate")
233 234 except IOError, err:
234 235 if err.errno != errno.ENOENT:
235 236 raise
236 237 return
237 238 if not st:
238 239 return
239 240
240 241 p = parsers.parse_dirstate(self._map, self._copymap, st)
241 242 if not self._dirtypl:
242 243 self._pl = p
243 244
244 245 def invalidate(self):
245 246 for a in ("_map", "_copymap", "_foldmap", "_branch", "_pl", "_dirs",
246 247 "_ignore"):
247 248 if a in self.__dict__:
248 249 delattr(self, a)
249 250 self._lastnormaltime = None
250 251 self._dirty = False
251 252
252 253 def copy(self, source, dest):
253 254 """Mark dest as a copy of source. Unmark dest if source is None."""
254 255 if source == dest:
255 256 return
256 257 self._dirty = True
257 258 if source is not None:
258 259 self._copymap[dest] = source
259 260 elif dest in self._copymap:
260 261 del self._copymap[dest]
261 262
262 263 def copied(self, file):
263 264 return self._copymap.get(file, None)
264 265
265 266 def copies(self):
266 267 return self._copymap
267 268
268 269 def _droppath(self, f):
269 270 if self[f] not in "?r" and "_dirs" in self.__dict__:
270 271 _decdirs(self._dirs, f)
271 272
272 273 def _addpath(self, f, check=False):
273 274 oldstate = self[f]
274 275 if check or oldstate == "r":
275 276 scmutil.checkfilename(f)
276 277 if f in self._dirs:
277 278 raise util.Abort(_('directory %r already in dirstate') % f)
278 279 # shadows
279 280 for d in _finddirs(f):
280 281 if d in self._dirs:
281 282 break
282 283 if d in self._map and self[d] != 'r':
283 284 raise util.Abort(
284 285 _('file %r in dirstate clashes with %r') % (d, f))
285 286 if oldstate in "?r" and "_dirs" in self.__dict__:
286 287 _incdirs(self._dirs, f)
287 288
288 289 def normal(self, f):
289 290 '''Mark a file normal and clean.'''
290 291 self._dirty = True
291 292 self._addpath(f)
292 293 s = os.lstat(self._join(f))
293 294 mtime = int(s.st_mtime)
294 295 self._map[f] = ('n', s.st_mode, s.st_size, mtime)
295 296 if f in self._copymap:
296 297 del self._copymap[f]
297 298 if mtime > self._lastnormaltime:
298 299 # Remember the most recent modification timeslot for status(),
299 300 # to make sure we won't miss future size-preserving file content
300 301 # modifications that happen within the same timeslot.
301 302 self._lastnormaltime = mtime
302 303
303 304 def normallookup(self, f):
304 305 '''Mark a file normal, but possibly dirty.'''
305 306 if self._pl[1] != nullid and f in self._map:
306 307 # if there is a merge going on and the file was either
307 308 # in state 'm' (-1) or coming from other parent (-2) before
308 309 # being removed, restore that state.
309 310 entry = self._map[f]
310 311 if entry[0] == 'r' and entry[2] in (-1, -2):
311 312 source = self._copymap.get(f)
312 313 if entry[2] == -1:
313 314 self.merge(f)
314 315 elif entry[2] == -2:
315 316 self.otherparent(f)
316 317 if source:
317 318 self.copy(source, f)
318 319 return
319 320 if entry[0] == 'm' or entry[0] == 'n' and entry[2] == -2:
320 321 return
321 322 self._dirty = True
322 323 self._addpath(f)
323 324 self._map[f] = ('n', 0, -1, -1)
324 325 if f in self._copymap:
325 326 del self._copymap[f]
326 327
327 328 def otherparent(self, f):
328 329 '''Mark as coming from the other parent, always dirty.'''
329 330 if self._pl[1] == nullid:
330 331 raise util.Abort(_("setting %r to other parent "
331 332 "only allowed in merges") % f)
332 333 self._dirty = True
333 334 self._addpath(f)
334 335 self._map[f] = ('n', 0, -2, -1)
335 336 if f in self._copymap:
336 337 del self._copymap[f]
337 338
338 339 def add(self, f):
339 340 '''Mark a file added.'''
340 341 self._dirty = True
341 342 self._addpath(f, True)
342 343 self._map[f] = ('a', 0, -1, -1)
343 344 if f in self._copymap:
344 345 del self._copymap[f]
345 346
346 347 def remove(self, f):
347 348 '''Mark a file removed.'''
348 349 self._dirty = True
349 350 self._droppath(f)
350 351 size = 0
351 352 if self._pl[1] != nullid and f in self._map:
352 353 # backup the previous state
353 354 entry = self._map[f]
354 355 if entry[0] == 'm': # merge
355 356 size = -1
356 357 elif entry[0] == 'n' and entry[2] == -2: # other parent
357 358 size = -2
358 359 self._map[f] = ('r', 0, size, 0)
359 360 if size == 0 and f in self._copymap:
360 361 del self._copymap[f]
361 362
362 363 def merge(self, f):
363 364 '''Mark a file merged.'''
364 365 self._dirty = True
365 366 s = os.lstat(self._join(f))
366 367 self._addpath(f)
367 368 self._map[f] = ('m', s.st_mode, s.st_size, int(s.st_mtime))
368 369 if f in self._copymap:
369 370 del self._copymap[f]
370 371
371 372 def drop(self, f):
372 373 '''Drop a file from the dirstate'''
373 374 if f in self._map:
374 375 self._dirty = True
375 376 self._droppath(f)
376 377 del self._map[f]
377 378
378 379 def _normalize(self, path, isknown):
379 380 normed = util.normcase(path)
380 381 folded = self._foldmap.get(normed, None)
381 382 if folded is None:
382 383 if isknown or not os.path.lexists(os.path.join(self._root, path)):
383 384 folded = path
384 385 else:
385 386 folded = self._foldmap.setdefault(normed,
386 387 util.fspath(path, self._root))
387 388 return folded
388 389
389 390 def normalize(self, path, isknown=False):
390 391 '''
391 392 normalize the case of a pathname when on a casefolding filesystem
392 393
393 394 isknown specifies whether the filename came from walking the
394 395 disk, to avoid extra filesystem access
395 396
396 397 The normalized case is determined based on the following precedence:
397 398
398 399 - version of name already stored in the dirstate
399 400 - version of name stored on disk
400 401 - version provided via command arguments
401 402 '''
402 403
403 404 if self._checkcase:
404 405 return self._normalize(path, isknown)
405 406 return path
406 407
407 408 def clear(self):
408 409 self._map = {}
409 410 if "_dirs" in self.__dict__:
410 411 delattr(self, "_dirs")
411 412 self._copymap = {}
412 413 self._pl = [nullid, nullid]
413 414 self._lastnormaltime = None
414 415 self._dirty = True
415 416
416 417 def rebuild(self, parent, files):
417 418 self.clear()
418 419 for f in files:
419 420 if 'x' in files.flags(f):
420 421 self._map[f] = ('n', 0777, -1, 0)
421 422 else:
422 423 self._map[f] = ('n', 0666, -1, 0)
423 424 self._pl = (parent, nullid)
424 425 self._dirty = True
425 426
426 427 def write(self):
427 428 if not self._dirty:
428 429 return
429 430 st = self._opener("dirstate", "w", atomictemp=True)
430 431
431 432 # use the modification time of the newly created temporary file as the
432 433 # filesystem's notion of 'now'
433 434 now = int(util.fstat(st).st_mtime)
434 435
435 436 cs = cStringIO.StringIO()
436 437 copymap = self._copymap
437 438 pack = struct.pack
438 439 write = cs.write
439 440 write("".join(self._pl))
440 441 for f, e in self._map.iteritems():
441 442 if e[0] == 'n' and e[3] == now:
442 443 # The file was last modified "simultaneously" with the current
443 444 # write to dirstate (i.e. within the same second for file-
444 445 # systems with a granularity of 1 sec). This commonly happens
445 446 # for at least a couple of files on 'update'.
446 447 # The user could change the file without changing its size
447 448 # within the same second. Invalidate the file's stat data in
448 449 # dirstate, forcing future 'status' calls to compare the
449 450 # contents of the file. This prevents mistakenly treating such
450 451 # files as clean.
451 452 e = (e[0], 0, -1, -1) # mark entry as 'unset'
452 453 self._map[f] = e
453 454
454 455 if f in copymap:
455 456 f = "%s\0%s" % (f, copymap[f])
456 457 e = pack(_format, e[0], e[1], e[2], e[3], len(f))
457 458 write(e)
458 459 write(f)
459 460 st.write(cs.getvalue())
460 461 st.close()
461 462 self._lastnormaltime = None
462 463 self._dirty = self._dirtypl = False
463 464
464 465 def _dirignore(self, f):
465 466 if f == '.':
466 467 return False
467 468 if self._ignore(f):
468 469 return True
469 470 for p in _finddirs(f):
470 471 if self._ignore(p):
471 472 return True
472 473 return False
473 474
474 475 def walk(self, match, subrepos, unknown, ignored):
475 476 '''
476 477 Walk recursively through the directory tree, finding all files
477 478 matched by match.
478 479
479 480 Return a dict mapping filename to stat-like object (either
480 481 mercurial.osutil.stat instance or return value of os.stat()).
481 482 '''
482 483
483 484 def fwarn(f, msg):
484 485 self._ui.warn('%s: %s\n' % (self.pathto(f), msg))
485 486 return False
486 487
487 488 def badtype(mode):
488 489 kind = _('unknown')
489 490 if stat.S_ISCHR(mode):
490 491 kind = _('character device')
491 492 elif stat.S_ISBLK(mode):
492 493 kind = _('block device')
493 494 elif stat.S_ISFIFO(mode):
494 495 kind = _('fifo')
495 496 elif stat.S_ISSOCK(mode):
496 497 kind = _('socket')
497 498 elif stat.S_ISDIR(mode):
498 499 kind = _('directory')
499 500 return _('unsupported file type (type is %s)') % kind
500 501
501 502 ignore = self._ignore
502 503 dirignore = self._dirignore
503 504 if ignored:
504 505 ignore = util.never
505 506 dirignore = util.never
506 507 elif not unknown:
507 508 # if unknown and ignored are False, skip step 2
508 509 ignore = util.always
509 510 dirignore = util.always
510 511
511 512 matchfn = match.matchfn
512 513 badfn = match.bad
513 514 dmap = self._map
514 515 normpath = util.normpath
515 516 listdir = osutil.listdir
516 517 lstat = os.lstat
517 518 getkind = stat.S_IFMT
518 519 dirkind = stat.S_IFDIR
519 520 regkind = stat.S_IFREG
520 521 lnkkind = stat.S_IFLNK
521 522 join = self._join
522 523 work = []
523 524 wadd = work.append
524 525
525 526 exact = skipstep3 = False
526 527 if matchfn == match.exact: # match.exact
527 528 exact = True
528 529 dirignore = util.always # skip step 2
529 530 elif match.files() and not match.anypats(): # match.match, no patterns
530 531 skipstep3 = True
531 532
532 533 if self._checkcase:
533 534 normalize = self._normalize
534 535 skipstep3 = False
535 536 else:
536 537 normalize = lambda x, y: x
537 538
538 539 files = sorted(match.files())
539 540 subrepos.sort()
540 541 i, j = 0, 0
541 542 while i < len(files) and j < len(subrepos):
542 543 subpath = subrepos[j] + "/"
543 544 if files[i] < subpath:
544 545 i += 1
545 546 continue
546 547 while i < len(files) and files[i].startswith(subpath):
547 548 del files[i]
548 549 j += 1
549 550
550 551 if not files or '.' in files:
551 552 files = ['']
552 553 results = dict.fromkeys(subrepos)
553 554 results['.hg'] = None
554 555
555 556 # step 1: find all explicit files
556 557 for ff in files:
557 558 nf = normalize(normpath(ff), False)
558 559 if nf in results:
559 560 continue
560 561
561 562 try:
562 563 st = lstat(join(nf))
563 564 kind = getkind(st.st_mode)
564 565 if kind == dirkind:
565 566 skipstep3 = False
566 567 if nf in dmap:
567 568 #file deleted on disk but still in dirstate
568 569 results[nf] = None
569 570 match.dir(nf)
570 571 if not dirignore(nf):
571 572 wadd(nf)
572 573 elif kind == regkind or kind == lnkkind:
573 574 results[nf] = st
574 575 else:
575 576 badfn(ff, badtype(kind))
576 577 if nf in dmap:
577 578 results[nf] = None
578 579 except OSError, inst:
579 580 if nf in dmap: # does it exactly match a file?
580 581 results[nf] = None
581 582 else: # does it match a directory?
582 583 prefix = nf + "/"
583 584 for fn in dmap:
584 585 if fn.startswith(prefix):
585 586 match.dir(nf)
586 587 skipstep3 = False
587 588 break
588 589 else:
589 590 badfn(ff, inst.strerror)
590 591
591 592 # step 2: visit subdirectories
592 593 while work:
593 594 nd = work.pop()
594 595 skip = None
595 596 if nd == '.':
596 597 nd = ''
597 598 else:
598 599 skip = '.hg'
599 600 try:
600 601 entries = listdir(join(nd), stat=True, skip=skip)
601 602 except OSError, inst:
602 603 if inst.errno == errno.EACCES:
603 604 fwarn(nd, inst.strerror)
604 605 continue
605 606 raise
606 607 for f, kind, st in entries:
607 608 nf = normalize(nd and (nd + "/" + f) or f, True)
608 609 if nf not in results:
609 610 if kind == dirkind:
610 611 if not ignore(nf):
611 612 match.dir(nf)
612 613 wadd(nf)
613 614 if nf in dmap and matchfn(nf):
614 615 results[nf] = None
615 616 elif kind == regkind or kind == lnkkind:
616 617 if nf in dmap:
617 618 if matchfn(nf):
618 619 results[nf] = st
619 620 elif matchfn(nf) and not ignore(nf):
620 621 results[nf] = st
621 622 elif nf in dmap and matchfn(nf):
622 623 results[nf] = None
623 624
624 625 # step 3: report unseen items in the dmap hash
625 626 if not skipstep3 and not exact:
626 627 visit = sorted([f for f in dmap if f not in results and matchfn(f)])
627 628 for nf, st in zip(visit, util.statfiles([join(i) for i in visit])):
628 629 if not st is None and not getkind(st.st_mode) in (regkind, lnkkind):
629 630 st = None
630 631 results[nf] = st
631 632 for s in subrepos:
632 633 del results[s]
633 634 del results['.hg']
634 635 return results
635 636
636 637 def status(self, match, subrepos, ignored, clean, unknown):
637 638 '''Determine the status of the working copy relative to the
638 639 dirstate and return a tuple of lists (unsure, modified, added,
639 640 removed, deleted, unknown, ignored, clean), where:
640 641
641 642 unsure:
642 643 files that might have been modified since the dirstate was
643 644 written, but need to be read to be sure (size is the same
644 645 but mtime differs)
645 646 modified:
646 647 files that have definitely been modified since the dirstate
647 648 was written (different size or mode)
648 649 added:
649 650 files that have been explicitly added with hg add
650 651 removed:
651 652 files that have been explicitly removed with hg remove
652 653 deleted:
653 654 files that have been deleted through other means ("missing")
654 655 unknown:
655 656 files not in the dirstate that are not ignored
656 657 ignored:
657 658 files not in the dirstate that are ignored
658 659 (by _dirignore())
659 660 clean:
660 661 files that have definitely not been modified since the
661 662 dirstate was written
662 663 '''
663 664 listignored, listclean, listunknown = ignored, clean, unknown
664 665 lookup, modified, added, unknown, ignored = [], [], [], [], []
665 666 removed, deleted, clean = [], [], []
666 667
667 668 dmap = self._map
668 669 ladd = lookup.append # aka "unsure"
669 670 madd = modified.append
670 671 aadd = added.append
671 672 uadd = unknown.append
672 673 iadd = ignored.append
673 674 radd = removed.append
674 675 dadd = deleted.append
675 676 cadd = clean.append
676 677
677 678 lnkkind = stat.S_IFLNK
678 679
679 680 for fn, st in self.walk(match, subrepos, listunknown,
680 681 listignored).iteritems():
681 682 if fn not in dmap:
682 683 if (listignored or match.exact(fn)) and self._dirignore(fn):
683 684 if listignored:
684 685 iadd(fn)
685 686 elif listunknown:
686 687 uadd(fn)
687 688 continue
688 689
689 690 state, mode, size, time = dmap[fn]
690 691
691 692 if not st and state in "nma":
692 693 dadd(fn)
693 694 elif state == 'n':
694 695 # The "mode & lnkkind != lnkkind or self._checklink"
695 696 # lines are an expansion of "islink => checklink"
696 697 # where islink means "is this a link?" and checklink
697 698 # means "can we check links?".
698 699 mtime = int(st.st_mtime)
699 700 if (size >= 0 and
700 701 (size != st.st_size
701 702 or ((mode ^ st.st_mode) & 0100 and self._checkexec))
702 703 and (mode & lnkkind != lnkkind or self._checklink)
703 704 or size == -2 # other parent
704 705 or fn in self._copymap):
705 706 madd(fn)
706 707 elif (mtime != time
707 708 and (mode & lnkkind != lnkkind or self._checklink)):
708 709 ladd(fn)
709 710 elif mtime == self._lastnormaltime:
710 711 # fn may have been changed in the same timeslot without
711 712 # changing its size. This can happen if we quickly do
712 713 # multiple commits in a single transaction.
713 714 # Force lookup, so we don't miss such a racy file change.
714 715 ladd(fn)
715 716 elif listclean:
716 717 cadd(fn)
717 718 elif state == 'm':
718 719 madd(fn)
719 720 elif state == 'a':
720 721 aadd(fn)
721 722 elif state == 'r':
722 723 radd(fn)
723 724
724 725 return (lookup, modified, added, removed, deleted, unknown, ignored,
725 726 clean)
General Comments 0
You need to be logged in to leave comments. Login now