Changeset View
Standalone View
mercurial/context.py
# context.py - changeset and file context objects for mercurial | # context.py - changeset and file context objects for mercurial | ||||
# | # | ||||
# Copyright 2006, 2007 Matt Mackall <mpm@selenic.com> | # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com> | ||||
# | # | ||||
# This software may be used and distributed according to the terms of the | # This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | # GNU General Public License version 2 or any later version. | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
import errno | import errno | ||||
import filecmp | |||||
import os | import os | ||||
import re | import re | ||||
import stat | import stat | ||||
from .i18n import _ | from .i18n import _ | ||||
from .node import ( | from .node import ( | ||||
addednodeid, | addednodeid, | ||||
bin, | bin, | ||||
▲ Show 20 Lines • Show All 2521 Lines • ▼ Show 20 Line(s) | def _status(self): | ||||
removed.append(f) | removed.append(f) | ||||
return scmutil.status(modified, added, removed, [], [], [], []) | return scmutil.status(modified, added, removed, [], [], [], []) | ||||
class arbitraryfilectx(object): | class arbitraryfilectx(object): | ||||
"""Allows you to use filectx-like functions on a file in an arbitrary | """Allows you to use filectx-like functions on a file in an arbitrary | ||||
location on disk, possibly not in the working directory. | location on disk, possibly not in the working directory. | ||||
""" | """ | ||||
def __init__(self, path): | def __init__(self, path, repo=None): | ||||
# Repo is optional because contrib/simplemerge uses this class. | |||||
self._repo = repo | |||||
self._path = path | self._path = path | ||||
def cmp(self, otherfilectx): | def cmp(self, fctx): | ||||
return self.data() != otherfilectx.data() | if isinstance(fctx, workingfilectx) and self._repo: | ||||
# Add a fast-path for merge if both sides are disk-backed. | |||||
# Note that filecmp uses the opposite return values as cmp. | |||||
ryanmce: Ugh, haha | |||||
return not filecmp.cmp(self.path(), self._repo.wjoin(fctx.path())) | |||||
Not Done ReplyWhy is this sufficient? Can't the contents be the same even if the paths are different? I think you can only fastpath if the paths are the same, otherwise you have to fall back to data comparison. This is already queued, but I think we need to drop it if I'm right here. ryanmce: Why is this sufficient? Can't the contents be the same even if the paths are different?
I… | |||||
Not Done ReplyRyan and I talked offline -- but surprisingly, the default filectx.cmp function only compares contents: 1:~/1$ repo['.']['A'].cmp(repo['.']['B']) Out[1]: False 2:~/1$ repo['.']['A'].cmp(repo['.']['A']) Out[2]: False 3:~/1$ repo['.']['A'].cmp(repo['.']['C']) Out[3]: True (here, A and B have the same content). And filecmp seems to behave the same way: 7:~/1$ filecmp.cmp('A', 'B') Out[7]: True 8:~/1$ filecmp.cmp('A', 'A') Out[8]: True 9:~/1$ filecmp.cmp('A', 'C') Out[9]: False That doesn't mean that it's wrong, but I think it's consistent. phillco: Ryan and I talked offline -- but surprisingly, the default `filectx.cmp` function only compares… | |||||
Not Done ReplyAh, but some experimenting revealed that filecmp does follow symlinks, but our filectx comparators do not. Otherwise, both filecmp and filectx.cmp ignore any flag differences. Thus, you can demonstrate a discrepancy: A contains "foo" real_A contains "A" sym_A link to A repo['.']['real_A'].cmp(repo['.']['sym_A']) # claims the same filecmp.cmp('real_A', 'sym_A') # claims a difference, because "foo" != "A" Note this simpler case doesn't trigger the discrepancy, because the linked file is otherwise identical: A contains "A" sym_A link to A repo['.']['A'].cmp(repo['.']['sym_A']) # claims the same filecmp.cmp('A', 'sym_A') # claims the same The easiest fix is just to skip the fast-comparison path if either side is a symlink, and that's what I'll do unless others have other ideas. (@ryanmce thought we should think about what this API _should_ do). phillco: Ah, but some experimenting revealed that `filecmp` does follow symlinks, but our `filectx`… | |||||
return self.data() != fctx.data() | |||||
def path(self): | def path(self): | ||||
return self._path | return self._path | ||||
def flags(self): | def flags(self): | ||||
return '' | return '' | ||||
def data(self): | def data(self): | ||||
Show All 13 Lines |
Ugh, haha