Mercurial > hg-stable
comparison mercurial/context.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 8af909893188 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
47 stringutil, | 47 stringutil, |
48 ) | 48 ) |
49 | 49 |
50 propertycache = util.propertycache | 50 propertycache = util.propertycache |
51 | 51 |
52 | |
52 class basectx(object): | 53 class basectx(object): |
53 """A basectx object represents the common logic for its children: | 54 """A basectx object represents the common logic for its children: |
54 changectx: read-only context that is already present in the repo, | 55 changectx: read-only context that is already present in the repo, |
55 workingctx: a context that represents the working directory and can | 56 workingctx: a context that represents the working directory and can |
56 be committed, | 57 be committed, |
96 """This internal method provides a way for child objects to override the | 97 """This internal method provides a way for child objects to override the |
97 match operator. | 98 match operator. |
98 """ | 99 """ |
99 return match | 100 return match |
100 | 101 |
101 def _buildstatus(self, other, s, match, listignored, listclean, | 102 def _buildstatus( |
102 listunknown): | 103 self, other, s, match, listignored, listclean, listunknown |
104 ): | |
103 """build a status with respect to another context""" | 105 """build a status with respect to another context""" |
104 # Load earliest manifest first for caching reasons. More specifically, | 106 # Load earliest manifest first for caching reasons. More specifically, |
105 # if you have revisions 1000 and 1001, 1001 is probably stored as a | 107 # if you have revisions 1000 and 1001, 1001 is probably stored as a |
106 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct | 108 # delta against 1000. Thus, if you read 1000 first, we'll reconstruct |
107 # 1000 and cache it so that when you read 1001, we just need to apply a | 109 # 1000 and cache it so that when you read 1001, we just need to apply a |
144 else: | 146 else: |
145 clean.append(fn) | 147 clean.append(fn) |
146 | 148 |
147 if removed: | 149 if removed: |
148 # need to filter files if they are already reported as removed | 150 # need to filter files if they are already reported as removed |
149 unknown = [fn for fn in unknown if fn not in mf1 and | 151 unknown = [ |
150 (not match or match(fn))] | 152 fn |
151 ignored = [fn for fn in ignored if fn not in mf1 and | 153 for fn in unknown |
152 (not match or match(fn))] | 154 if fn not in mf1 and (not match or match(fn)) |
155 ] | |
156 ignored = [ | |
157 fn | |
158 for fn in ignored | |
159 if fn not in mf1 and (not match or match(fn)) | |
160 ] | |
153 # if they're deleted, don't report them as removed | 161 # if they're deleted, don't report them as removed |
154 removed = [fn for fn in removed if fn not in deletedset] | 162 removed = [fn for fn in removed if fn not in deletedset] |
155 | 163 |
156 return scmutil.status(modified, added, removed, deleted, unknown, | 164 return scmutil.status( |
157 ignored, clean) | 165 modified, added, removed, deleted, unknown, ignored, clean |
166 ) | |
158 | 167 |
159 @propertycache | 168 @propertycache |
160 def substate(self): | 169 def substate(self): |
161 return subrepoutil.state(self, self._repo.ui) | 170 return subrepoutil.state(self, self._repo.ui) |
162 | 171 |
163 def subrev(self, subpath): | 172 def subrev(self, subpath): |
164 return self.substate[subpath][1] | 173 return self.substate[subpath][1] |
165 | 174 |
166 def rev(self): | 175 def rev(self): |
167 return self._rev | 176 return self._rev |
177 | |
168 def node(self): | 178 def node(self): |
169 return self._node | 179 return self._node |
180 | |
170 def hex(self): | 181 def hex(self): |
171 return hex(self.node()) | 182 return hex(self.node()) |
183 | |
172 def manifest(self): | 184 def manifest(self): |
173 return self._manifest | 185 return self._manifest |
186 | |
174 def manifestctx(self): | 187 def manifestctx(self): |
175 return self._manifestctx | 188 return self._manifestctx |
189 | |
176 def repo(self): | 190 def repo(self): |
177 return self._repo | 191 return self._repo |
192 | |
178 def phasestr(self): | 193 def phasestr(self): |
179 return phases.phasenames[self.phase()] | 194 return phases.phasenames[self.phase()] |
195 | |
180 def mutable(self): | 196 def mutable(self): |
181 return self.phase() > phases.public | 197 return self.phase() > phases.public |
182 | 198 |
183 def matchfileset(self, expr, badfn=None): | 199 def matchfileset(self, expr, badfn=None): |
184 return fileset.match(self, expr, badfn=badfn) | 200 return fileset.match(self, expr, badfn=badfn) |
247 def _fileinfo(self, path): | 263 def _fileinfo(self, path): |
248 if r'_manifest' in self.__dict__: | 264 if r'_manifest' in self.__dict__: |
249 try: | 265 try: |
250 return self._manifest[path], self._manifest.flags(path) | 266 return self._manifest[path], self._manifest.flags(path) |
251 except KeyError: | 267 except KeyError: |
252 raise error.ManifestLookupError(self._node, path, | 268 raise error.ManifestLookupError( |
253 _('not found in manifest')) | 269 self._node, path, _('not found in manifest') |
270 ) | |
254 if r'_manifestdelta' in self.__dict__ or path in self.files(): | 271 if r'_manifestdelta' in self.__dict__ or path in self.files(): |
255 if path in self._manifestdelta: | 272 if path in self._manifestdelta: |
256 return (self._manifestdelta[path], | 273 return ( |
257 self._manifestdelta.flags(path)) | 274 self._manifestdelta[path], |
275 self._manifestdelta.flags(path), | |
276 ) | |
258 mfl = self._repo.manifestlog | 277 mfl = self._repo.manifestlog |
259 try: | 278 try: |
260 node, flag = mfl[self._changeset.manifest].find(path) | 279 node, flag = mfl[self._changeset.manifest].find(path) |
261 except KeyError: | 280 except KeyError: |
262 raise error.ManifestLookupError(self._node, path, | 281 raise error.ManifestLookupError( |
263 _('not found in manifest')) | 282 self._node, path, _('not found in manifest') |
283 ) | |
264 | 284 |
265 return node, flag | 285 return node, flag |
266 | 286 |
267 def filenode(self, path): | 287 def filenode(self, path): |
268 return self._fileinfo(path)[0] | 288 return self._fileinfo(path)[0] |
274 return '' | 294 return '' |
275 | 295 |
276 @propertycache | 296 @propertycache |
277 def _copies(self): | 297 def _copies(self): |
278 return copies.computechangesetcopies(self) | 298 return copies.computechangesetcopies(self) |
299 | |
279 def p1copies(self): | 300 def p1copies(self): |
280 return self._copies[0] | 301 return self._copies[0] |
302 | |
281 def p2copies(self): | 303 def p2copies(self): |
282 return self._copies[1] | 304 return self._copies[1] |
283 | 305 |
284 def sub(self, path, allowcreate=True): | 306 def sub(self, path, allowcreate=True): |
285 '''return a subrepo for the stored revision of path, never wdir()''' | 307 '''return a subrepo for the stored revision of path, never wdir()''' |
292 '''return a subrepo for the stored revision, or wdir if this is a wdir | 314 '''return a subrepo for the stored revision, or wdir if this is a wdir |
293 context. | 315 context. |
294 ''' | 316 ''' |
295 return subrepo.subrepo(self, path, allowwdir=True) | 317 return subrepo.subrepo(self, path, allowwdir=True) |
296 | 318 |
297 def match(self, pats=None, include=None, exclude=None, default='glob', | 319 def match( |
298 listsubrepos=False, badfn=None): | 320 self, |
321 pats=None, | |
322 include=None, | |
323 exclude=None, | |
324 default='glob', | |
325 listsubrepos=False, | |
326 badfn=None, | |
327 ): | |
299 r = self._repo | 328 r = self._repo |
300 return matchmod.match(r.root, r.getcwd(), pats, | 329 return matchmod.match( |
301 include, exclude, default, | 330 r.root, |
302 auditor=r.nofsauditor, ctx=self, | 331 r.getcwd(), |
303 listsubrepos=listsubrepos, badfn=badfn) | 332 pats, |
304 | 333 include, |
305 def diff(self, ctx2=None, match=None, changes=None, opts=None, | 334 exclude, |
306 losedatafn=None, pathfn=None, copy=None, | 335 default, |
307 copysourcematch=None, hunksfilterfn=None): | 336 auditor=r.nofsauditor, |
337 ctx=self, | |
338 listsubrepos=listsubrepos, | |
339 badfn=badfn, | |
340 ) | |
341 | |
342 def diff( | |
343 self, | |
344 ctx2=None, | |
345 match=None, | |
346 changes=None, | |
347 opts=None, | |
348 losedatafn=None, | |
349 pathfn=None, | |
350 copy=None, | |
351 copysourcematch=None, | |
352 hunksfilterfn=None, | |
353 ): | |
308 """Returns a diff generator for the given contexts and matcher""" | 354 """Returns a diff generator for the given contexts and matcher""" |
309 if ctx2 is None: | 355 if ctx2 is None: |
310 ctx2 = self.p1() | 356 ctx2 = self.p1() |
311 if ctx2 is not None: | 357 if ctx2 is not None: |
312 ctx2 = self._repo[ctx2] | 358 ctx2 = self._repo[ctx2] |
313 return patch.diff(self._repo, ctx2, self, match=match, changes=changes, | 359 return patch.diff( |
314 opts=opts, losedatafn=losedatafn, pathfn=pathfn, | 360 self._repo, |
315 copy=copy, copysourcematch=copysourcematch, | 361 ctx2, |
316 hunksfilterfn=hunksfilterfn) | 362 self, |
363 match=match, | |
364 changes=changes, | |
365 opts=opts, | |
366 losedatafn=losedatafn, | |
367 pathfn=pathfn, | |
368 copy=copy, | |
369 copysourcematch=copysourcematch, | |
370 hunksfilterfn=hunksfilterfn, | |
371 ) | |
317 | 372 |
318 def dirs(self): | 373 def dirs(self): |
319 return self._manifest.dirs() | 374 return self._manifest.dirs() |
320 | 375 |
321 def hasdir(self, dir): | 376 def hasdir(self, dir): |
322 return self._manifest.hasdir(dir) | 377 return self._manifest.hasdir(dir) |
323 | 378 |
324 def status(self, other=None, match=None, listignored=False, | 379 def status( |
325 listclean=False, listunknown=False, listsubrepos=False): | 380 self, |
381 other=None, | |
382 match=None, | |
383 listignored=False, | |
384 listclean=False, | |
385 listunknown=False, | |
386 listsubrepos=False, | |
387 ): | |
326 """return status of files between two nodes or node and working | 388 """return status of files between two nodes or node and working |
327 directory. | 389 directory. |
328 | 390 |
329 If other is None, compare this node with working directory. | 391 If other is None, compare this node with working directory. |
330 | 392 |
345 # | 407 # |
346 # If we always built the manifest for each context and compared those, | 408 # If we always built the manifest for each context and compared those, |
347 # then we'd be done. But the special case of the above call means we | 409 # then we'd be done. But the special case of the above call means we |
348 # just copy the manifest of the parent. | 410 # just copy the manifest of the parent. |
349 reversed = False | 411 reversed = False |
350 if (not isinstance(ctx1, changectx) | 412 if not isinstance(ctx1, changectx) and isinstance(ctx2, changectx): |
351 and isinstance(ctx2, changectx)): | |
352 reversed = True | 413 reversed = True |
353 ctx1, ctx2 = ctx2, ctx1 | 414 ctx1, ctx2 = ctx2, ctx1 |
354 | 415 |
355 match = self._repo.narrowmatch(match) | 416 match = self._repo.narrowmatch(match) |
356 match = ctx2._matchstatus(ctx1, match) | 417 match = ctx2._matchstatus(ctx1, match) |
357 r = scmutil.status([], [], [], [], [], [], []) | 418 r = scmutil.status([], [], [], [], [], [], []) |
358 r = ctx2._buildstatus(ctx1, r, match, listignored, listclean, | 419 r = ctx2._buildstatus( |
359 listunknown) | 420 ctx1, r, match, listignored, listclean, listunknown |
421 ) | |
360 | 422 |
361 if reversed: | 423 if reversed: |
362 # Reverse added and removed. Clear deleted, unknown and ignored as | 424 # Reverse added and removed. Clear deleted, unknown and ignored as |
363 # these make no sense to reverse. | 425 # these make no sense to reverse. |
364 r = scmutil.status(r.modified, r.removed, r.added, [], [], [], | 426 r = scmutil.status( |
365 r.clean) | 427 r.modified, r.removed, r.added, [], [], [], r.clean |
428 ) | |
366 | 429 |
367 if listsubrepos: | 430 if listsubrepos: |
368 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2): | 431 for subpath, sub in scmutil.itersubrepos(ctx1, ctx2): |
369 try: | 432 try: |
370 rev2 = ctx2.subrev(subpath) | 433 rev2 = ctx2.subrev(subpath) |
372 # A subrepo that existed in node1 was deleted between | 435 # A subrepo that existed in node1 was deleted between |
373 # node1 and node2 (inclusive). Thus, ctx2's substate | 436 # node1 and node2 (inclusive). Thus, ctx2's substate |
374 # won't contain that subpath. The best we can do ignore it. | 437 # won't contain that subpath. The best we can do ignore it. |
375 rev2 = None | 438 rev2 = None |
376 submatch = matchmod.subdirmatcher(subpath, match) | 439 submatch = matchmod.subdirmatcher(subpath, match) |
377 s = sub.status(rev2, match=submatch, ignored=listignored, | 440 s = sub.status( |
378 clean=listclean, unknown=listunknown, | 441 rev2, |
379 listsubrepos=True) | 442 match=submatch, |
443 ignored=listignored, | |
444 clean=listclean, | |
445 unknown=listunknown, | |
446 listsubrepos=True, | |
447 ) | |
380 for rfiles, sfiles in zip(r, s): | 448 for rfiles, sfiles in zip(r, s): |
381 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles) | 449 rfiles.extend("%s/%s" % (subpath, f) for f in sfiles) |
382 | 450 |
383 for l in r: | 451 for l in r: |
384 l.sort() | 452 l.sort() |
385 | 453 |
386 return r | 454 return r |
455 | |
387 | 456 |
388 class changectx(basectx): | 457 class changectx(basectx): |
389 """A changecontext object makes access to data related to a particular | 458 """A changecontext object makes access to data related to a particular |
390 changeset convenient. It represents a read-only context already present in | 459 changeset convenient. It represents a read-only context already present in |
391 the repo.""" | 460 the repo.""" |
461 | |
392 def __init__(self, repo, rev, node): | 462 def __init__(self, repo, rev, node): |
393 super(changectx, self).__init__(repo) | 463 super(changectx, self).__init__(repo) |
394 self._rev = rev | 464 self._rev = rev |
395 self._node = node | 465 self._node = node |
396 | 466 |
437 c.date, | 507 c.date, |
438 c.files, | 508 c.files, |
439 c.description, | 509 c.description, |
440 c.extra, | 510 c.extra, |
441 ) | 511 ) |
512 | |
442 def manifestnode(self): | 513 def manifestnode(self): |
443 return self._changeset.manifest | 514 return self._changeset.manifest |
444 | 515 |
445 def user(self): | 516 def user(self): |
446 return self._changeset.user | 517 return self._changeset.user |
518 | |
447 def date(self): | 519 def date(self): |
448 return self._changeset.date | 520 return self._changeset.date |
521 | |
449 def files(self): | 522 def files(self): |
450 return self._changeset.files | 523 return self._changeset.files |
524 | |
451 def filesmodified(self): | 525 def filesmodified(self): |
452 modified = set(self.files()) | 526 modified = set(self.files()) |
453 modified.difference_update(self.filesadded()) | 527 modified.difference_update(self.filesadded()) |
454 modified.difference_update(self.filesremoved()) | 528 modified.difference_update(self.filesremoved()) |
455 return sorted(modified) | 529 return sorted(modified) |
506 p1copies, p2copies = super(changectx, self)._copies | 580 p1copies, p2copies = super(changectx, self)._copies |
507 return p1copies, p2copies | 581 return p1copies, p2copies |
508 | 582 |
509 def description(self): | 583 def description(self): |
510 return self._changeset.description | 584 return self._changeset.description |
585 | |
511 def branch(self): | 586 def branch(self): |
512 return encoding.tolocal(self._changeset.extra.get("branch")) | 587 return encoding.tolocal(self._changeset.extra.get("branch")) |
588 | |
513 def closesbranch(self): | 589 def closesbranch(self): |
514 return 'close' in self._changeset.extra | 590 return 'close' in self._changeset.extra |
591 | |
515 def extra(self): | 592 def extra(self): |
516 """Return a dict of extra information.""" | 593 """Return a dict of extra information.""" |
517 return self._changeset.extra | 594 return self._changeset.extra |
595 | |
518 def tags(self): | 596 def tags(self): |
519 """Return a list of byte tag names""" | 597 """Return a list of byte tag names""" |
520 return self._repo.nodetags(self._node) | 598 return self._repo.nodetags(self._node) |
599 | |
521 def bookmarks(self): | 600 def bookmarks(self): |
522 """Return a list of byte bookmark names.""" | 601 """Return a list of byte bookmark names.""" |
523 return self._repo.nodebookmarks(self._node) | 602 return self._repo.nodebookmarks(self._node) |
603 | |
524 def phase(self): | 604 def phase(self): |
525 return self._repo._phasecache.phase(self._repo, self._rev) | 605 return self._repo._phasecache.phase(self._repo, self._rev) |
606 | |
526 def hidden(self): | 607 def hidden(self): |
527 return self._rev in repoview.filterrevs(self._repo, 'visible') | 608 return self._rev in repoview.filterrevs(self._repo, 'visible') |
528 | 609 |
529 def isinmemory(self): | 610 def isinmemory(self): |
530 return False | 611 return False |
552 | 633 |
553 def filectx(self, path, fileid=None, filelog=None): | 634 def filectx(self, path, fileid=None, filelog=None): |
554 """get a file context from this changeset""" | 635 """get a file context from this changeset""" |
555 if fileid is None: | 636 if fileid is None: |
556 fileid = self.filenode(path) | 637 fileid = self.filenode(path) |
557 return filectx(self._repo, path, fileid=fileid, | 638 return filectx( |
558 changectx=self, filelog=filelog) | 639 self._repo, path, fileid=fileid, changectx=self, filelog=filelog |
640 ) | |
559 | 641 |
560 def ancestor(self, c2, warn=False): | 642 def ancestor(self, c2, warn=False): |
561 """return the "best" ancestor context of self and c2 | 643 """return the "best" ancestor context of self and c2 |
562 | 644 |
563 If there are multiple candidates, it will show a message and check | 645 If there are multiple candidates, it will show a message and check |
584 break | 666 break |
585 else: | 667 else: |
586 anc = self._repo.changelog.ancestor(self._node, n2) | 668 anc = self._repo.changelog.ancestor(self._node, n2) |
587 if warn: | 669 if warn: |
588 self._repo.ui.status( | 670 self._repo.ui.status( |
589 (_("note: using %s as ancestor of %s and %s\n") % | 671 ( |
590 (short(anc), short(self._node), short(n2))) + | 672 _("note: using %s as ancestor of %s and %s\n") |
591 ''.join(_(" alternatively, use --config " | 673 % (short(anc), short(self._node), short(n2)) |
592 "merge.preferancestor=%s\n") % | 674 ) |
593 short(n) for n in sorted(cahs) if n != anc)) | 675 + ''.join( |
676 _( | |
677 " alternatively, use --config " | |
678 "merge.preferancestor=%s\n" | |
679 ) | |
680 % short(n) | |
681 for n in sorted(cahs) | |
682 if n != anc | |
683 ) | |
684 ) | |
594 return self._repo[anc] | 685 return self._repo[anc] |
595 | 686 |
596 def isancestorof(self, other): | 687 def isancestorof(self, other): |
597 """True if this changeset is an ancestor of other""" | 688 """True if this changeset is an ancestor of other""" |
598 return self._repo.changelog.isancestorrev(self._rev, other._rev) | 689 return self._repo.changelog.isancestorrev(self._rev, other._rev) |
602 | 693 |
603 # Wrap match.bad method to have message with nodeid | 694 # Wrap match.bad method to have message with nodeid |
604 def bad(fn, msg): | 695 def bad(fn, msg): |
605 # The manifest doesn't know about subrepos, so don't complain about | 696 # The manifest doesn't know about subrepos, so don't complain about |
606 # paths into valid subrepos. | 697 # paths into valid subrepos. |
607 if any(fn == s or fn.startswith(s + '/') | 698 if any(fn == s or fn.startswith(s + '/') for s in self.substate): |
608 for s in self.substate): | |
609 return | 699 return |
610 match.bad(fn, _('no such file in rev %s') % self) | 700 match.bad(fn, _('no such file in rev %s') % self) |
611 | 701 |
612 m = matchmod.badmatch(self._repo.narrowmatch(match), bad) | 702 m = matchmod.badmatch(self._repo.narrowmatch(match), bad) |
613 return self._manifest.walk(m) | 703 return self._manifest.walk(m) |
614 | 704 |
615 def matches(self, match): | 705 def matches(self, match): |
616 return self.walk(match) | 706 return self.walk(match) |
707 | |
617 | 708 |
618 class basefilectx(object): | 709 class basefilectx(object): |
619 """A filecontext object represents the common logic for its children: | 710 """A filecontext object represents the common logic for its children: |
620 filectx: read-only access to a filerevision that is already present | 711 filectx: read-only access to a filerevision that is already present |
621 in the repo, | 712 in the repo, |
622 workingfilectx: a filecontext that represents files from the working | 713 workingfilectx: a filecontext that represents files from the working |
623 directory, | 714 directory, |
624 memfilectx: a filecontext that represents files in-memory, | 715 memfilectx: a filecontext that represents files in-memory, |
625 """ | 716 """ |
717 | |
626 @propertycache | 718 @propertycache |
627 def _filelog(self): | 719 def _filelog(self): |
628 return self._repo.file(self._path) | 720 return self._repo.file(self._path) |
629 | 721 |
630 @propertycache | 722 @propertycache |
680 except AttributeError: | 772 except AttributeError: |
681 return id(self) | 773 return id(self) |
682 | 774 |
683 def __eq__(self, other): | 775 def __eq__(self, other): |
684 try: | 776 try: |
685 return (type(self) == type(other) and self._path == other._path | 777 return ( |
686 and self._filenode == other._filenode) | 778 type(self) == type(other) |
779 and self._path == other._path | |
780 and self._filenode == other._filenode | |
781 ) | |
687 except AttributeError: | 782 except AttributeError: |
688 return False | 783 return False |
689 | 784 |
690 def __ne__(self, other): | 785 def __ne__(self, other): |
691 return not (self == other) | 786 return not (self == other) |
692 | 787 |
693 def filerev(self): | 788 def filerev(self): |
694 return self._filerev | 789 return self._filerev |
790 | |
695 def filenode(self): | 791 def filenode(self): |
696 return self._filenode | 792 return self._filenode |
793 | |
697 @propertycache | 794 @propertycache |
698 def _flags(self): | 795 def _flags(self): |
699 return self._changectx.flags(self._path) | 796 return self._changectx.flags(self._path) |
797 | |
700 def flags(self): | 798 def flags(self): |
701 return self._flags | 799 return self._flags |
800 | |
702 def filelog(self): | 801 def filelog(self): |
703 return self._filelog | 802 return self._filelog |
803 | |
704 def rev(self): | 804 def rev(self): |
705 return self._changeid | 805 return self._changeid |
806 | |
706 def linkrev(self): | 807 def linkrev(self): |
707 return self._filelog.linkrev(self._filerev) | 808 return self._filelog.linkrev(self._filerev) |
809 | |
708 def node(self): | 810 def node(self): |
709 return self._changectx.node() | 811 return self._changectx.node() |
812 | |
710 def hex(self): | 813 def hex(self): |
711 return self._changectx.hex() | 814 return self._changectx.hex() |
815 | |
712 def user(self): | 816 def user(self): |
713 return self._changectx.user() | 817 return self._changectx.user() |
818 | |
714 def date(self): | 819 def date(self): |
715 return self._changectx.date() | 820 return self._changectx.date() |
821 | |
716 def files(self): | 822 def files(self): |
717 return self._changectx.files() | 823 return self._changectx.files() |
824 | |
718 def description(self): | 825 def description(self): |
719 return self._changectx.description() | 826 return self._changectx.description() |
827 | |
720 def branch(self): | 828 def branch(self): |
721 return self._changectx.branch() | 829 return self._changectx.branch() |
830 | |
722 def extra(self): | 831 def extra(self): |
723 return self._changectx.extra() | 832 return self._changectx.extra() |
833 | |
724 def phase(self): | 834 def phase(self): |
725 return self._changectx.phase() | 835 return self._changectx.phase() |
836 | |
726 def phasestr(self): | 837 def phasestr(self): |
727 return self._changectx.phasestr() | 838 return self._changectx.phasestr() |
839 | |
728 def obsolete(self): | 840 def obsolete(self): |
729 return self._changectx.obsolete() | 841 return self._changectx.obsolete() |
842 | |
730 def instabilities(self): | 843 def instabilities(self): |
731 return self._changectx.instabilities() | 844 return self._changectx.instabilities() |
845 | |
732 def manifest(self): | 846 def manifest(self): |
733 return self._changectx.manifest() | 847 return self._changectx.manifest() |
848 | |
734 def changectx(self): | 849 def changectx(self): |
735 return self._changectx | 850 return self._changectx |
851 | |
736 def renamed(self): | 852 def renamed(self): |
737 return self._copied | 853 return self._copied |
854 | |
738 def copysource(self): | 855 def copysource(self): |
739 return self._copied and self._copied[0] | 856 return self._copied and self._copied[0] |
857 | |
740 def repo(self): | 858 def repo(self): |
741 return self._repo | 859 return self._repo |
860 | |
742 def size(self): | 861 def size(self): |
743 return len(self.data()) | 862 return len(self.data()) |
744 | 863 |
745 def path(self): | 864 def path(self): |
746 return self._path | 865 return self._path |
748 def isbinary(self): | 867 def isbinary(self): |
749 try: | 868 try: |
750 return stringutil.binary(self.data()) | 869 return stringutil.binary(self.data()) |
751 except IOError: | 870 except IOError: |
752 return False | 871 return False |
872 | |
753 def isexec(self): | 873 def isexec(self): |
754 return 'x' in self.flags() | 874 return 'x' in self.flags() |
875 | |
755 def islink(self): | 876 def islink(self): |
756 return 'l' in self.flags() | 877 return 'l' in self.flags() |
757 | 878 |
758 def isabsent(self): | 879 def isabsent(self): |
759 """whether this filectx represents a file not in self._changectx | 880 """whether this filectx represents a file not in self._changectx |
761 This is mainly for merge code to detect change/delete conflicts. This is | 882 This is mainly for merge code to detect change/delete conflicts. This is |
762 expected to be True for all subclasses of basectx.""" | 883 expected to be True for all subclasses of basectx.""" |
763 return False | 884 return False |
764 | 885 |
765 _customcmp = False | 886 _customcmp = False |
887 | |
766 def cmp(self, fctx): | 888 def cmp(self, fctx): |
767 """compare with other file context | 889 """compare with other file context |
768 | 890 |
769 returns True if different than fctx. | 891 returns True if different than fctx. |
770 """ | 892 """ |
771 if fctx._customcmp: | 893 if fctx._customcmp: |
772 return fctx.cmp(self) | 894 return fctx.cmp(self) |
773 | 895 |
774 if self._filenode is None: | 896 if self._filenode is None: |
775 raise error.ProgrammingError( | 897 raise error.ProgrammingError( |
776 'filectx.cmp() must be reimplemented if not backed by revlog') | 898 'filectx.cmp() must be reimplemented if not backed by revlog' |
899 ) | |
777 | 900 |
778 if fctx._filenode is None: | 901 if fctx._filenode is None: |
779 if self._repo._encodefilterpats: | 902 if self._repo._encodefilterpats: |
780 # can't rely on size() because wdir content may be decoded | 903 # can't rely on size() because wdir content may be decoded |
781 return self._filelog.cmp(self._filenode, fctx.data()) | 904 return self._filelog.cmp(self._filenode, fctx.data()) |
816 memberanc = getattr(self, '_ancestrycontext', None) | 939 memberanc = getattr(self, '_ancestrycontext', None) |
817 iteranc = None | 940 iteranc = None |
818 if srcrev is None: | 941 if srcrev is None: |
819 # wctx case, used by workingfilectx during mergecopy | 942 # wctx case, used by workingfilectx during mergecopy |
820 revs = [p.rev() for p in self._repo[None].parents()] | 943 revs = [p.rev() for p in self._repo[None].parents()] |
821 inclusive = True # we skipped the real (revless) source | 944 inclusive = True # we skipped the real (revless) source |
822 else: | 945 else: |
823 revs = [srcrev] | 946 revs = [srcrev] |
824 if memberanc is None: | 947 if memberanc is None: |
825 memberanc = iteranc = cl.ancestors(revs, lkr, | 948 memberanc = iteranc = cl.ancestors(revs, lkr, inclusive=inclusive) |
826 inclusive=inclusive) | |
827 # check if this linkrev is an ancestor of srcrev | 949 # check if this linkrev is an ancestor of srcrev |
828 if lkr not in memberanc: | 950 if lkr not in memberanc: |
829 if iteranc is None: | 951 if iteranc is None: |
830 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive) | 952 iteranc = cl.ancestors(revs, lkr, inclusive=inclusive) |
831 fnode = self._filenode | 953 fnode = self._filenode |
832 path = self._path | 954 path = self._path |
833 for a in iteranc: | 955 for a in iteranc: |
834 if stoprev is not None and a < stoprev: | 956 if stoprev is not None and a < stoprev: |
835 return None | 957 return None |
836 ac = cl.read(a) # get changeset data (we avoid object creation) | 958 ac = cl.read(a) # get changeset data (we avoid object creation) |
837 if path in ac[3]: # checking the 'files' field. | 959 if path in ac[3]: # checking the 'files' field. |
838 # The file has been touched, check if the content is | 960 # The file has been touched, check if the content is |
839 # similar to the one we search for. | 961 # similar to the one we search for. |
840 if fnode == mfl[ac[0]].readfast().get(path): | 962 if fnode == mfl[ac[0]].readfast().get(path): |
841 return a | 963 return a |
842 # In theory, we should never get out of that loop without a result. | 964 # In theory, we should never get out of that loop without a result. |
983 if getattr(base, '_ancestrycontext', None) is None: | 1105 if getattr(base, '_ancestrycontext', None) is None: |
984 cl = self._repo.changelog | 1106 cl = self._repo.changelog |
985 if base.rev() is None: | 1107 if base.rev() is None: |
986 # wctx is not inclusive, but works because _ancestrycontext | 1108 # wctx is not inclusive, but works because _ancestrycontext |
987 # is used to test filelog revisions | 1109 # is used to test filelog revisions |
988 ac = cl.ancestors([p.rev() for p in base.parents()], | 1110 ac = cl.ancestors( |
989 inclusive=True) | 1111 [p.rev() for p in base.parents()], inclusive=True |
1112 ) | |
990 else: | 1113 else: |
991 ac = cl.ancestors([base.rev()], inclusive=True) | 1114 ac = cl.ancestors([base.rev()], inclusive=True) |
992 base._ancestrycontext = ac | 1115 base._ancestrycontext = ac |
993 | 1116 |
994 return dagop.annotate(base, parents, skiprevs=skiprevs, | 1117 return dagop.annotate( |
995 diffopts=diffopts) | 1118 base, parents, skiprevs=skiprevs, diffopts=diffopts |
1119 ) | |
996 | 1120 |
997 def ancestors(self, followfirst=False): | 1121 def ancestors(self, followfirst=False): |
998 visit = {} | 1122 visit = {} |
999 c = self | 1123 c = self |
1000 if followfirst: | 1124 if followfirst: |
1015 | 1139 |
1016 This is often equivalent to how the data would be expressed on disk. | 1140 This is often equivalent to how the data would be expressed on disk. |
1017 """ | 1141 """ |
1018 return self._repo.wwritedata(self.path(), self.data()) | 1142 return self._repo.wwritedata(self.path(), self.data()) |
1019 | 1143 |
1144 | |
1020 class filectx(basefilectx): | 1145 class filectx(basefilectx): |
1021 """A filecontext object makes access to data related to a particular | 1146 """A filecontext object makes access to data related to a particular |
1022 filerevision convenient.""" | 1147 filerevision convenient.""" |
1023 def __init__(self, repo, path, changeid=None, fileid=None, | 1148 |
1024 filelog=None, changectx=None): | 1149 def __init__( |
1150 self, | |
1151 repo, | |
1152 path, | |
1153 changeid=None, | |
1154 fileid=None, | |
1155 filelog=None, | |
1156 changectx=None, | |
1157 ): | |
1025 """changeid must be a revision number, if specified. | 1158 """changeid must be a revision number, if specified. |
1026 fileid can be a file revision or node.""" | 1159 fileid can be a file revision or node.""" |
1027 self._repo = repo | 1160 self._repo = repo |
1028 self._path = path | 1161 self._path = path |
1029 | 1162 |
1030 assert (changeid is not None | 1163 assert ( |
1031 or fileid is not None | 1164 changeid is not None or fileid is not None or changectx is not None |
1032 or changectx is not None), ( | 1165 ), "bad args: changeid=%r, fileid=%r, changectx=%r" % ( |
1033 "bad args: changeid=%r, fileid=%r, changectx=%r" | 1166 changeid, |
1034 % (changeid, fileid, changectx)) | 1167 fileid, |
1168 changectx, | |
1169 ) | |
1035 | 1170 |
1036 if filelog is not None: | 1171 if filelog is not None: |
1037 self._filelog = filelog | 1172 self._filelog = filelog |
1038 | 1173 |
1039 if changeid is not None: | 1174 if changeid is not None: |
1067 return self._repo.unfiltered()[self._changeid] | 1202 return self._repo.unfiltered()[self._changeid] |
1068 | 1203 |
1069 def filectx(self, fileid, changeid=None): | 1204 def filectx(self, fileid, changeid=None): |
1070 '''opens an arbitrary revision of the file without | 1205 '''opens an arbitrary revision of the file without |
1071 opening a new filelog''' | 1206 opening a new filelog''' |
1072 return filectx(self._repo, self._path, fileid=fileid, | 1207 return filectx( |
1073 filelog=self._filelog, changeid=changeid) | 1208 self._repo, |
1209 self._path, | |
1210 fileid=fileid, | |
1211 filelog=self._filelog, | |
1212 changeid=changeid, | |
1213 ) | |
1074 | 1214 |
1075 def rawdata(self): | 1215 def rawdata(self): |
1076 return self._filelog.rawdata(self._filenode) | 1216 return self._filelog.rawdata(self._filenode) |
1077 | 1217 |
1078 def rawflags(self): | 1218 def rawflags(self): |
1083 try: | 1223 try: |
1084 return self._filelog.read(self._filenode) | 1224 return self._filelog.read(self._filenode) |
1085 except error.CensoredNodeError: | 1225 except error.CensoredNodeError: |
1086 if self._repo.ui.config("censor", "policy") == "ignore": | 1226 if self._repo.ui.config("censor", "policy") == "ignore": |
1087 return "" | 1227 return "" |
1088 raise error.Abort(_("censored node: %s") % short(self._filenode), | 1228 raise error.Abort( |
1089 hint=_("set censor.policy to ignore errors")) | 1229 _("censored node: %s") % short(self._filenode), |
1230 hint=_("set censor.policy to ignore errors"), | |
1231 ) | |
1090 | 1232 |
1091 def size(self): | 1233 def size(self): |
1092 return self._filelog.size(self._filerev) | 1234 return self._filelog.size(self._filerev) |
1093 | 1235 |
1094 @propertycache | 1236 @propertycache |
1118 return renamed | 1260 return renamed |
1119 | 1261 |
1120 def children(self): | 1262 def children(self): |
1121 # hard for renames | 1263 # hard for renames |
1122 c = self._filelog.children(self._filenode) | 1264 c = self._filelog.children(self._filenode) |
1123 return [filectx(self._repo, self._path, fileid=x, | 1265 return [ |
1124 filelog=self._filelog) for x in c] | 1266 filectx(self._repo, self._path, fileid=x, filelog=self._filelog) |
1267 for x in c | |
1268 ] | |
1269 | |
1125 | 1270 |
1126 class committablectx(basectx): | 1271 class committablectx(basectx): |
1127 """A committablectx object provides common functionality for a context that | 1272 """A committablectx object provides common functionality for a context that |
1128 wants the ability to commit, e.g. workingctx or memctx.""" | 1273 wants the ability to commit, e.g. workingctx or memctx.""" |
1129 def __init__(self, repo, text="", user=None, date=None, extra=None, | 1274 |
1130 changes=None, branch=None): | 1275 def __init__( |
1276 self, | |
1277 repo, | |
1278 text="", | |
1279 user=None, | |
1280 date=None, | |
1281 extra=None, | |
1282 changes=None, | |
1283 branch=None, | |
1284 ): | |
1131 super(committablectx, self).__init__(repo) | 1285 super(committablectx, self).__init__(repo) |
1132 self._rev = None | 1286 self._rev = None |
1133 self._node = None | 1287 self._node = None |
1134 self._text = text | 1288 self._text = text |
1135 if date: | 1289 if date: |
1176 def subrev(self, subpath): | 1330 def subrev(self, subpath): |
1177 return None | 1331 return None |
1178 | 1332 |
1179 def manifestnode(self): | 1333 def manifestnode(self): |
1180 return None | 1334 return None |
1335 | |
1181 def user(self): | 1336 def user(self): |
1182 return self._user or self._repo.ui.username() | 1337 return self._user or self._repo.ui.username() |
1338 | |
1183 def date(self): | 1339 def date(self): |
1184 return self._date | 1340 return self._date |
1341 | |
1185 def description(self): | 1342 def description(self): |
1186 return self._text | 1343 return self._text |
1344 | |
1187 def files(self): | 1345 def files(self): |
1188 return sorted(self._status.modified + self._status.added + | 1346 return sorted( |
1189 self._status.removed) | 1347 self._status.modified + self._status.added + self._status.removed |
1348 ) | |
1349 | |
1190 def modified(self): | 1350 def modified(self): |
1191 return self._status.modified | 1351 return self._status.modified |
1352 | |
1192 def added(self): | 1353 def added(self): |
1193 return self._status.added | 1354 return self._status.added |
1355 | |
1194 def removed(self): | 1356 def removed(self): |
1195 return self._status.removed | 1357 return self._status.removed |
1358 | |
1196 def deleted(self): | 1359 def deleted(self): |
1197 return self._status.deleted | 1360 return self._status.deleted |
1361 | |
1198 filesmodified = modified | 1362 filesmodified = modified |
1199 filesadded = added | 1363 filesadded = added |
1200 filesremoved = removed | 1364 filesremoved = removed |
1201 | 1365 |
1202 def branch(self): | 1366 def branch(self): |
1203 return encoding.tolocal(self._extra['branch']) | 1367 return encoding.tolocal(self._extra['branch']) |
1368 | |
1204 def closesbranch(self): | 1369 def closesbranch(self): |
1205 return 'close' in self._extra | 1370 return 'close' in self._extra |
1371 | |
1206 def extra(self): | 1372 def extra(self): |
1207 return self._extra | 1373 return self._extra |
1208 | 1374 |
1209 def isinmemory(self): | 1375 def isinmemory(self): |
1210 return False | 1376 return False |
1217 for p in self.parents(): | 1383 for p in self.parents(): |
1218 b.extend(p.bookmarks()) | 1384 b.extend(p.bookmarks()) |
1219 return b | 1385 return b |
1220 | 1386 |
1221 def phase(self): | 1387 def phase(self): |
1222 phase = phases.draft # default phase to draft | 1388 phase = phases.draft # default phase to draft |
1223 for p in self.parents(): | 1389 for p in self.parents(): |
1224 phase = max(phase, p.phase()) | 1390 phase = max(phase, p.phase()) |
1225 return phase | 1391 return phase |
1226 | 1392 |
1227 def hidden(self): | 1393 def hidden(self): |
1230 def children(self): | 1396 def children(self): |
1231 return [] | 1397 return [] |
1232 | 1398 |
1233 def ancestor(self, c2): | 1399 def ancestor(self, c2): |
1234 """return the "best" ancestor context of self and c2""" | 1400 """return the "best" ancestor context of self and c2""" |
1235 return self._parents[0].ancestor(c2) # punt on two parents for now | 1401 return self._parents[0].ancestor(c2) # punt on two parents for now |
1236 | 1402 |
1237 def ancestors(self): | 1403 def ancestors(self): |
1238 for p in self._parents: | 1404 for p in self._parents: |
1239 yield p | 1405 yield p |
1240 for a in self._repo.changelog.ancestors( | 1406 for a in self._repo.changelog.ancestors( |
1241 [p.rev() for p in self._parents]): | 1407 [p.rev() for p in self._parents] |
1408 ): | |
1242 yield self._repo[a] | 1409 yield self._repo[a] |
1243 | 1410 |
1244 def markcommitted(self, node): | 1411 def markcommitted(self, node): |
1245 """Perform post-commit cleanup necessary after committing this ctx | 1412 """Perform post-commit cleanup necessary after committing this ctx |
1246 | 1413 |
1251 | 1418 |
1252 """ | 1419 """ |
1253 | 1420 |
1254 def dirty(self, missing=False, merge=True, branch=True): | 1421 def dirty(self, missing=False, merge=True, branch=True): |
1255 return False | 1422 return False |
1423 | |
1256 | 1424 |
1257 class workingctx(committablectx): | 1425 class workingctx(committablectx): |
1258 """A workingctx object makes access to data related to | 1426 """A workingctx object makes access to data related to |
1259 the current working directory convenient. | 1427 the current working directory convenient. |
1260 date - any valid date string or (unixtime, offset), or None. | 1428 date - any valid date string or (unixtime, offset), or None. |
1261 user - username string, or None. | 1429 user - username string, or None. |
1262 extra - a dictionary of extra values, or None. | 1430 extra - a dictionary of extra values, or None. |
1263 changes - a list of file lists as returned by localrepo.status() | 1431 changes - a list of file lists as returned by localrepo.status() |
1264 or None to use the repository status. | 1432 or None to use the repository status. |
1265 """ | 1433 """ |
1266 def __init__(self, repo, text="", user=None, date=None, extra=None, | 1434 |
1267 changes=None): | 1435 def __init__( |
1436 self, repo, text="", user=None, date=None, extra=None, changes=None | |
1437 ): | |
1268 branch = None | 1438 branch = None |
1269 if not extra or 'branch' not in extra: | 1439 if not extra or 'branch' not in extra: |
1270 try: | 1440 try: |
1271 branch = repo.dirstate.branch() | 1441 branch = repo.dirstate.branch() |
1272 except UnicodeDecodeError: | 1442 except UnicodeDecodeError: |
1273 raise error.Abort(_('branch name not in UTF-8!')) | 1443 raise error.Abort(_('branch name not in UTF-8!')) |
1274 super(workingctx, self).__init__(repo, text, user, date, extra, changes, | 1444 super(workingctx, self).__init__( |
1275 branch=branch) | 1445 repo, text, user, date, extra, changes, branch=branch |
1446 ) | |
1276 | 1447 |
1277 def __iter__(self): | 1448 def __iter__(self): |
1278 d = self._repo.dirstate | 1449 d = self._repo.dirstate |
1279 for f in d: | 1450 for f in d: |
1280 if d[f] != 'r': | 1451 if d[f] != 'r': |
1307 copiesget = self._repo.dirstate.copies().get | 1478 copiesget = self._repo.dirstate.copies().get |
1308 parents = self.parents() | 1479 parents = self.parents() |
1309 if len(parents) < 2: | 1480 if len(parents) < 2: |
1310 # when we have one parent, it's easy: copy from parent | 1481 # when we have one parent, it's easy: copy from parent |
1311 man = parents[0].manifest() | 1482 man = parents[0].manifest() |
1483 | |
1312 def func(f): | 1484 def func(f): |
1313 f = copiesget(f, f) | 1485 f = copiesget(f, f) |
1314 return man.flags(f) | 1486 return man.flags(f) |
1487 | |
1315 else: | 1488 else: |
1316 # merges are tricky: we try to reconstruct the unstored | 1489 # merges are tricky: we try to reconstruct the unstored |
1317 # result from the merge (issue1802) | 1490 # result from the merge (issue1802) |
1318 p1, p2 = parents | 1491 p1, p2 = parents |
1319 pa = p1.ancestor(p2) | 1492 pa = p1.ancestor(p2) |
1320 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest() | 1493 m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest() |
1321 | 1494 |
1322 def func(f): | 1495 def func(f): |
1323 f = copiesget(f, f) # may be wrong for merges with copies | 1496 f = copiesget(f, f) # may be wrong for merges with copies |
1324 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f) | 1497 fl1, fl2, fla = m1.flags(f), m2.flags(f), ma.flags(f) |
1325 if fl1 == fl2: | 1498 if fl1 == fl2: |
1326 return fl1 | 1499 return fl1 |
1327 if fl1 == fla: | 1500 if fl1 == fla: |
1328 return fl2 | 1501 return fl2 |
1329 if fl2 == fla: | 1502 if fl2 == fla: |
1330 return fl1 | 1503 return fl1 |
1331 return '' # punt for conflicts | 1504 return '' # punt for conflicts |
1332 | 1505 |
1333 return func | 1506 return func |
1334 | 1507 |
1335 @propertycache | 1508 @propertycache |
1336 def _flagfunc(self): | 1509 def _flagfunc(self): |
1348 except OSError: | 1521 except OSError: |
1349 return '' | 1522 return '' |
1350 | 1523 |
1351 def filectx(self, path, filelog=None): | 1524 def filectx(self, path, filelog=None): |
1352 """get a file context from the working directory""" | 1525 """get a file context from the working directory""" |
1353 return workingfilectx(self._repo, path, workingctx=self, | 1526 return workingfilectx( |
1354 filelog=filelog) | 1527 self._repo, path, workingctx=self, filelog=filelog |
1528 ) | |
1355 | 1529 |
1356 def dirty(self, missing=False, merge=True, branch=True): | 1530 def dirty(self, missing=False, merge=True, branch=True): |
1357 "check whether a working directory is modified" | 1531 "check whether a working directory is modified" |
1358 # check subrepos first | 1532 # check subrepos first |
1359 for s in sorted(self.substate): | 1533 for s in sorted(self.substate): |
1360 if self.sub(s).dirty(missing=missing): | 1534 if self.sub(s).dirty(missing=missing): |
1361 return True | 1535 return True |
1362 # check current working dir | 1536 # check current working dir |
1363 return ((merge and self.p2()) or | 1537 return ( |
1364 (branch and self.branch() != self.p1().branch()) or | 1538 (merge and self.p2()) |
1365 self.modified() or self.added() or self.removed() or | 1539 or (branch and self.branch() != self.p1().branch()) |
1366 (missing and self.deleted())) | 1540 or self.modified() |
1541 or self.added() | |
1542 or self.removed() | |
1543 or (missing and self.deleted()) | |
1544 ) | |
1367 | 1545 |
1368 def add(self, list, prefix=""): | 1546 def add(self, list, prefix=""): |
1369 with self._repo.wlock(): | 1547 with self._repo.wlock(): |
1370 ui, ds = self._repo.ui, self._repo.dirstate | 1548 ui, ds = self._repo.ui, self._repo.dirstate |
1371 uipath = lambda f: ds.pathto(pathutil.join(prefix, f)) | 1549 uipath = lambda f: ds.pathto(pathutil.join(prefix, f)) |
1382 ui.warn(_("%s does not exist!\n") % uipath(f)) | 1560 ui.warn(_("%s does not exist!\n") % uipath(f)) |
1383 rejected.append(f) | 1561 rejected.append(f) |
1384 continue | 1562 continue |
1385 limit = ui.configbytes('ui', 'large-file-limit') | 1563 limit = ui.configbytes('ui', 'large-file-limit') |
1386 if limit != 0 and st.st_size > limit: | 1564 if limit != 0 and st.st_size > limit: |
1387 ui.warn(_("%s: up to %d MB of RAM may be required " | 1565 ui.warn( |
1388 "to manage this file\n" | 1566 _( |
1389 "(use 'hg revert %s' to cancel the " | 1567 "%s: up to %d MB of RAM may be required " |
1390 "pending addition)\n") | 1568 "to manage this file\n" |
1391 % (f, 3 * st.st_size // 1000000, uipath(f))) | 1569 "(use 'hg revert %s' to cancel the " |
1570 "pending addition)\n" | |
1571 ) | |
1572 % (f, 3 * st.st_size // 1000000, uipath(f)) | |
1573 ) | |
1392 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): | 1574 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): |
1393 ui.warn(_("%s not added: only files and symlinks " | 1575 ui.warn( |
1394 "supported currently\n") % uipath(f)) | 1576 _( |
1577 "%s not added: only files and symlinks " | |
1578 "supported currently\n" | |
1579 ) | |
1580 % uipath(f) | |
1581 ) | |
1395 rejected.append(f) | 1582 rejected.append(f) |
1396 elif ds[f] in 'amn': | 1583 elif ds[f] in 'amn': |
1397 ui.warn(_("%s already tracked!\n") % uipath(f)) | 1584 ui.warn(_("%s already tracked!\n") % uipath(f)) |
1398 elif ds[f] == 'r': | 1585 elif ds[f] == 'r': |
1399 ds.normallookup(f) | 1586 ds.normallookup(f) |
1420 try: | 1607 try: |
1421 st = self._repo.wvfs.lstat(dest) | 1608 st = self._repo.wvfs.lstat(dest) |
1422 except OSError as err: | 1609 except OSError as err: |
1423 if err.errno != errno.ENOENT: | 1610 if err.errno != errno.ENOENT: |
1424 raise | 1611 raise |
1425 self._repo.ui.warn(_("%s does not exist!\n") | 1612 self._repo.ui.warn( |
1426 % self._repo.dirstate.pathto(dest)) | 1613 _("%s does not exist!\n") % self._repo.dirstate.pathto(dest) |
1614 ) | |
1427 return | 1615 return |
1428 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): | 1616 if not (stat.S_ISREG(st.st_mode) or stat.S_ISLNK(st.st_mode)): |
1429 self._repo.ui.warn(_("copy failed: %s is not a file or a " | 1617 self._repo.ui.warn( |
1430 "symbolic link\n") | 1618 _("copy failed: %s is not a file or a " "symbolic link\n") |
1431 % self._repo.dirstate.pathto(dest)) | 1619 % self._repo.dirstate.pathto(dest) |
1620 ) | |
1432 else: | 1621 else: |
1433 with self._repo.wlock(): | 1622 with self._repo.wlock(): |
1434 ds = self._repo.dirstate | 1623 ds = self._repo.dirstate |
1435 if ds[dest] in '?': | 1624 if ds[dest] in '?': |
1436 ds.add(dest) | 1625 ds.add(dest) |
1437 elif ds[dest] in 'r': | 1626 elif ds[dest] in 'r': |
1438 ds.normallookup(dest) | 1627 ds.normallookup(dest) |
1439 ds.copy(source, dest) | 1628 ds.copy(source, dest) |
1440 | 1629 |
1441 def match(self, pats=None, include=None, exclude=None, default='glob', | 1630 def match( |
1442 listsubrepos=False, badfn=None): | 1631 self, |
1632 pats=None, | |
1633 include=None, | |
1634 exclude=None, | |
1635 default='glob', | |
1636 listsubrepos=False, | |
1637 badfn=None, | |
1638 ): | |
1443 r = self._repo | 1639 r = self._repo |
1444 | 1640 |
1445 # Only a case insensitive filesystem needs magic to translate user input | 1641 # Only a case insensitive filesystem needs magic to translate user input |
1446 # to actual case in the filesystem. | 1642 # to actual case in the filesystem. |
1447 icasefs = not util.fscasesensitive(r.root) | 1643 icasefs = not util.fscasesensitive(r.root) |
1448 return matchmod.match(r.root, r.getcwd(), pats, include, exclude, | 1644 return matchmod.match( |
1449 default, auditor=r.auditor, ctx=self, | 1645 r.root, |
1450 listsubrepos=listsubrepos, badfn=badfn, | 1646 r.getcwd(), |
1451 icasefs=icasefs) | 1647 pats, |
1648 include, | |
1649 exclude, | |
1650 default, | |
1651 auditor=r.auditor, | |
1652 ctx=self, | |
1653 listsubrepos=listsubrepos, | |
1654 badfn=badfn, | |
1655 icasefs=icasefs, | |
1656 ) | |
1452 | 1657 |
1453 def _filtersuspectsymlink(self, files): | 1658 def _filtersuspectsymlink(self, files): |
1454 if not files or self._repo.dirstate._checklink: | 1659 if not files or self._repo.dirstate._checklink: |
1455 return files | 1660 return files |
1456 | 1661 |
1460 # symlink | 1665 # symlink |
1461 sane = [] | 1666 sane = [] |
1462 for f in files: | 1667 for f in files: |
1463 if self.flags(f) == 'l': | 1668 if self.flags(f) == 'l': |
1464 d = self[f].data() | 1669 d = self[f].data() |
1465 if (d == '' or len(d) >= 1024 or '\n' in d | 1670 if ( |
1466 or stringutil.binary(d)): | 1671 d == '' |
1467 self._repo.ui.debug('ignoring suspect symlink placeholder' | 1672 or len(d) >= 1024 |
1468 ' "%s"\n' % f) | 1673 or '\n' in d |
1674 or stringutil.binary(d) | |
1675 ): | |
1676 self._repo.ui.debug( | |
1677 'ignoring suspect symlink placeholder' ' "%s"\n' % f | |
1678 ) | |
1469 continue | 1679 continue |
1470 sane.append(f) | 1680 sane.append(f) |
1471 return sane | 1681 return sane |
1472 | 1682 |
1473 def _checklookup(self, files): | 1683 def _checklookup(self, files): |
1482 # do a full compare of any files that might have changed | 1692 # do a full compare of any files that might have changed |
1483 for f in sorted(files): | 1693 for f in sorted(files): |
1484 try: | 1694 try: |
1485 # This will return True for a file that got replaced by a | 1695 # This will return True for a file that got replaced by a |
1486 # directory in the interim, but fixing that is pretty hard. | 1696 # directory in the interim, but fixing that is pretty hard. |
1487 if (f not in pctx or self.flags(f) != pctx.flags(f) | 1697 if ( |
1488 or pctx[f].cmp(self[f])): | 1698 f not in pctx |
1699 or self.flags(f) != pctx.flags(f) | |
1700 or pctx[f].cmp(self[f]) | |
1701 ): | |
1489 modified.append(f) | 1702 modified.append(f) |
1490 else: | 1703 else: |
1491 fixup.append(f) | 1704 fixup.append(f) |
1492 except (IOError, OSError): | 1705 except (IOError, OSError): |
1493 # A file become inaccessible in between? Mark it as deleted, | 1706 # A file become inaccessible in between? Mark it as deleted, |
1530 else: | 1743 else: |
1531 # in this case, writing changes out breaks | 1744 # in this case, writing changes out breaks |
1532 # consistency, because .hg/dirstate was | 1745 # consistency, because .hg/dirstate was |
1533 # already changed simultaneously after last | 1746 # already changed simultaneously after last |
1534 # caching (see also issue5584 for detail) | 1747 # caching (see also issue5584 for detail) |
1535 self._repo.ui.debug('skip updating dirstate: ' | 1748 self._repo.ui.debug( |
1536 'identity mismatch\n') | 1749 'skip updating dirstate: ' 'identity mismatch\n' |
1750 ) | |
1537 except error.LockError: | 1751 except error.LockError: |
1538 pass | 1752 pass |
1539 finally: | 1753 finally: |
1540 # Even if the wlock couldn't be grabbed, clear out the list. | 1754 # Even if the wlock couldn't be grabbed, clear out the list. |
1541 self._repo.clearpostdsstatus() | 1755 self._repo.clearpostdsstatus() |
1543 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False): | 1757 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False): |
1544 '''Gets the status from the dirstate -- internal use only.''' | 1758 '''Gets the status from the dirstate -- internal use only.''' |
1545 subrepos = [] | 1759 subrepos = [] |
1546 if '.hgsub' in self: | 1760 if '.hgsub' in self: |
1547 subrepos = sorted(self.substate) | 1761 subrepos = sorted(self.substate) |
1548 cmp, s = self._repo.dirstate.status(match, subrepos, ignored=ignored, | 1762 cmp, s = self._repo.dirstate.status( |
1549 clean=clean, unknown=unknown) | 1763 match, subrepos, ignored=ignored, clean=clean, unknown=unknown |
1764 ) | |
1550 | 1765 |
1551 # check for any possibly clean files | 1766 # check for any possibly clean files |
1552 fixup = [] | 1767 fixup = [] |
1553 if cmp: | 1768 if cmp: |
1554 modified2, deleted2, fixup = self._checklookup(cmp) | 1769 modified2, deleted2, fixup = self._checklookup(cmp) |
1562 | 1777 |
1563 if match.always(): | 1778 if match.always(): |
1564 # cache for performance | 1779 # cache for performance |
1565 if s.unknown or s.ignored or s.clean: | 1780 if s.unknown or s.ignored or s.clean: |
1566 # "_status" is cached with list*=False in the normal route | 1781 # "_status" is cached with list*=False in the normal route |
1567 self._status = scmutil.status(s.modified, s.added, s.removed, | 1782 self._status = scmutil.status( |
1568 s.deleted, [], [], []) | 1783 s.modified, s.added, s.removed, s.deleted, [], [], [] |
1784 ) | |
1569 else: | 1785 else: |
1570 self._status = s | 1786 self._status = s |
1571 | 1787 |
1572 return s | 1788 return s |
1573 | 1789 |
1605 parents = self.parents() | 1821 parents = self.parents() |
1606 | 1822 |
1607 man = parents[0].manifest().copy() | 1823 man = parents[0].manifest().copy() |
1608 | 1824 |
1609 ff = self._flagfunc | 1825 ff = self._flagfunc |
1610 for i, l in ((addednodeid, status.added), | 1826 for i, l in ( |
1611 (modifiednodeid, status.modified)): | 1827 (addednodeid, status.added), |
1828 (modifiednodeid, status.modified), | |
1829 ): | |
1612 for f in l: | 1830 for f in l: |
1613 man[f] = i | 1831 man[f] = i |
1614 try: | 1832 try: |
1615 man.setflag(f, ff(f)) | 1833 man.setflag(f, ff(f)) |
1616 except OSError: | 1834 except OSError: |
1620 if f in man: | 1838 if f in man: |
1621 del man[f] | 1839 del man[f] |
1622 | 1840 |
1623 return man | 1841 return man |
1624 | 1842 |
1625 def _buildstatus(self, other, s, match, listignored, listclean, | 1843 def _buildstatus( |
1626 listunknown): | 1844 self, other, s, match, listignored, listclean, listunknown |
1845 ): | |
1627 """build a status with respect to another context | 1846 """build a status with respect to another context |
1628 | 1847 |
1629 This includes logic for maintaining the fast path of status when | 1848 This includes logic for maintaining the fast path of status when |
1630 comparing the working directory against its parent, which is to skip | 1849 comparing the working directory against its parent, which is to skip |
1631 building a new manifest if self (working directory) is not comparing | 1850 building a new manifest if self (working directory) is not comparing |
1635 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems, | 1854 # Filter out symlinks that, in the case of FAT32 and NTFS filesystems, |
1636 # might have accidentally ended up with the entire contents of the file | 1855 # might have accidentally ended up with the entire contents of the file |
1637 # they are supposed to be linking to. | 1856 # they are supposed to be linking to. |
1638 s.modified[:] = self._filtersuspectsymlink(s.modified) | 1857 s.modified[:] = self._filtersuspectsymlink(s.modified) |
1639 if other != self._repo['.']: | 1858 if other != self._repo['.']: |
1640 s = super(workingctx, self)._buildstatus(other, s, match, | 1859 s = super(workingctx, self)._buildstatus( |
1641 listignored, listclean, | 1860 other, s, match, listignored, listclean, listunknown |
1642 listunknown) | 1861 ) |
1643 return s | 1862 return s |
1644 | 1863 |
1645 def _matchstatus(self, other, match): | 1864 def _matchstatus(self, other, match): |
1646 """override the match method with a filter for directory patterns | 1865 """override the match method with a filter for directory patterns |
1647 | 1866 |
1651 | 1870 |
1652 If we aren't comparing against the working directory's parent, then we | 1871 If we aren't comparing against the working directory's parent, then we |
1653 just use the default match object sent to us. | 1872 just use the default match object sent to us. |
1654 """ | 1873 """ |
1655 if other != self._repo['.']: | 1874 if other != self._repo['.']: |
1875 | |
1656 def bad(f, msg): | 1876 def bad(f, msg): |
1657 # 'f' may be a directory pattern from 'match.files()', | 1877 # 'f' may be a directory pattern from 'match.files()', |
1658 # so 'f not in ctx1' is not enough | 1878 # so 'f not in ctx1' is not enough |
1659 if f not in other and not other.hasdir(f): | 1879 if f not in other and not other.hasdir(f): |
1660 self._repo.ui.warn('%s: %s\n' % | 1880 self._repo.ui.warn( |
1661 (self._repo.dirstate.pathto(f), msg)) | 1881 '%s: %s\n' % (self._repo.dirstate.pathto(f), msg) |
1882 ) | |
1883 | |
1662 match.bad = bad | 1884 match.bad = bad |
1663 return match | 1885 return match |
1664 | 1886 |
1665 def walk(self, match): | 1887 def walk(self, match): |
1666 '''Generates matching file names.''' | 1888 '''Generates matching file names.''' |
1667 return sorted(self._repo.dirstate.walk(self._repo.narrowmatch(match), | 1889 return sorted( |
1668 subrepos=sorted(self.substate), | 1890 self._repo.dirstate.walk( |
1669 unknown=True, ignored=False)) | 1891 self._repo.narrowmatch(match), |
1892 subrepos=sorted(self.substate), | |
1893 unknown=True, | |
1894 ignored=False, | |
1895 ) | |
1896 ) | |
1670 | 1897 |
1671 def matches(self, match): | 1898 def matches(self, match): |
1672 match = self._repo.narrowmatch(match) | 1899 match = self._repo.narrowmatch(match) |
1673 ds = self._repo.dirstate | 1900 ds = self._repo.dirstate |
1674 return sorted(f for f in ds.matches(match) if ds[f] != 'r') | 1901 return sorted(f for f in ds.matches(match) if ds[f] != 'r') |
1686 # from immediately doing so for subsequent changing files | 1913 # from immediately doing so for subsequent changing files |
1687 self._repo.dirstate.write(self._repo.currenttransaction()) | 1914 self._repo.dirstate.write(self._repo.currenttransaction()) |
1688 | 1915 |
1689 sparse.aftercommit(self._repo, node) | 1916 sparse.aftercommit(self._repo, node) |
1690 | 1917 |
1918 | |
1691 class committablefilectx(basefilectx): | 1919 class committablefilectx(basefilectx): |
1692 """A committablefilectx provides common functionality for a file context | 1920 """A committablefilectx provides common functionality for a file context |
1693 that wants the ability to commit, e.g. workingfilectx or memfilectx.""" | 1921 that wants the ability to commit, e.g. workingfilectx or memfilectx.""" |
1922 | |
1694 def __init__(self, repo, path, filelog=None, ctx=None): | 1923 def __init__(self, repo, path, filelog=None, ctx=None): |
1695 self._repo = repo | 1924 self._repo = repo |
1696 self._path = path | 1925 self._path = path |
1697 self._changeid = None | 1926 self._changeid = None |
1698 self._filerev = self._filenode = None | 1927 self._filerev = self._filenode = None |
1717 return None | 1946 return None |
1718 return path, self._changectx._parents[0]._manifest.get(path, nullid) | 1947 return path, self._changectx._parents[0]._manifest.get(path, nullid) |
1719 | 1948 |
1720 def parents(self): | 1949 def parents(self): |
1721 '''return parent filectxs, following copies if necessary''' | 1950 '''return parent filectxs, following copies if necessary''' |
1951 | |
1722 def filenode(ctx, path): | 1952 def filenode(ctx, path): |
1723 return ctx._manifest.get(path, nullid) | 1953 return ctx._manifest.get(path, nullid) |
1724 | 1954 |
1725 path = self._path | 1955 path = self._path |
1726 fl = self._filelog | 1956 fl = self._filelog |
1733 pl = [(path, filenode(pcl[0], path), fl)] | 1963 pl = [(path, filenode(pcl[0], path), fl)] |
1734 | 1964 |
1735 for pc in pcl[1:]: | 1965 for pc in pcl[1:]: |
1736 pl.append((path, filenode(pc, path), fl)) | 1966 pl.append((path, filenode(pc, path), fl)) |
1737 | 1967 |
1738 return [self._parentfilectx(p, fileid=n, filelog=l) | 1968 return [ |
1739 for p, n, l in pl if n != nullid] | 1969 self._parentfilectx(p, fileid=n, filelog=l) |
1970 for p, n, l in pl | |
1971 if n != nullid | |
1972 ] | |
1740 | 1973 |
1741 def children(self): | 1974 def children(self): |
1742 return [] | 1975 return [] |
1976 | |
1743 | 1977 |
1744 class workingfilectx(committablefilectx): | 1978 class workingfilectx(committablefilectx): |
1745 """A workingfilectx object makes access to data related to a particular | 1979 """A workingfilectx object makes access to data related to a particular |
1746 file in the working directory convenient.""" | 1980 file in the working directory convenient.""" |
1981 | |
1747 def __init__(self, repo, path, filelog=None, workingctx=None): | 1982 def __init__(self, repo, path, filelog=None, workingctx=None): |
1748 super(workingfilectx, self).__init__(repo, path, filelog, workingctx) | 1983 super(workingfilectx, self).__init__(repo, path, filelog, workingctx) |
1749 | 1984 |
1750 @propertycache | 1985 @propertycache |
1751 def _changectx(self): | 1986 def _changectx(self): |
1752 return workingctx(self._repo) | 1987 return workingctx(self._repo) |
1753 | 1988 |
1754 def data(self): | 1989 def data(self): |
1755 return self._repo.wread(self._path) | 1990 return self._repo.wread(self._path) |
1991 | |
1756 def copysource(self): | 1992 def copysource(self): |
1757 return self._repo.dirstate.copied(self._path) | 1993 return self._repo.dirstate.copied(self._path) |
1758 | 1994 |
1759 def size(self): | 1995 def size(self): |
1760 return self._repo.wvfs.lstat(self._path).st_size | 1996 return self._repo.wvfs.lstat(self._path).st_size |
1997 | |
1761 def lstat(self): | 1998 def lstat(self): |
1762 return self._repo.wvfs.lstat(self._path) | 1999 return self._repo.wvfs.lstat(self._path) |
2000 | |
1763 def date(self): | 2001 def date(self): |
1764 t, tz = self._changectx.date() | 2002 t, tz = self._changectx.date() |
1765 try: | 2003 try: |
1766 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz) | 2004 return (self._repo.wvfs.lstat(self._path)[stat.ST_MTIME], tz) |
1767 except OSError as err: | 2005 except OSError as err: |
1788 return fctx.cmp(self) | 2026 return fctx.cmp(self) |
1789 | 2027 |
1790 def remove(self, ignoremissing=False): | 2028 def remove(self, ignoremissing=False): |
1791 """wraps unlink for a repo's working directory""" | 2029 """wraps unlink for a repo's working directory""" |
1792 rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs') | 2030 rmdir = self._repo.ui.configbool('experimental', 'removeemptydirs') |
1793 self._repo.wvfs.unlinkpath(self._path, ignoremissing=ignoremissing, | 2031 self._repo.wvfs.unlinkpath( |
1794 rmdir=rmdir) | 2032 self._path, ignoremissing=ignoremissing, rmdir=rmdir |
2033 ) | |
1795 | 2034 |
1796 def write(self, data, flags, backgroundclose=False, **kwargs): | 2035 def write(self, data, flags, backgroundclose=False, **kwargs): |
1797 """wraps repo.wwrite""" | 2036 """wraps repo.wwrite""" |
1798 return self._repo.wwrite(self._path, data, flags, | 2037 return self._repo.wwrite( |
1799 backgroundclose=backgroundclose, | 2038 self._path, data, flags, backgroundclose=backgroundclose, **kwargs |
1800 **kwargs) | 2039 ) |
1801 | 2040 |
1802 def markcopied(self, src): | 2041 def markcopied(self, src): |
1803 """marks this file a copy of `src`""" | 2042 """marks this file a copy of `src`""" |
1804 self._repo.dirstate.copy(src, self._path) | 2043 self._repo.dirstate.copy(src, self._path) |
1805 | 2044 |
1825 wvfs.removedirs(f) | 2064 wvfs.removedirs(f) |
1826 | 2065 |
1827 def setflags(self, l, x): | 2066 def setflags(self, l, x): |
1828 self._repo.wvfs.setflags(self._path, l, x) | 2067 self._repo.wvfs.setflags(self._path, l, x) |
1829 | 2068 |
2069 | |
1830 class overlayworkingctx(committablectx): | 2070 class overlayworkingctx(committablectx): |
1831 """Wraps another mutable context with a write-back cache that can be | 2071 """Wraps another mutable context with a write-back cache that can be |
1832 converted into a commit context. | 2072 converted into a commit context. |
1833 | 2073 |
1834 self._cache[path] maps to a dict with keys: { | 2074 self._cache[path] maps to a dict with keys: { |
1861 return self._cache[path]['data'] | 2101 return self._cache[path]['data'] |
1862 else: | 2102 else: |
1863 # Must fallback here, too, because we only set flags. | 2103 # Must fallback here, too, because we only set flags. |
1864 return self._wrappedctx[path].data() | 2104 return self._wrappedctx[path].data() |
1865 else: | 2105 else: |
1866 raise error.ProgrammingError("No such file or directory: %s" % | 2106 raise error.ProgrammingError( |
1867 path) | 2107 "No such file or directory: %s" % path |
2108 ) | |
1868 else: | 2109 else: |
1869 return self._wrappedctx[path].data() | 2110 return self._wrappedctx[path].data() |
1870 | 2111 |
1871 @propertycache | 2112 @propertycache |
1872 def _manifest(self): | 2113 def _manifest(self): |
1886 | 2127 |
1887 @propertycache | 2128 @propertycache |
1888 def _flagfunc(self): | 2129 def _flagfunc(self): |
1889 def f(path): | 2130 def f(path): |
1890 return self._cache[path]['flags'] | 2131 return self._cache[path]['flags'] |
2132 | |
1891 return f | 2133 return f |
1892 | 2134 |
1893 def files(self): | 2135 def files(self): |
1894 return sorted(self.added() + self.modified() + self.removed()) | 2136 return sorted(self.added() + self.modified() + self.removed()) |
1895 | 2137 |
1896 def modified(self): | 2138 def modified(self): |
1897 return [f for f in self._cache.keys() if self._cache[f]['exists'] and | 2139 return [ |
1898 self._existsinparent(f)] | 2140 f |
2141 for f in self._cache.keys() | |
2142 if self._cache[f]['exists'] and self._existsinparent(f) | |
2143 ] | |
1899 | 2144 |
1900 def added(self): | 2145 def added(self): |
1901 return [f for f in self._cache.keys() if self._cache[f]['exists'] and | 2146 return [ |
1902 not self._existsinparent(f)] | 2147 f |
2148 for f in self._cache.keys() | |
2149 if self._cache[f]['exists'] and not self._existsinparent(f) | |
2150 ] | |
1903 | 2151 |
1904 def removed(self): | 2152 def removed(self): |
1905 return [f for f in self._cache.keys() if | 2153 return [ |
1906 not self._cache[f]['exists'] and self._existsinparent(f)] | 2154 f |
2155 for f in self._cache.keys() | |
2156 if not self._cache[f]['exists'] and self._existsinparent(f) | |
2157 ] | |
1907 | 2158 |
1908 def p1copies(self): | 2159 def p1copies(self): |
1909 copies = self._repo._wrappedctx.p1copies().copy() | 2160 copies = self._repo._wrappedctx.p1copies().copy() |
1910 narrowmatch = self._repo.narrowmatch() | 2161 narrowmatch = self._repo.narrowmatch() |
1911 for f in self._cache.keys(): | 2162 for f in self._cache.keys(): |
1912 if not narrowmatch(f): | 2163 if not narrowmatch(f): |
1913 continue | 2164 continue |
1914 copies.pop(f, None) # delete if it exists | 2165 copies.pop(f, None) # delete if it exists |
1915 source = self._cache[f]['copied'] | 2166 source = self._cache[f]['copied'] |
1916 if source: | 2167 if source: |
1917 copies[f] = source | 2168 copies[f] = source |
1918 return copies | 2169 return copies |
1919 | 2170 |
1921 copies = self._repo._wrappedctx.p2copies().copy() | 2172 copies = self._repo._wrappedctx.p2copies().copy() |
1922 narrowmatch = self._repo.narrowmatch() | 2173 narrowmatch = self._repo.narrowmatch() |
1923 for f in self._cache.keys(): | 2174 for f in self._cache.keys(): |
1924 if not narrowmatch(f): | 2175 if not narrowmatch(f): |
1925 continue | 2176 continue |
1926 copies.pop(f, None) # delete if it exists | 2177 copies.pop(f, None) # delete if it exists |
1927 source = self._cache[f]['copied'] | 2178 source = self._cache[f]['copied'] |
1928 if source: | 2179 if source: |
1929 copies[f] = source | 2180 copies[f] = source |
1930 return copies | 2181 return copies |
1931 | 2182 |
1937 return self._cache[path]['date'] | 2188 return self._cache[path]['date'] |
1938 else: | 2189 else: |
1939 return self._wrappedctx[path].date() | 2190 return self._wrappedctx[path].date() |
1940 | 2191 |
1941 def markcopied(self, path, origin): | 2192 def markcopied(self, path, origin): |
1942 self._markdirty(path, exists=True, date=self.filedate(path), | 2193 self._markdirty( |
1943 flags=self.flags(path), copied=origin) | 2194 path, |
2195 exists=True, | |
2196 date=self.filedate(path), | |
2197 flags=self.flags(path), | |
2198 copied=origin, | |
2199 ) | |
1944 | 2200 |
1945 def copydata(self, path): | 2201 def copydata(self, path): |
1946 if self.isdirty(path): | 2202 if self.isdirty(path): |
1947 return self._cache[path]['copied'] | 2203 return self._cache[path]['copied'] |
1948 else: | 2204 else: |
1951 def flags(self, path): | 2207 def flags(self, path): |
1952 if self.isdirty(path): | 2208 if self.isdirty(path): |
1953 if self._cache[path]['exists']: | 2209 if self._cache[path]['exists']: |
1954 return self._cache[path]['flags'] | 2210 return self._cache[path]['flags'] |
1955 else: | 2211 else: |
1956 raise error.ProgrammingError("No such file or directory: %s" % | 2212 raise error.ProgrammingError( |
1957 self._path) | 2213 "No such file or directory: %s" % self._path |
2214 ) | |
1958 else: | 2215 else: |
1959 return self._wrappedctx[path].flags() | 2216 return self._wrappedctx[path].flags() |
1960 | 2217 |
1961 def __contains__(self, key): | 2218 def __contains__(self, key): |
1962 if key in self._cache: | 2219 if key in self._cache: |
1978 | 2235 |
1979 Since we never write to the filesystem and never call `applyupdates` in | 2236 Since we never write to the filesystem and never call `applyupdates` in |
1980 IMM, we'll never check that a path is actually writable -- e.g., because | 2237 IMM, we'll never check that a path is actually writable -- e.g., because |
1981 it adds `a/foo`, but `a` is actually a file in the other commit. | 2238 it adds `a/foo`, but `a` is actually a file in the other commit. |
1982 """ | 2239 """ |
2240 | |
1983 def fail(path, component): | 2241 def fail(path, component): |
1984 # p1() is the base and we're receiving "writes" for p2()'s | 2242 # p1() is the base and we're receiving "writes" for p2()'s |
1985 # files. | 2243 # files. |
1986 if 'l' in self.p1()[component].flags(): | 2244 if 'l' in self.p1()[component].flags(): |
1987 raise error.Abort("error: %s conflicts with symlink %s " | 2245 raise error.Abort( |
1988 "in %d." % (path, component, | 2246 "error: %s conflicts with symlink %s " |
1989 self.p1().rev())) | 2247 "in %d." % (path, component, self.p1().rev()) |
2248 ) | |
1990 else: | 2249 else: |
1991 raise error.Abort("error: '%s' conflicts with file '%s' in " | 2250 raise error.Abort( |
1992 "%d." % (path, component, | 2251 "error: '%s' conflicts with file '%s' in " |
1993 self.p1().rev())) | 2252 "%d." % (path, component, self.p1().rev()) |
2253 ) | |
1994 | 2254 |
1995 # Test that each new directory to be created to write this path from p2 | 2255 # Test that each new directory to be created to write this path from p2 |
1996 # is not a file in p1. | 2256 # is not a file in p1. |
1997 components = path.split('/') | 2257 components = path.split('/') |
1998 for i in pycompat.xrange(len(components)): | 2258 for i in pycompat.xrange(len(components)): |
2010 return | 2270 return |
2011 # omit the files which are deleted in current IMM wctx | 2271 # omit the files which are deleted in current IMM wctx |
2012 mfiles = [m for m in mfiles if m in self] | 2272 mfiles = [m for m in mfiles if m in self] |
2013 if not mfiles: | 2273 if not mfiles: |
2014 return | 2274 return |
2015 raise error.Abort("error: file '%s' cannot be written because " | 2275 raise error.Abort( |
2016 " '%s/' is a directory in %s (containing %d " | 2276 "error: file '%s' cannot be written because " |
2017 "entries: %s)" | 2277 " '%s/' is a directory in %s (containing %d " |
2018 % (path, path, self.p1(), len(mfiles), | 2278 "entries: %s)" |
2019 ', '.join(mfiles))) | 2279 % (path, path, self.p1(), len(mfiles), ', '.join(mfiles)) |
2280 ) | |
2020 | 2281 |
2021 def write(self, path, data, flags='', **kwargs): | 2282 def write(self, path, data, flags='', **kwargs): |
2022 if data is None: | 2283 if data is None: |
2023 raise error.ProgrammingError("data must be non-None") | 2284 raise error.ProgrammingError("data must be non-None") |
2024 self._auditconflicts(path) | 2285 self._auditconflicts(path) |
2025 self._markdirty(path, exists=True, data=data, date=dateutil.makedate(), | 2286 self._markdirty( |
2026 flags=flags) | 2287 path, exists=True, data=data, date=dateutil.makedate(), flags=flags |
2288 ) | |
2027 | 2289 |
2028 def setflags(self, path, l, x): | 2290 def setflags(self, path, l, x): |
2029 flag = '' | 2291 flag = '' |
2030 if l: | 2292 if l: |
2031 flag = 'l' | 2293 flag = 'l' |
2032 elif x: | 2294 elif x: |
2033 flag = 'x' | 2295 flag = 'x' |
2034 self._markdirty(path, exists=True, date=dateutil.makedate(), | 2296 self._markdirty(path, exists=True, date=dateutil.makedate(), flags=flag) |
2035 flags=flag) | |
2036 | 2297 |
2037 def remove(self, path): | 2298 def remove(self, path): |
2038 self._markdirty(path, exists=False) | 2299 self._markdirty(path, exists=False) |
2039 | 2300 |
2040 def exists(self, path): | 2301 def exists(self, path): |
2042 return False if they are broken. | 2303 return False if they are broken. |
2043 """ | 2304 """ |
2044 if self.isdirty(path): | 2305 if self.isdirty(path): |
2045 # If this path exists and is a symlink, "follow" it by calling | 2306 # If this path exists and is a symlink, "follow" it by calling |
2046 # exists on the destination path. | 2307 # exists on the destination path. |
2047 if (self._cache[path]['exists'] and | 2308 if ( |
2048 'l' in self._cache[path]['flags']): | 2309 self._cache[path]['exists'] |
2310 and 'l' in self._cache[path]['flags'] | |
2311 ): | |
2049 return self.exists(self._cache[path]['data'].strip()) | 2312 return self.exists(self._cache[path]['data'].strip()) |
2050 else: | 2313 else: |
2051 return self._cache[path]['exists'] | 2314 return self._cache[path]['exists'] |
2052 | 2315 |
2053 return self._existsinparent(path) | 2316 return self._existsinparent(path) |
2062 def size(self, path): | 2325 def size(self, path): |
2063 if self.isdirty(path): | 2326 if self.isdirty(path): |
2064 if self._cache[path]['exists']: | 2327 if self._cache[path]['exists']: |
2065 return len(self._cache[path]['data']) | 2328 return len(self._cache[path]['data']) |
2066 else: | 2329 else: |
2067 raise error.ProgrammingError("No such file or directory: %s" % | 2330 raise error.ProgrammingError( |
2068 self._path) | 2331 "No such file or directory: %s" % self._path |
2332 ) | |
2069 return self._wrappedctx[path].size() | 2333 return self._wrappedctx[path].size() |
2070 | 2334 |
2071 def tomemctx(self, text, branch=None, extra=None, date=None, parents=None, | 2335 def tomemctx( |
2072 user=None, editor=None): | 2336 self, |
2337 text, | |
2338 branch=None, | |
2339 extra=None, | |
2340 date=None, | |
2341 parents=None, | |
2342 user=None, | |
2343 editor=None, | |
2344 ): | |
2073 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be | 2345 """Converts this ``overlayworkingctx`` into a ``memctx`` ready to be |
2074 committed. | 2346 committed. |
2075 | 2347 |
2076 ``text`` is the commit message. | 2348 ``text`` is the commit message. |
2077 ``parents`` (optional) are rev numbers. | 2349 ``parents`` (optional) are rev numbers. |
2087 parents = (self._repo[parents[0]], None) | 2359 parents = (self._repo[parents[0]], None) |
2088 else: | 2360 else: |
2089 parents = (self._repo[parents[0]], self._repo[parents[1]]) | 2361 parents = (self._repo[parents[0]], self._repo[parents[1]]) |
2090 | 2362 |
2091 files = self.files() | 2363 files = self.files() |
2364 | |
2092 def getfile(repo, memctx, path): | 2365 def getfile(repo, memctx, path): |
2093 if self._cache[path]['exists']: | 2366 if self._cache[path]['exists']: |
2094 return memfilectx(repo, memctx, path, | 2367 return memfilectx( |
2095 self._cache[path]['data'], | 2368 repo, |
2096 'l' in self._cache[path]['flags'], | 2369 memctx, |
2097 'x' in self._cache[path]['flags'], | 2370 path, |
2098 self._cache[path]['copied']) | 2371 self._cache[path]['data'], |
2372 'l' in self._cache[path]['flags'], | |
2373 'x' in self._cache[path]['flags'], | |
2374 self._cache[path]['copied'], | |
2375 ) | |
2099 else: | 2376 else: |
2100 # Returning None, but including the path in `files`, is | 2377 # Returning None, but including the path in `files`, is |
2101 # necessary for memctx to register a deletion. | 2378 # necessary for memctx to register a deletion. |
2102 return None | 2379 return None |
2103 return memctx(self._repo, parents, text, files, getfile, date=date, | 2380 |
2104 extra=extra, user=user, branch=branch, editor=editor) | 2381 return memctx( |
2382 self._repo, | |
2383 parents, | |
2384 text, | |
2385 files, | |
2386 getfile, | |
2387 date=date, | |
2388 extra=extra, | |
2389 user=user, | |
2390 branch=branch, | |
2391 editor=editor, | |
2392 ) | |
2105 | 2393 |
2106 def isdirty(self, path): | 2394 def isdirty(self, path): |
2107 return path in self._cache | 2395 return path in self._cache |
2108 | 2396 |
2109 def isempty(self): | 2397 def isempty(self): |
2124 """ | 2412 """ |
2125 keys = [] | 2413 keys = [] |
2126 # This won't be perfect, but can help performance significantly when | 2414 # This won't be perfect, but can help performance significantly when |
2127 # using things like remotefilelog. | 2415 # using things like remotefilelog. |
2128 scmutil.prefetchfiles( | 2416 scmutil.prefetchfiles( |
2129 self.repo(), [self.p1().rev()], | 2417 self.repo(), |
2130 scmutil.matchfiles(self.repo(), self._cache.keys())) | 2418 [self.p1().rev()], |
2419 scmutil.matchfiles(self.repo(), self._cache.keys()), | |
2420 ) | |
2131 | 2421 |
2132 for path in self._cache.keys(): | 2422 for path in self._cache.keys(): |
2133 cache = self._cache[path] | 2423 cache = self._cache[path] |
2134 try: | 2424 try: |
2135 underlying = self._wrappedctx[path] | 2425 underlying = self._wrappedctx[path] |
2136 if (underlying.data() == cache['data'] and | 2426 if ( |
2137 underlying.flags() == cache['flags']): | 2427 underlying.data() == cache['data'] |
2428 and underlying.flags() == cache['flags'] | |
2429 ): | |
2138 keys.append(path) | 2430 keys.append(path) |
2139 except error.ManifestLookupError: | 2431 except error.ManifestLookupError: |
2140 # Path not in the underlying manifest (created). | 2432 # Path not in the underlying manifest (created). |
2141 continue | 2433 continue |
2142 | 2434 |
2143 for path in keys: | 2435 for path in keys: |
2144 del self._cache[path] | 2436 del self._cache[path] |
2145 return keys | 2437 return keys |
2146 | 2438 |
2147 def _markdirty(self, path, exists, data=None, date=None, flags='', | 2439 def _markdirty( |
2148 copied=None): | 2440 self, path, exists, data=None, date=None, flags='', copied=None |
2441 ): | |
2149 # data not provided, let's see if we already have some; if not, let's | 2442 # data not provided, let's see if we already have some; if not, let's |
2150 # grab it from our underlying context, so that we always have data if | 2443 # grab it from our underlying context, so that we always have data if |
2151 # the file is marked as existing. | 2444 # the file is marked as existing. |
2152 if exists and data is None: | 2445 if exists and data is None: |
2153 oldentry = self._cache.get(path) or {} | 2446 oldentry = self._cache.get(path) or {} |
2162 'flags': flags, | 2455 'flags': flags, |
2163 'copied': copied, | 2456 'copied': copied, |
2164 } | 2457 } |
2165 | 2458 |
2166 def filectx(self, path, filelog=None): | 2459 def filectx(self, path, filelog=None): |
2167 return overlayworkingfilectx(self._repo, path, parent=self, | 2460 return overlayworkingfilectx( |
2168 filelog=filelog) | 2461 self._repo, path, parent=self, filelog=filelog |
2462 ) | |
2463 | |
2169 | 2464 |
2170 class overlayworkingfilectx(committablefilectx): | 2465 class overlayworkingfilectx(committablefilectx): |
2171 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory | 2466 """Wrap a ``workingfilectx`` but intercepts all writes into an in-memory |
2172 cache, which can be flushed through later by calling ``flush()``.""" | 2467 cache, which can be flushed through later by calling ``flush()``.""" |
2173 | 2468 |
2174 def __init__(self, repo, path, filelog=None, parent=None): | 2469 def __init__(self, repo, path, filelog=None, parent=None): |
2175 super(overlayworkingfilectx, self).__init__(repo, path, filelog, | 2470 super(overlayworkingfilectx, self).__init__(repo, path, filelog, parent) |
2176 parent) | |
2177 self._repo = repo | 2471 self._repo = repo |
2178 self._parent = parent | 2472 self._parent = parent |
2179 self._path = path | 2473 self._path = path |
2180 | 2474 |
2181 def cmp(self, fctx): | 2475 def cmp(self, fctx): |
2221 return self._parent.remove(self._path) | 2515 return self._parent.remove(self._path) |
2222 | 2516 |
2223 def clearunknown(self): | 2517 def clearunknown(self): |
2224 pass | 2518 pass |
2225 | 2519 |
2520 | |
2226 class workingcommitctx(workingctx): | 2521 class workingcommitctx(workingctx): |
2227 """A workingcommitctx object makes access to data related to | 2522 """A workingcommitctx object makes access to data related to |
2228 the revision being committed convenient. | 2523 the revision being committed convenient. |
2229 | 2524 |
2230 This hides changes in the working directory, if they aren't | 2525 This hides changes in the working directory, if they aren't |
2231 committed in this context. | 2526 committed in this context. |
2232 """ | 2527 """ |
2233 def __init__(self, repo, changes, | 2528 |
2234 text="", user=None, date=None, extra=None): | 2529 def __init__( |
2235 super(workingcommitctx, self).__init__(repo, text, user, date, extra, | 2530 self, repo, changes, text="", user=None, date=None, extra=None |
2236 changes) | 2531 ): |
2532 super(workingcommitctx, self).__init__( | |
2533 repo, text, user, date, extra, changes | |
2534 ) | |
2237 | 2535 |
2238 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False): | 2536 def _dirstatestatus(self, match, ignored=False, clean=False, unknown=False): |
2239 """Return matched files only in ``self._status`` | 2537 """Return matched files only in ``self._status`` |
2240 | 2538 |
2241 Uncommitted files appear "clean" via this context, even if | 2539 Uncommitted files appear "clean" via this context, even if |
2243 """ | 2541 """ |
2244 if clean: | 2542 if clean: |
2245 clean = [f for f in self._manifest if f not in self._changedset] | 2543 clean = [f for f in self._manifest if f not in self._changedset] |
2246 else: | 2544 else: |
2247 clean = [] | 2545 clean = [] |
2248 return scmutil.status([f for f in self._status.modified if match(f)], | 2546 return scmutil.status( |
2249 [f for f in self._status.added if match(f)], | 2547 [f for f in self._status.modified if match(f)], |
2250 [f for f in self._status.removed if match(f)], | 2548 [f for f in self._status.added if match(f)], |
2251 [], [], [], clean) | 2549 [f for f in self._status.removed if match(f)], |
2550 [], | |
2551 [], | |
2552 [], | |
2553 clean, | |
2554 ) | |
2252 | 2555 |
2253 @propertycache | 2556 @propertycache |
2254 def _changedset(self): | 2557 def _changedset(self): |
2255 """Return the set of files changed in this context | 2558 """Return the set of files changed in this context |
2256 """ | 2559 """ |
2257 changed = set(self._status.modified) | 2560 changed = set(self._status.modified) |
2258 changed.update(self._status.added) | 2561 changed.update(self._status.added) |
2259 changed.update(self._status.removed) | 2562 changed.update(self._status.removed) |
2260 return changed | 2563 return changed |
2564 | |
2261 | 2565 |
2262 def makecachingfilectxfn(func): | 2566 def makecachingfilectxfn(func): |
2263 """Create a filectxfn that caches based on the path. | 2567 """Create a filectxfn that caches based on the path. |
2264 | 2568 |
2265 We can't use util.cachefunc because it uses all arguments as the cache | 2569 We can't use util.cachefunc because it uses all arguments as the cache |
2273 cache[path] = func(repo, memctx, path) | 2577 cache[path] = func(repo, memctx, path) |
2274 return cache[path] | 2578 return cache[path] |
2275 | 2579 |
2276 return getfilectx | 2580 return getfilectx |
2277 | 2581 |
2582 | |
2278 def memfilefromctx(ctx): | 2583 def memfilefromctx(ctx): |
2279 """Given a context return a memfilectx for ctx[path] | 2584 """Given a context return a memfilectx for ctx[path] |
2280 | 2585 |
2281 This is a convenience method for building a memctx based on another | 2586 This is a convenience method for building a memctx based on another |
2282 context. | 2587 context. |
2283 """ | 2588 """ |
2589 | |
2284 def getfilectx(repo, memctx, path): | 2590 def getfilectx(repo, memctx, path): |
2285 fctx = ctx[path] | 2591 fctx = ctx[path] |
2286 copysource = fctx.copysource() | 2592 copysource = fctx.copysource() |
2287 return memfilectx(repo, memctx, path, fctx.data(), | 2593 return memfilectx( |
2288 islink=fctx.islink(), isexec=fctx.isexec(), | 2594 repo, |
2289 copysource=copysource) | 2595 memctx, |
2596 path, | |
2597 fctx.data(), | |
2598 islink=fctx.islink(), | |
2599 isexec=fctx.isexec(), | |
2600 copysource=copysource, | |
2601 ) | |
2290 | 2602 |
2291 return getfilectx | 2603 return getfilectx |
2604 | |
2292 | 2605 |
2293 def memfilefrompatch(patchstore): | 2606 def memfilefrompatch(patchstore): |
2294 """Given a patch (e.g. patchstore object) return a memfilectx | 2607 """Given a patch (e.g. patchstore object) return a memfilectx |
2295 | 2608 |
2296 This is a convenience method for building a memctx based on a patchstore. | 2609 This is a convenience method for building a memctx based on a patchstore. |
2297 """ | 2610 """ |
2611 | |
2298 def getfilectx(repo, memctx, path): | 2612 def getfilectx(repo, memctx, path): |
2299 data, mode, copysource = patchstore.getfile(path) | 2613 data, mode, copysource = patchstore.getfile(path) |
2300 if data is None: | 2614 if data is None: |
2301 return None | 2615 return None |
2302 islink, isexec = mode | 2616 islink, isexec = mode |
2303 return memfilectx(repo, memctx, path, data, islink=islink, | 2617 return memfilectx( |
2304 isexec=isexec, copysource=copysource) | 2618 repo, |
2619 memctx, | |
2620 path, | |
2621 data, | |
2622 islink=islink, | |
2623 isexec=isexec, | |
2624 copysource=copysource, | |
2625 ) | |
2305 | 2626 |
2306 return getfilectx | 2627 return getfilectx |
2628 | |
2307 | 2629 |
2308 class memctx(committablectx): | 2630 class memctx(committablectx): |
2309 """Use memctx to perform in-memory commits via localrepo.commitctx(). | 2631 """Use memctx to perform in-memory commits via localrepo.commitctx(). |
2310 | 2632 |
2311 Revision information is supplied at initialization time while | 2633 Revision information is supplied at initialization time while |
2336 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files. | 2658 # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files. |
2337 # Extensions that need to retain compatibility across Mercurial 3.1 can use | 2659 # Extensions that need to retain compatibility across Mercurial 3.1 can use |
2338 # this field to determine what to do in filectxfn. | 2660 # this field to determine what to do in filectxfn. |
2339 _returnnoneformissingfiles = True | 2661 _returnnoneformissingfiles = True |
2340 | 2662 |
2341 def __init__(self, repo, parents, text, files, filectxfn, user=None, | 2663 def __init__( |
2342 date=None, extra=None, branch=None, editor=False): | 2664 self, |
2343 super(memctx, self).__init__(repo, text, user, date, extra, | 2665 repo, |
2344 branch=branch) | 2666 parents, |
2667 text, | |
2668 files, | |
2669 filectxfn, | |
2670 user=None, | |
2671 date=None, | |
2672 extra=None, | |
2673 branch=None, | |
2674 editor=False, | |
2675 ): | |
2676 super(memctx, self).__init__( | |
2677 repo, text, user, date, extra, branch=branch | |
2678 ) | |
2345 self._rev = None | 2679 self._rev = None |
2346 self._node = None | 2680 self._node = None |
2347 parents = [(p or nullid) for p in parents] | 2681 parents = [(p or nullid) for p in parents] |
2348 p1, p2 = parents | 2682 p1, p2 = parents |
2349 self._parents = [self._repo[p] for p in (p1, p2)] | 2683 self._parents = [self._repo[p] for p in (p1, p2)] |
2418 else: | 2752 else: |
2419 removed.append(f) | 2753 removed.append(f) |
2420 | 2754 |
2421 return scmutil.status(modified, added, removed, [], [], [], []) | 2755 return scmutil.status(modified, added, removed, [], [], [], []) |
2422 | 2756 |
2757 | |
2423 class memfilectx(committablefilectx): | 2758 class memfilectx(committablefilectx): |
2424 """memfilectx represents an in-memory file to commit. | 2759 """memfilectx represents an in-memory file to commit. |
2425 | 2760 |
2426 See memctx and committablefilectx for more details. | 2761 See memctx and committablefilectx for more details. |
2427 """ | 2762 """ |
2428 def __init__(self, repo, changectx, path, data, islink=False, | 2763 |
2429 isexec=False, copysource=None): | 2764 def __init__( |
2765 self, | |
2766 repo, | |
2767 changectx, | |
2768 path, | |
2769 data, | |
2770 islink=False, | |
2771 isexec=False, | |
2772 copysource=None, | |
2773 ): | |
2430 """ | 2774 """ |
2431 path is the normalized file path relative to repository root. | 2775 path is the normalized file path relative to repository root. |
2432 data is the file content as a string. | 2776 data is the file content as a string. |
2433 islink is True if the file is a symbolic link. | 2777 islink is True if the file is a symbolic link. |
2434 isexec is True if the file is executable. | 2778 isexec is True if the file is executable. |
2476 user receives the committer name and defaults to current repository | 2820 user receives the committer name and defaults to current repository |
2477 username, date is the commit date in any format supported by | 2821 username, date is the commit date in any format supported by |
2478 dateutil.parsedate() and defaults to current date, extra is a dictionary of | 2822 dateutil.parsedate() and defaults to current date, extra is a dictionary of |
2479 metadata or is left empty. | 2823 metadata or is left empty. |
2480 """ | 2824 """ |
2481 def __init__(self, repo, originalctx, parents=None, text=None, user=None, | 2825 |
2482 date=None, extra=None, editor=False): | 2826 def __init__( |
2827 self, | |
2828 repo, | |
2829 originalctx, | |
2830 parents=None, | |
2831 text=None, | |
2832 user=None, | |
2833 date=None, | |
2834 extra=None, | |
2835 editor=False, | |
2836 ): | |
2483 if text is None: | 2837 if text is None: |
2484 text = originalctx.description() | 2838 text = originalctx.description() |
2485 super(metadataonlyctx, self).__init__(repo, text, user, date, extra) | 2839 super(metadataonlyctx, self).__init__(repo, text, user, date, extra) |
2486 self._rev = None | 2840 self._rev = None |
2487 self._node = None | 2841 self._node = None |
2498 | 2852 |
2499 # sanity check to ensure that the reused manifest parents are | 2853 # sanity check to ensure that the reused manifest parents are |
2500 # manifests of our commit parents | 2854 # manifests of our commit parents |
2501 mp1, mp2 = self.manifestctx().parents | 2855 mp1, mp2 = self.manifestctx().parents |
2502 if p1 != nullid and p1.manifestnode() != mp1: | 2856 if p1 != nullid and p1.manifestnode() != mp1: |
2503 raise RuntimeError(r"can't reuse the manifest: its p1 " | 2857 raise RuntimeError( |
2504 r"doesn't match the new ctx p1") | 2858 r"can't reuse the manifest: its p1 " |
2859 r"doesn't match the new ctx p1" | |
2860 ) | |
2505 if p2 != nullid and p2.manifestnode() != mp2: | 2861 if p2 != nullid and p2.manifestnode() != mp2: |
2506 raise RuntimeError(r"can't reuse the manifest: " | 2862 raise RuntimeError( |
2507 r"its p2 doesn't match the new ctx p2") | 2863 r"can't reuse the manifest: " |
2864 r"its p2 doesn't match the new ctx p2" | |
2865 ) | |
2508 | 2866 |
2509 self._files = originalctx.files() | 2867 self._files = originalctx.files() |
2510 self.substate = {} | 2868 self.substate = {} |
2511 | 2869 |
2512 if editor: | 2870 if editor: |
2556 else: | 2914 else: |
2557 removed.append(f) | 2915 removed.append(f) |
2558 | 2916 |
2559 return scmutil.status(modified, added, removed, [], [], [], []) | 2917 return scmutil.status(modified, added, removed, [], [], [], []) |
2560 | 2918 |
2919 | |
2561 class arbitraryfilectx(object): | 2920 class arbitraryfilectx(object): |
2562 """Allows you to use filectx-like functions on a file in an arbitrary | 2921 """Allows you to use filectx-like functions on a file in an arbitrary |
2563 location on disk, possibly not in the working directory. | 2922 location on disk, possibly not in the working directory. |
2564 """ | 2923 """ |
2924 | |
2565 def __init__(self, path, repo=None): | 2925 def __init__(self, path, repo=None): |
2566 # Repo is optional because contrib/simplemerge uses this class. | 2926 # Repo is optional because contrib/simplemerge uses this class. |
2567 self._repo = repo | 2927 self._repo = repo |
2568 self._path = path | 2928 self._path = path |
2569 | 2929 |
2570 def cmp(self, fctx): | 2930 def cmp(self, fctx): |
2571 # filecmp follows symlinks whereas `cmp` should not, so skip the fast | 2931 # filecmp follows symlinks whereas `cmp` should not, so skip the fast |
2572 # path if either side is a symlink. | 2932 # path if either side is a symlink. |
2573 symlinks = ('l' in self.flags() or 'l' in fctx.flags()) | 2933 symlinks = 'l' in self.flags() or 'l' in fctx.flags() |
2574 if not symlinks and isinstance(fctx, workingfilectx) and self._repo: | 2934 if not symlinks and isinstance(fctx, workingfilectx) and self._repo: |
2575 # Add a fast-path for merge if both sides are disk-backed. | 2935 # Add a fast-path for merge if both sides are disk-backed. |
2576 # Note that filecmp uses the opposite return values (True if same) | 2936 # Note that filecmp uses the opposite return values (True if same) |
2577 # from our cmp functions (True if different). | 2937 # from our cmp functions (True if different). |
2578 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path())) | 2938 return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path())) |