~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Martin Pool
  • Date: 2005-07-11 03:40:02 UTC
  • Revision ID: mbp@sourcefrog.net-20050711034002-575d84b4c7514542
- commit command refuses unless something is changed or --unchanged is given

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
# TODO: Don't allow WorkingTrees to be constructed for remote branches.
18
18
 
19
 
# FIXME: I don't know if writing out the cache from the destructor is really a
20
 
# good idea, because destructors are considered poor taste in Python, and
21
 
# it's not predictable when it will be written out.
22
 
 
23
19
import os
24
 
import stat
25
 
import fnmatch
26
 
        
 
20
    
27
21
import bzrlib.tree
28
 
from bzrlib.osutils import appendpath, file_kind, isdir, splitpath
29
 
from bzrlib.errors import BzrCheckError
30
 
from bzrlib.trace import mutter
31
 
 
32
 
class TreeEntry(object):
33
 
    """An entry that implements the minium interface used by commands.
34
 
 
35
 
    This needs further inspection, it may be better to have 
36
 
    InventoryEntries without ids - though that seems wrong. For now,
37
 
    this is a parallel hierarchy to InventoryEntry, and needs to become
38
 
    one of several things: decorates to that hierarchy, children of, or
39
 
    parents of it.
40
 
    Another note is that these objects are currently only used when there is
41
 
    no InventoryEntry available - i.e. for unversioned objects.
42
 
    Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
43
 
    """
44
 
 
45
 
    def __eq__(self, other):
46
 
        # yes, this us ugly, TODO: best practice __eq__ style.
47
 
        return (isinstance(other, TreeEntry)
48
 
                and other.__class__ == self.__class__)
49
 
 
50
 
    def kind_character(self):
51
 
        return "???"
52
 
 
53
 
 
54
 
class TreeDirectory(TreeEntry):
55
 
    """See TreeEntry. This is a directory in a working tree."""
56
 
 
57
 
    def __eq__(self, other):
58
 
        return (isinstance(other, TreeDirectory)
59
 
                and other.__class__ == self.__class__)
60
 
 
61
 
    def kind_character(self):
62
 
        return "/"
63
 
 
64
 
 
65
 
class TreeFile(TreeEntry):
66
 
    """See TreeEntry. This is a regular file in a working tree."""
67
 
 
68
 
    def __eq__(self, other):
69
 
        return (isinstance(other, TreeFile)
70
 
                and other.__class__ == self.__class__)
71
 
 
72
 
    def kind_character(self):
73
 
        return ''
74
 
 
75
 
 
76
 
class TreeLink(TreeEntry):
77
 
    """See TreeEntry. This is a symlink in a working tree."""
78
 
 
79
 
    def __eq__(self, other):
80
 
        return (isinstance(other, TreeLink)
81
 
                and other.__class__ == self.__class__)
82
 
 
83
 
    def kind_character(self):
84
 
        return ''
85
 
 
 
22
from errors import BzrCheckError
 
23
from trace import mutter
86
24
 
87
25
class WorkingTree(bzrlib.tree.Tree):
88
26
    """Working copy tree.
105
43
        # in the future we might want to do this more selectively
106
44
        hc = self._hashcache = HashCache(basedir)
107
45
        hc.read()
108
 
        hc.scan()
 
46
        for path, ie in inv.iter_entries():
 
47
            hc.get_sha1(path)
109
48
 
110
49
        if hc.needs_write:
111
50
            mutter("write hc")
112
51
            hc.write()
113
 
            
114
 
            
115
 
    def __del__(self):
116
 
        if self._hashcache.needs_write:
117
 
            self._hashcache.write()
 
52
 
118
53
 
119
54
 
120
55
    def __iter__(self):
125
60
        """
126
61
        inv = self._inventory
127
62
        for path, ie in inv.iter_entries():
128
 
            if bzrlib.osutils.lexists(self.abspath(path)):
 
63
            if os.path.exists(self.abspath(path)):
129
64
                yield ie.file_id
130
65
 
131
66
 
132
67
    def __repr__(self):
133
68
        return "<%s of %s>" % (self.__class__.__name__,
134
 
                               getattr(self, 'basedir', None))
 
69
                               self.basedir)
135
70
 
136
71
 
137
72
 
139
74
        return os.path.join(self.basedir, filename)
140
75
 
141
76
    def has_filename(self, filename):
142
 
        return bzrlib.osutils.lexists(self.abspath(filename))
 
77
        return os.path.exists(self.abspath(filename))
143
78
 
144
79
    def get_file(self, file_id):
145
80
        return self.get_file_byname(self.id2path(file_id))
151
86
        ## XXX: badly named; this isn't in the store at all
152
87
        return self.abspath(self.id2path(file_id))
153
88
 
154
 
 
155
 
    def id2abspath(self, file_id):
156
 
        return self.abspath(self.id2path(file_id))
157
 
 
158
89
                
159
90
    def has_id(self, file_id):
160
91
        # files that have been deleted are excluded
162
93
        if not inv.has_id(file_id):
163
94
            return False
164
95
        path = inv.id2path(file_id)
165
 
        return bzrlib.osutils.lexists(self.abspath(path))
 
96
        return os.path.exists(self.abspath(path))
166
97
 
167
98
 
168
99
    __contains__ = has_id
169
100
    
170
101
 
171
102
    def get_file_size(self, file_id):
172
 
        return os.path.getsize(self.id2abspath(file_id))
 
103
        # is this still called?
 
104
        raise NotImplementedError()
 
105
 
173
106
 
174
107
    def get_file_sha1(self, file_id):
175
108
        path = self._inventory.id2path(file_id)
176
109
        return self._hashcache.get_sha1(path)
177
110
 
178
111
 
179
 
    def is_executable(self, file_id):
180
 
        if os.name == "nt":
181
 
            return self._inventory[file_id].executable
182
 
        else:
183
 
            path = self._inventory.id2path(file_id)
184
 
            mode = os.lstat(self.abspath(path)).st_mode
185
 
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC&mode)
186
 
 
187
 
    def get_symlink_target(self, file_id):
188
 
        return os.readlink(self.id2path(file_id))
189
 
 
190
112
    def file_class(self, filename):
191
113
        if self.path2id(filename):
192
114
            return 'V'
206
128
 
207
129
        Skips the control directory.
208
130
        """
 
131
        from osutils import appendpath, file_kind
 
132
        import os
 
133
 
209
134
        inv = self._inventory
210
135
 
211
136
        def descend(from_dir_relpath, from_dir_id, dp):
240
165
                                            "now of kind %r"
241
166
                                            % (fap, f_ie.kind, f_ie.file_id, fk))
242
167
 
243
 
                # make a last minute entry
244
 
                if f_ie:
245
 
                    entry = f_ie
246
 
                else:
247
 
                    if fk == 'directory':
248
 
                        entry = TreeDirectory()
249
 
                    elif fk == 'file':
250
 
                        entry = TreeFile()
251
 
                    elif fk == 'symlink':
252
 
                        entry = TreeLink()
253
 
                    else:
254
 
                        entry = TreeEntry()
255
 
                
256
 
                yield fp, c, fk, (f_ie and f_ie.file_id), entry
 
168
                yield fp, c, fk, (f_ie and f_ie.file_id)
257
169
 
258
170
                if fk != 'directory':
259
171
                    continue
286
198
        Currently returned depth-first, sorted by name within directories.
287
199
        """
288
200
        ## TODO: Work from given directory downwards
 
201
        from osutils import isdir, appendpath
 
202
        
289
203
        for path, dir_entry in self.inventory.directories():
290
204
            mutter("search for unknowns in %r" % path)
291
205
            dirabs = self.abspath(path)
348
262
        # Eventually it should be replaced with something more
349
263
        # accurate.
350
264
        
 
265
        import fnmatch
 
266
        from osutils import splitpath
 
267
        
351
268
        for pat in self.get_ignore_list():
352
269
            if '/' in pat or '\\' in pat:
353
270
                
367
284
        else:
368
285
            return None
369
286
        
 
287
 
 
288
        
 
289
        
 
290