~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Robert Collins
  • Date: 2005-10-17 11:41:07 UTC
  • mfrom: (1442.1.60)
  • Revision ID: robertc@robertcollins.net-20051017114107-f5586285d825c105
Merge in first part of GPG support.

This adds check_signatures config support, triams back the transport api
to be leaner and easier to hook in suffixes - non primary streams in the store
associated with the fileid that primary data is stored in, a gpg module which
will encapsulate all signing and checking operations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
# it's not predictable when it will be written out.
22
22
 
23
23
import os
 
24
import stat
24
25
import fnmatch
25
 
        
 
26
 
 
27
from bzrlib.branch import Branch
26
28
import bzrlib.tree
27
 
from bzrlib.osutils import appendpath, file_kind, isdir, splitpath
 
29
from bzrlib.osutils import appendpath, file_kind, isdir, splitpath, relpath
28
30
from bzrlib.errors import BzrCheckError
29
31
from bzrlib.trace import mutter
30
32
 
 
33
class TreeEntry(object):
 
34
    """An entry that implements the minium interface used by commands.
 
35
 
 
36
    This needs further inspection, it may be better to have 
 
37
    InventoryEntries without ids - though that seems wrong. For now,
 
38
    this is a parallel hierarchy to InventoryEntry, and needs to become
 
39
    one of several things: decorates to that hierarchy, children of, or
 
40
    parents of it.
 
41
    Another note is that these objects are currently only used when there is
 
42
    no InventoryEntry available - i.e. for unversioned objects.
 
43
    Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
 
44
    """
 
45
 
 
46
    def __eq__(self, other):
 
47
        # yes, this us ugly, TODO: best practice __eq__ style.
 
48
        return (isinstance(other, TreeEntry)
 
49
                and other.__class__ == self.__class__)
 
50
 
 
51
    def kind_character(self):
 
52
        return "???"
 
53
 
 
54
 
 
55
class TreeDirectory(TreeEntry):
 
56
    """See TreeEntry. This is a directory in a working tree."""
 
57
 
 
58
    def __eq__(self, other):
 
59
        return (isinstance(other, TreeDirectory)
 
60
                and other.__class__ == self.__class__)
 
61
 
 
62
    def kind_character(self):
 
63
        return "/"
 
64
 
 
65
 
 
66
class TreeFile(TreeEntry):
 
67
    """See TreeEntry. This is a regular file in a working tree."""
 
68
 
 
69
    def __eq__(self, other):
 
70
        return (isinstance(other, TreeFile)
 
71
                and other.__class__ == self.__class__)
 
72
 
 
73
    def kind_character(self):
 
74
        return ''
 
75
 
 
76
 
 
77
class TreeLink(TreeEntry):
 
78
    """See TreeEntry. This is a symlink in a working tree."""
 
79
 
 
80
    def __eq__(self, other):
 
81
        return (isinstance(other, TreeLink)
 
82
                and other.__class__ == self.__class__)
 
83
 
 
84
    def kind_character(self):
 
85
        return ''
 
86
 
 
87
 
31
88
class WorkingTree(bzrlib.tree.Tree):
32
89
    """Working copy tree.
33
90
 
37
94
    It is possible for a `WorkingTree` to have a filename which is
38
95
    not listed in the Inventory and vice versa.
39
96
    """
40
 
    def __init__(self, basedir, inv):
 
97
    def __init__(self, basedir, branch=None):
 
98
        """Construct a WorkingTree for basedir.
 
99
 
 
100
        If the branch is not supplied, it is opened automatically.
 
101
        If the branch is supplied, it must be the branch for this basedir.
 
102
        (branch.base is not cross checked, because for remote branches that
 
103
        would be meaningless).
 
104
        """
41
105
        from bzrlib.hashcache import HashCache
42
106
        from bzrlib.trace import note, mutter
43
107
 
44
 
        self._inventory = inv
 
108
        if branch is None:
 
109
            branch = Branch.open(basedir)
 
110
        self._inventory = branch.inventory
 
111
        self.path2id = self._inventory.path2id
 
112
        self.branch = branch
45
113
        self.basedir = basedir
46
 
        self.path2id = inv.path2id
47
114
 
48
115
        # update the whole cache up front and write to disk if anything changed;
49
116
        # in the future we might want to do this more selectively
69
136
        """
70
137
        inv = self._inventory
71
138
        for path, ie in inv.iter_entries():
72
 
            if os.path.exists(self.abspath(path)):
 
139
            if bzrlib.osutils.lexists(self.abspath(path)):
73
140
                yield ie.file_id
74
141
 
75
142
 
82
149
    def abspath(self, filename):
83
150
        return os.path.join(self.basedir, filename)
84
151
 
 
152
    def relpath(self, abspath):
 
153
        """Return the local path portion from a given absolute path."""
 
154
        return relpath(self.basedir, abspath)
 
155
 
85
156
    def has_filename(self, filename):
86
 
        return os.path.exists(self.abspath(filename))
 
157
        return bzrlib.osutils.lexists(self.abspath(filename))
87
158
 
88
159
    def get_file(self, file_id):
89
160
        return self.get_file_byname(self.id2path(file_id))
106
177
        if not inv.has_id(file_id):
107
178
            return False
108
179
        path = inv.id2path(file_id)
109
 
        return os.path.exists(self.abspath(path))
 
180
        return bzrlib.osutils.lexists(self.abspath(path))
110
181
 
111
182
 
112
183
    __contains__ = has_id
115
186
    def get_file_size(self, file_id):
116
187
        return os.path.getsize(self.id2abspath(file_id))
117
188
 
118
 
 
119
189
    def get_file_sha1(self, file_id):
120
190
        path = self._inventory.id2path(file_id)
121
191
        return self._hashcache.get_sha1(path)
122
192
 
123
193
 
 
194
    def is_executable(self, file_id):
 
195
        if os.name == "nt":
 
196
            return self._inventory[file_id].executable
 
197
        else:
 
198
            path = self._inventory.id2path(file_id)
 
199
            mode = os.lstat(self.abspath(path)).st_mode
 
200
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC&mode)
 
201
 
 
202
    def get_symlink_target(self, file_id):
 
203
        return os.readlink(self.id2abspath(file_id))
 
204
 
124
205
    def file_class(self, filename):
125
206
        if self.path2id(filename):
126
207
            return 'V'
174
255
                                            "now of kind %r"
175
256
                                            % (fap, f_ie.kind, f_ie.file_id, fk))
176
257
 
177
 
                yield fp, c, fk, (f_ie and f_ie.file_id)
 
258
                # make a last minute entry
 
259
                if f_ie:
 
260
                    entry = f_ie
 
261
                else:
 
262
                    if fk == 'directory':
 
263
                        entry = TreeDirectory()
 
264
                    elif fk == 'file':
 
265
                        entry = TreeFile()
 
266
                    elif fk == 'symlink':
 
267
                        entry = TreeLink()
 
268
                    else:
 
269
                        entry = TreeEntry()
 
270
                
 
271
                yield fp, c, fk, (f_ie and f_ie.file_id), entry
178
272
 
179
273
                if fk != 'directory':
180
274
                    continue
196
290
            if not self.is_ignored(subp):
197
291
                yield subp
198
292
 
 
293
    def iter_conflicts(self):
 
294
        conflicted = set()
 
295
        for path in (s[0] for s in self.list_files()):
 
296
            stem = get_conflicted_stem(path)
 
297
            if stem is None:
 
298
                continue
 
299
            if stem not in conflicted:
 
300
                conflicted.add(stem)
 
301
                yield stem
199
302
 
200
303
    def extras(self):
201
304
        """Yield all unknown files in this WorkingTree.
287
390
                    return pat
288
391
        else:
289
392
            return None
290
 
        
 
393
 
 
394
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
 
395
def get_conflicted_stem(path):
 
396
    for suffix in CONFLICT_SUFFIXES:
 
397
        if path.endswith(suffix):
 
398
            return path[:-len(suffix)]