##// END OF EJS Templates
dirstatemap: move `set_untracked` out of the common methods...
Raphaël Gomès -
r50000:953b08a2 default
parent child Browse files
Show More
@@ -1,744 +1,745 b''
1 1 # dirstatemap.py
2 2 #
3 3 # This software may be used and distributed according to the terms of the
4 4 # GNU General Public License version 2 or any later version.
5 5
6 6
7 7 import errno
8 8
9 9 from .i18n import _
10 10
11 11 from . import (
12 12 error,
13 13 pathutil,
14 14 policy,
15 15 txnutil,
16 16 util,
17 17 )
18 18
19 19 from .dirstateutils import (
20 20 docket as docketmod,
21 21 v2,
22 22 )
23 23
24 24 parsers = policy.importmod('parsers')
25 25 rustmod = policy.importrust('dirstate')
26 26
27 27 propertycache = util.propertycache
28 28
29 29 if rustmod is None:
30 30 DirstateItem = parsers.DirstateItem
31 31 else:
32 32 DirstateItem = rustmod.DirstateItem
33 33
34 34 rangemask = 0x7FFFFFFF
35 35
36 36
37 37 class _dirstatemapcommon:
38 38 """
39 39 Methods that are identical for both implementations of the dirstatemap
40 40 class, with and without Rust extensions enabled.
41 41 """
42 42
43 43 # please pytype
44 44
45 45 _map = None
46 46 copymap = None
47 47
48 48 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
49 49 self._use_dirstate_v2 = use_dirstate_v2
50 50 self._nodeconstants = nodeconstants
51 51 self._ui = ui
52 52 self._opener = opener
53 53 self._root = root
54 54 self._filename = b'dirstate'
55 55 self._nodelen = 20 # Also update Rust code when changing this!
56 56 self._parents = None
57 57 self._dirtyparents = False
58 58 self._docket = None
59 59
60 60 # for consistent view between _pl() and _read() invocations
61 61 self._pendingmode = None
62 62
63 63 def preload(self):
64 64 """Loads the underlying data, if it's not already loaded"""
65 65 self._map
66 66
67 67 def get(self, key, default=None):
68 68 return self._map.get(key, default)
69 69
70 70 def __len__(self):
71 71 return len(self._map)
72 72
73 73 def __iter__(self):
74 74 return iter(self._map)
75 75
76 76 def __contains__(self, key):
77 77 return key in self._map
78 78
79 79 def __getitem__(self, item):
80 80 return self._map[item]
81 81
82 82 ### sub-class utility method
83 83 #
84 84 # Use to allow for generic implementation of some method while still coping
85 85 # with minor difference between implementation.
86 86
87 87 def _dirs_incr(self, filename, old_entry=None):
88 88 """increment the dirstate counter if applicable
89 89
90 90 This might be a no-op for some subclasses who deal with directory
91 91 tracking in a different way.
92 92 """
93 93
94 94 def _dirs_decr(self, filename, old_entry=None, remove_variant=False):
95 95 """decrement the dirstate counter if applicable
96 96
97 97 This might be a no-op for some subclasses who deal with directory
98 98 tracking in a different way.
99 99 """
100 100
101 101 def _refresh_entry(self, f, entry):
102 102 """record updated state of an entry"""
103 103
104 104 def _drop_entry(self, f):
105 105 """remove any entry for file f
106 106
107 107 This should also drop associated copy information
108 108
109 109 The fact we actually need to drop it is the responsability of the caller"""
110 110
111 ### method to manipulate the entries
112
113 def set_untracked(self, f):
114 """Mark a file as no longer tracked in the dirstate map"""
115 entry = self.get(f)
116 if entry is None:
117 return False
118 else:
119 self._dirs_decr(f, old_entry=entry, remove_variant=not entry.added)
120 if not entry.p2_info:
121 self.copymap.pop(f, None)
122 entry.set_untracked()
123 self._refresh_entry(f, entry)
124 return True
125
126 111 ### disk interaction
127 112
128 113 def _opendirstatefile(self):
129 114 fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
130 115 if self._pendingmode is not None and self._pendingmode != mode:
131 116 fp.close()
132 117 raise error.Abort(
133 118 _(b'working directory state may be changed parallelly')
134 119 )
135 120 self._pendingmode = mode
136 121 return fp
137 122
138 123 def _readdirstatefile(self, size=-1):
139 124 try:
140 125 with self._opendirstatefile() as fp:
141 126 return fp.read(size)
142 127 except IOError as err:
143 128 if err.errno != errno.ENOENT:
144 129 raise
145 130 # File doesn't exist, so the current state is empty
146 131 return b''
147 132
148 133 @property
149 134 def docket(self):
150 135 if not self._docket:
151 136 if not self._use_dirstate_v2:
152 137 raise error.ProgrammingError(
153 138 b'dirstate only has a docket in v2 format'
154 139 )
155 140 self._docket = docketmod.DirstateDocket.parse(
156 141 self._readdirstatefile(), self._nodeconstants
157 142 )
158 143 return self._docket
159 144
160 145 def write_v2_no_append(self, tr, st, meta, packed):
161 146 old_docket = self.docket
162 147 new_docket = docketmod.DirstateDocket.with_new_uuid(
163 148 self.parents(), len(packed), meta
164 149 )
165 150 data_filename = new_docket.data_filename()
166 151 if tr:
167 152 tr.add(data_filename, 0)
168 153 self._opener.write(data_filename, packed)
169 154 # Write the new docket after the new data file has been
170 155 # written. Because `st` was opened with `atomictemp=True`,
171 156 # the actual `.hg/dirstate` file is only affected on close.
172 157 st.write(new_docket.serialize())
173 158 st.close()
174 159 # Remove the old data file after the new docket pointing to
175 160 # the new data file was written.
176 161 if old_docket.uuid:
177 162 data_filename = old_docket.data_filename()
178 163 unlink = lambda _tr=None: self._opener.unlink(data_filename)
179 164 if tr:
180 165 category = b"dirstate-v2-clean-" + old_docket.uuid
181 166 tr.addpostclose(category, unlink)
182 167 else:
183 168 unlink()
184 169 self._docket = new_docket
185 170
186 171 ### reading/setting parents
187 172
188 173 def parents(self):
189 174 if not self._parents:
190 175 if self._use_dirstate_v2:
191 176 self._parents = self.docket.parents
192 177 else:
193 178 read_len = self._nodelen * 2
194 179 st = self._readdirstatefile(read_len)
195 180 l = len(st)
196 181 if l == read_len:
197 182 self._parents = (
198 183 st[: self._nodelen],
199 184 st[self._nodelen : 2 * self._nodelen],
200 185 )
201 186 elif l == 0:
202 187 self._parents = (
203 188 self._nodeconstants.nullid,
204 189 self._nodeconstants.nullid,
205 190 )
206 191 else:
207 192 raise error.Abort(
208 193 _(b'working directory state appears damaged!')
209 194 )
210 195
211 196 return self._parents
212 197
213 198
214 199 class dirstatemap(_dirstatemapcommon):
215 200 """Map encapsulating the dirstate's contents.
216 201
217 202 The dirstate contains the following state:
218 203
219 204 - `identity` is the identity of the dirstate file, which can be used to
220 205 detect when changes have occurred to the dirstate file.
221 206
222 207 - `parents` is a pair containing the parents of the working copy. The
223 208 parents are updated by calling `setparents`.
224 209
225 210 - the state map maps filenames to tuples of (state, mode, size, mtime),
226 211 where state is a single character representing 'normal', 'added',
227 212 'removed', or 'merged'. It is read by treating the dirstate as a
228 213 dict. File state is updated by calling various methods (see each
229 214 documentation for details):
230 215
231 216 - `reset_state`,
232 217 - `set_tracked`
233 218 - `set_untracked`
234 219 - `set_clean`
235 220 - `set_possibly_dirty`
236 221
237 222 - `copymap` maps destination filenames to their source filename.
238 223
239 224 The dirstate also provides the following views onto the state:
240 225
241 226 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
242 227 form that they appear as in the dirstate.
243 228
244 229 - `dirfoldmap` is a dict mapping normalized directory names to the
245 230 denormalized form that they appear as in the dirstate.
246 231 """
247 232
248 233 ### Core data storage and access
249 234
250 235 @propertycache
251 236 def _map(self):
252 237 self._map = {}
253 238 self.read()
254 239 return self._map
255 240
256 241 @propertycache
257 242 def copymap(self):
258 243 self.copymap = {}
259 244 self._map
260 245 return self.copymap
261 246
262 247 def clear(self):
263 248 self._map.clear()
264 249 self.copymap.clear()
265 250 self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid)
266 251 util.clearcachedproperty(self, b"_dirs")
267 252 util.clearcachedproperty(self, b"_alldirs")
268 253 util.clearcachedproperty(self, b"filefoldmap")
269 254 util.clearcachedproperty(self, b"dirfoldmap")
270 255
271 256 def items(self):
272 257 return self._map.items()
273 258
274 259 # forward for python2,3 compat
275 260 iteritems = items
276 261
277 262 def debug_iter(self, all):
278 263 """
279 264 Return an iterator of (filename, state, mode, size, mtime) tuples
280 265
281 266 `all` is unused when Rust is not enabled
282 267 """
283 268 for (filename, item) in self.items():
284 269 yield (filename, item.state, item.mode, item.size, item.mtime)
285 270
286 271 def keys(self):
287 272 return self._map.keys()
288 273
289 274 ### reading/setting parents
290 275
291 276 def setparents(self, p1, p2, fold_p2=False):
292 277 self._parents = (p1, p2)
293 278 self._dirtyparents = True
294 279 copies = {}
295 280 if fold_p2:
296 281 for f, s in self._map.items():
297 282 # Discard "merged" markers when moving away from a merge state
298 283 if s.p2_info:
299 284 source = self.copymap.pop(f, None)
300 285 if source:
301 286 copies[f] = source
302 287 s.drop_merge_data()
303 288 return copies
304 289
305 290 ### disk interaction
306 291
307 292 def read(self):
308 293 # ignore HG_PENDING because identity is used only for writing
309 294 self.identity = util.filestat.frompath(
310 295 self._opener.join(self._filename)
311 296 )
312 297
313 298 if self._use_dirstate_v2:
314 299 if not self.docket.uuid:
315 300 return
316 301 st = self._opener.read(self.docket.data_filename())
317 302 else:
318 303 st = self._readdirstatefile()
319 304
320 305 if not st:
321 306 return
322 307
323 308 # TODO: adjust this estimate for dirstate-v2
324 309 if util.safehasattr(parsers, b'dict_new_presized'):
325 310 # Make an estimate of the number of files in the dirstate based on
326 311 # its size. This trades wasting some memory for avoiding costly
327 312 # resizes. Each entry have a prefix of 17 bytes followed by one or
328 313 # two path names. Studies on various large-scale real-world repositories
329 314 # found 54 bytes a reasonable upper limit for the average path names.
330 315 # Copy entries are ignored for the sake of this estimate.
331 316 self._map = parsers.dict_new_presized(len(st) // 71)
332 317
333 318 # Python's garbage collector triggers a GC each time a certain number
334 319 # of container objects (the number being defined by
335 320 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
336 321 # for each file in the dirstate. The C version then immediately marks
337 322 # them as not to be tracked by the collector. However, this has no
338 323 # effect on when GCs are triggered, only on what objects the GC looks
339 324 # into. This means that O(number of files) GCs are unavoidable.
340 325 # Depending on when in the process's lifetime the dirstate is parsed,
341 326 # this can get very expensive. As a workaround, disable GC while
342 327 # parsing the dirstate.
343 328 #
344 329 # (we cannot decorate the function directly since it is in a C module)
345 330 if self._use_dirstate_v2:
346 331 p = self.docket.parents
347 332 meta = self.docket.tree_metadata
348 333 parse_dirstate = util.nogc(v2.parse_dirstate)
349 334 parse_dirstate(self._map, self.copymap, st, meta)
350 335 else:
351 336 parse_dirstate = util.nogc(parsers.parse_dirstate)
352 337 p = parse_dirstate(self._map, self.copymap, st)
353 338 if not self._dirtyparents:
354 339 self.setparents(*p)
355 340
356 341 # Avoid excess attribute lookups by fast pathing certain checks
357 342 self.__contains__ = self._map.__contains__
358 343 self.__getitem__ = self._map.__getitem__
359 344 self.get = self._map.get
360 345
361 346 def write(self, tr, st):
362 347 if self._use_dirstate_v2:
363 348 packed, meta = v2.pack_dirstate(self._map, self.copymap)
364 349 self.write_v2_no_append(tr, st, meta, packed)
365 350 else:
366 351 packed = parsers.pack_dirstate(
367 352 self._map, self.copymap, self.parents()
368 353 )
369 354 st.write(packed)
370 355 st.close()
371 356 self._dirtyparents = False
372 357
373 358 @propertycache
374 359 def identity(self):
375 360 self._map
376 361 return self.identity
377 362
378 363 ### code related to maintaining and accessing "extra" property
379 364 # (e.g. "has_dir")
380 365
381 366 def _dirs_incr(self, filename, old_entry=None):
382 367 """incremente the dirstate counter if applicable"""
383 368 if (
384 369 old_entry is None or old_entry.removed
385 370 ) and "_dirs" in self.__dict__:
386 371 self._dirs.addpath(filename)
387 372 if old_entry is None and "_alldirs" in self.__dict__:
388 373 self._alldirs.addpath(filename)
389 374
390 375 def _dirs_decr(self, filename, old_entry=None, remove_variant=False):
391 376 """decremente the dirstate counter if applicable"""
392 377 if old_entry is not None:
393 378 if "_dirs" in self.__dict__ and not old_entry.removed:
394 379 self._dirs.delpath(filename)
395 380 if "_alldirs" in self.__dict__ and not remove_variant:
396 381 self._alldirs.delpath(filename)
397 382 elif remove_variant and "_alldirs" in self.__dict__:
398 383 self._alldirs.addpath(filename)
399 384 if "filefoldmap" in self.__dict__:
400 385 normed = util.normcase(filename)
401 386 self.filefoldmap.pop(normed, None)
402 387
403 388 @propertycache
404 389 def filefoldmap(self):
405 390 """Returns a dictionary mapping normalized case paths to their
406 391 non-normalized versions.
407 392 """
408 393 try:
409 394 makefilefoldmap = parsers.make_file_foldmap
410 395 except AttributeError:
411 396 pass
412 397 else:
413 398 return makefilefoldmap(
414 399 self._map, util.normcasespec, util.normcasefallback
415 400 )
416 401
417 402 f = {}
418 403 normcase = util.normcase
419 404 for name, s in self._map.items():
420 405 if not s.removed:
421 406 f[normcase(name)] = name
422 407 f[b'.'] = b'.' # prevents useless util.fspath() invocation
423 408 return f
424 409
425 410 @propertycache
426 411 def dirfoldmap(self):
427 412 f = {}
428 413 normcase = util.normcase
429 414 for name in self._dirs:
430 415 f[normcase(name)] = name
431 416 return f
432 417
433 418 def hastrackeddir(self, d):
434 419 """
435 420 Returns True if the dirstate contains a tracked (not removed) file
436 421 in this directory.
437 422 """
438 423 return d in self._dirs
439 424
440 425 def hasdir(self, d):
441 426 """
442 427 Returns True if the dirstate contains a file (tracked or removed)
443 428 in this directory.
444 429 """
445 430 return d in self._alldirs
446 431
447 432 @propertycache
448 433 def _dirs(self):
449 434 return pathutil.dirs(self._map, only_tracked=True)
450 435
451 436 @propertycache
452 437 def _alldirs(self):
453 438 return pathutil.dirs(self._map)
454 439
455 440 ### code related to manipulation of entries and copy-sources
456 441
457 442 def reset_state(
458 443 self,
459 444 filename,
460 445 wc_tracked=False,
461 446 p1_tracked=False,
462 447 p2_info=False,
463 448 has_meaningful_mtime=True,
464 449 parentfiledata=None,
465 450 ):
466 451 """Set a entry to a given state, diregarding all previous state
467 452
468 453 This is to be used by the part of the dirstate API dedicated to
469 454 adjusting the dirstate after a update/merge.
470 455
471 456 note: calling this might result to no entry existing at all if the
472 457 dirstate map does not see any point at having one for this file
473 458 anymore.
474 459 """
475 460 # copy information are now outdated
476 461 # (maybe new information should be in directly passed to this function)
477 462 self.copymap.pop(filename, None)
478 463
479 464 if not (p1_tracked or p2_info or wc_tracked):
480 465 old_entry = self._map.get(filename)
481 466 self._drop_entry(filename)
482 467 self._dirs_decr(filename, old_entry=old_entry)
483 468 return
484 469
485 470 old_entry = self._map.get(filename)
486 471 self._dirs_incr(filename, old_entry)
487 472 entry = DirstateItem(
488 473 wc_tracked=wc_tracked,
489 474 p1_tracked=p1_tracked,
490 475 p2_info=p2_info,
491 476 has_meaningful_mtime=has_meaningful_mtime,
492 477 parentfiledata=parentfiledata,
493 478 )
494 479 self._map[filename] = entry
495 480
496 481 def set_tracked(self, filename):
497 482 new = False
498 483 entry = self.get(filename)
499 484 if entry is None:
500 485 self._dirs_incr(filename)
501 486 entry = DirstateItem(
502 487 wc_tracked=True,
503 488 )
504 489
505 490 self._map[filename] = entry
506 491 new = True
507 492 elif not entry.tracked:
508 493 self._dirs_incr(filename, entry)
509 494 entry.set_tracked()
510 495 self._refresh_entry(filename, entry)
511 496 new = True
512 497 else:
513 498 # XXX This is probably overkill for more case, but we need this to
514 499 # fully replace the `normallookup` call with `set_tracked` one.
515 500 # Consider smoothing this in the future.
516 501 entry.set_possibly_dirty()
517 502 self._refresh_entry(filename, entry)
518 503 return new
519 504
505 def set_untracked(self, f):
506 """Mark a file as no longer tracked in the dirstate map"""
507 entry = self.get(f)
508 if entry is None:
509 return False
510 else:
511 self._dirs_decr(f, old_entry=entry, remove_variant=not entry.added)
512 if not entry.p2_info:
513 self.copymap.pop(f, None)
514 entry.set_untracked()
515 self._refresh_entry(f, entry)
516 return True
517
520 518 def set_clean(self, filename, mode, size, mtime):
521 519 """mark a file as back to a clean state"""
522 520 entry = self[filename]
523 521 size = size & rangemask
524 522 entry.set_clean(mode, size, mtime)
525 523 self._refresh_entry(filename, entry)
526 524 self.copymap.pop(filename, None)
527 525
528 526 def set_possibly_dirty(self, filename):
529 527 """record that the current state of the file on disk is unknown"""
530 528 entry = self[filename]
531 529 entry.set_possibly_dirty()
532 530 self._refresh_entry(filename, entry)
533 531
534 532 def _refresh_entry(self, f, entry):
535 533 if not entry.any_tracked:
536 534 self._map.pop(f, None)
537 535
538 536 def _drop_entry(self, f):
539 537 self._map.pop(f, None)
540 538 self.copymap.pop(f, None)
541 539
542 540
543 541 if rustmod is not None:
544 542
545 543 class dirstatemap(_dirstatemapcommon):
546 544
547 545 ### Core data storage and access
548 546
549 547 @propertycache
550 548 def _map(self):
551 549 """
552 550 Fills the Dirstatemap when called.
553 551 """
554 552 # ignore HG_PENDING because identity is used only for writing
555 553 self.identity = util.filestat.frompath(
556 554 self._opener.join(self._filename)
557 555 )
558 556
559 557 if self._use_dirstate_v2:
560 558 if self.docket.uuid:
561 559 # TODO: use mmap when possible
562 560 data = self._opener.read(self.docket.data_filename())
563 561 else:
564 562 data = b''
565 563 self._map = rustmod.DirstateMap.new_v2(
566 564 data, self.docket.data_size, self.docket.tree_metadata
567 565 )
568 566 parents = self.docket.parents
569 567 else:
570 568 self._map, parents = rustmod.DirstateMap.new_v1(
571 569 self._readdirstatefile()
572 570 )
573 571
574 572 if parents and not self._dirtyparents:
575 573 self.setparents(*parents)
576 574
577 575 self.__contains__ = self._map.__contains__
578 576 self.__getitem__ = self._map.__getitem__
579 577 self.get = self._map.get
580 578 return self._map
581 579
582 580 @property
583 581 def copymap(self):
584 582 return self._map.copymap()
585 583
586 584 def debug_iter(self, all):
587 585 """
588 586 Return an iterator of (filename, state, mode, size, mtime) tuples
589 587
590 588 `all`: also include with `state == b' '` dirstate tree nodes that
591 589 don't have an associated `DirstateItem`.
592 590
593 591 """
594 592 return self._map.debug_iter(all)
595 593
596 594 def clear(self):
597 595 self._map.clear()
598 596 self.setparents(
599 597 self._nodeconstants.nullid, self._nodeconstants.nullid
600 598 )
601 599 util.clearcachedproperty(self, b"_dirs")
602 600 util.clearcachedproperty(self, b"_alldirs")
603 601 util.clearcachedproperty(self, b"dirfoldmap")
604 602
605 603 def items(self):
606 604 return self._map.items()
607 605
608 606 # forward for python2,3 compat
609 607 iteritems = items
610 608
611 609 def keys(self):
612 610 return iter(self._map)
613 611
614 612 ### reading/setting parents
615 613
616 614 def setparents(self, p1, p2, fold_p2=False):
617 615 self._parents = (p1, p2)
618 616 self._dirtyparents = True
619 617 copies = {}
620 618 if fold_p2:
621 619 # Collect into an intermediate list to avoid a `RuntimeError`
622 620 # exception due to mutation during iteration.
623 621 # TODO: move this the whole loop to Rust where `iter_mut`
624 622 # enables in-place mutation of elements of a collection while
625 623 # iterating it, without mutating the collection itself.
626 624 files_with_p2_info = [
627 625 f for f, s in self._map.items() if s.p2_info
628 626 ]
629 627 rust_map = self._map
630 628 for f in files_with_p2_info:
631 629 e = rust_map.get(f)
632 630 source = self.copymap.pop(f, None)
633 631 if source:
634 632 copies[f] = source
635 633 e.drop_merge_data()
636 634 rust_map.set_dirstate_item(f, e)
637 635 return copies
638 636
639 637 ### disk interaction
640 638
641 639 @propertycache
642 640 def identity(self):
643 641 self._map
644 642 return self.identity
645 643
646 644 def write(self, tr, st):
647 645 if not self._use_dirstate_v2:
648 646 p1, p2 = self.parents()
649 647 packed = self._map.write_v1(p1, p2)
650 648 st.write(packed)
651 649 st.close()
652 650 self._dirtyparents = False
653 651 return
654 652
655 653 # We can only append to an existing data file if there is one
656 654 can_append = self.docket.uuid is not None
657 655 packed, meta, append = self._map.write_v2(can_append)
658 656 if append:
659 657 docket = self.docket
660 658 data_filename = docket.data_filename()
661 659 if tr:
662 660 tr.add(data_filename, docket.data_size)
663 661 with self._opener(data_filename, b'r+b') as fp:
664 662 fp.seek(docket.data_size)
665 663 assert fp.tell() == docket.data_size
666 664 written = fp.write(packed)
667 665 if written is not None: # py2 may return None
668 666 assert written == len(packed), (written, len(packed))
669 667 docket.data_size += len(packed)
670 668 docket.parents = self.parents()
671 669 docket.tree_metadata = meta
672 670 st.write(docket.serialize())
673 671 st.close()
674 672 else:
675 673 self.write_v2_no_append(tr, st, meta, packed)
676 674 # Reload from the newly-written file
677 675 util.clearcachedproperty(self, b"_map")
678 676 self._dirtyparents = False
679 677
680 678 ### code related to maintaining and accessing "extra" property
681 679 # (e.g. "has_dir")
682 680
683 681 @propertycache
684 682 def filefoldmap(self):
685 683 """Returns a dictionary mapping normalized case paths to their
686 684 non-normalized versions.
687 685 """
688 686 return self._map.filefoldmapasdict()
689 687
690 688 def hastrackeddir(self, d):
691 689 return self._map.hastrackeddir(d)
692 690
693 691 def hasdir(self, d):
694 692 return self._map.hasdir(d)
695 693
696 694 @propertycache
697 695 def dirfoldmap(self):
698 696 f = {}
699 697 normcase = util.normcase
700 698 for name in self._map.tracked_dirs():
701 699 f[normcase(name)] = name
702 700 return f
703 701
704 702 ### code related to manipulation of entries and copy-sources
705 703
706 704 def _refresh_entry(self, f, entry):
707 705 if not entry.any_tracked:
708 706 self._map.drop_item_and_copy_source(f)
709 707 else:
710 708 self._map.addfile(f, entry)
711 709
712 710 def set_tracked(self, f):
713 711 return self._map.set_tracked(f)
714 712
713 def set_untracked(self, f):
714 return self._map.set_untracked(f)
715
715 716 def set_clean(self, filename, mode, size, mtime):
716 717 self._map.set_clean(filename, mode, size, mtime)
717 718
718 719 def set_possibly_dirty(self, f):
719 720 self._map.set_possibly_dirty(f)
720 721
721 722 def reset_state(
722 723 self,
723 724 filename,
724 725 wc_tracked=False,
725 726 p1_tracked=False,
726 727 p2_info=False,
727 728 has_meaningful_mtime=True,
728 729 parentfiledata=None,
729 730 ):
730 731 return self._map.reset_state(
731 732 filename,
732 733 wc_tracked,
733 734 p1_tracked,
734 735 p2_info,
735 736 has_meaningful_mtime,
736 737 parentfiledata,
737 738 )
738 739
739 740 def _drop_entry(self, f):
740 741 self._map.drop_item_and_copy_source(f)
741 742
742 743 def __setitem__(self, key, value):
743 744 assert isinstance(value, DirstateItem)
744 745 self._map.set_dirstate_item(key, value)
General Comments 0
You need to be logged in to leave comments. Login now