~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tree.py

  • Committer: Martin Pool
  • Date: 2005-06-11 01:33:22 UTC
  • Revision ID: mbp@sourcefrog.net-20050611013322-f12014bf65accd0c
- don't show progress bar unless completion is known

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
"""Tree classes, representing directory at point in time.
18
18
"""
19
19
 
20
 
import os
21
 
from cStringIO import StringIO
 
20
from sets import Set
 
21
import os.path, os, fnmatch
 
22
 
 
23
from osutils import pumpfile, filesize, quotefn, sha_file, \
 
24
     joinpath, splitpath, appendpath, isdir, isfile, file_kind, fingerprint_file
 
25
import errno
 
26
from stat import S_ISREG, S_ISDIR, ST_MODE, ST_SIZE
 
27
 
 
28
from inventory import Inventory
 
29
from trace import mutter, note
 
30
from errors import bailout
 
31
import branch
22
32
 
23
33
import bzrlib
24
 
from bzrlib.trace import mutter, note
25
 
from bzrlib.errors import BzrError, BzrCheckError
26
 
from bzrlib.inventory import Inventory
27
 
from bzrlib.osutils import appendpath, fingerprint_file
28
34
 
29
35
class Tree(object):
30
36
    """Abstract file tree.
55
61
    def has_id(self, file_id):
56
62
        return self.inventory.has_id(file_id)
57
63
 
58
 
    def has_or_had_id(self, file_id):
59
 
        if file_id == self.inventory.root.file_id:
60
 
            return True
61
 
        return self.inventory.has_id(file_id)
62
 
 
63
64
    __contains__ = has_id
64
65
 
65
66
    def __iter__(self):
68
69
    def id2path(self, file_id):
69
70
        return self.inventory.id2path(file_id)
70
71
 
71
 
    def kind(self, file_id):
72
 
        raise NotImplementedError("subclasses must implement kind")
73
 
 
74
72
    def _get_inventory(self):
75
73
        return self._inventory
76
 
    
77
 
    def get_file_by_path(self, path):
78
 
        return self.get_file(self._inventory.path2id(path))
79
74
 
80
75
    inventory = property(_get_inventory,
81
76
                         doc="Inventory of this Tree")
82
77
 
83
78
    def _check_retrieved(self, ie, f):
84
 
        if not __debug__:
85
 
            return  
86
79
        fp = fingerprint_file(f)
87
80
        f.seek(0)
88
81
        
89
82
        if ie.text_size != None:
90
83
            if ie.text_size != fp['size']:
91
 
                raise BzrError("mismatched size for file %r in %r" % (ie.file_id, self._store),
 
84
                bailout("mismatched size for file %r in %r" % (ie.file_id, self._store),
92
85
                        ["inventory expects %d bytes" % ie.text_size,
93
86
                         "file is actually %d bytes" % fp['size'],
94
87
                         "store is probably damaged/corrupt"])
95
88
 
96
89
        if ie.text_sha1 != fp['sha1']:
97
 
            raise BzrError("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
 
90
            bailout("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
98
91
                    ["inventory expects %s" % ie.text_sha1,
99
92
                     "file is actually %s" % fp['sha1'],
100
93
                     "store is probably damaged/corrupt"])
101
94
 
102
95
 
103
 
    def print_file(self, file_id):
104
 
        """Print file with id `file_id` to stdout."""
 
96
    def print_file(self, fileid):
 
97
        """Print file with id `fileid` to stdout."""
105
98
        import sys
106
 
        sys.stdout.write(self.get_file_text(file_id))
107
 
 
108
 
    def lock_read(self):
109
 
        pass
110
 
 
111
 
    def unlock(self):
112
 
        pass
113
 
 
114
 
    def filter_unversioned_files(self, paths):
115
 
        """Filter out paths that are not versioned.
116
 
 
117
 
        :return: set of paths.
 
99
        pumpfile(self.get_file(fileid), sys.stdout)
 
100
        
 
101
        
 
102
    def export(self, dest):        
 
103
        """Export this tree to a new directory.
 
104
 
 
105
        `dest` should not exist, and will be created holding the
 
106
        contents of this tree.
 
107
 
 
108
        TODO: To handle subdirectories we need to create the
 
109
               directories first.
 
110
 
 
111
        :note: If the export fails, the destination directory will be
 
112
               left in a half-assed state.
118
113
        """
119
 
        # NB: we specifically *don't* call self.has_filename, because for
120
 
        # WorkingTrees that can indicate files that exist on disk but that 
121
 
        # are not versioned.
122
 
        pred = self.inventory.has_filename
123
 
        return set((p for p in paths if not pred(p)))
124
 
        
125
 
        
 
114
        os.mkdir(dest)
 
115
        mutter('export version %r' % self)
 
116
        inv = self.inventory
 
117
        for dp, ie in inv.iter_entries():
 
118
            kind = ie.kind
 
119
            fullpath = appendpath(dest, dp)
 
120
            if kind == 'directory':
 
121
                os.mkdir(fullpath)
 
122
            elif kind == 'file':
 
123
                pumpfile(self.get_file(ie.file_id), file(fullpath, 'wb'))
 
124
            else:
 
125
                bailout("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
 
126
            mutter("  export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
 
127
 
 
128
 
 
129
 
126
130
class RevisionTree(Tree):
127
131
    """Tree viewing a previous revision.
128
132
 
133
137
           or at least passing a description to the constructor.
134
138
    """
135
139
    
136
 
    def __init__(self, branch, inv, revision_id):
137
 
        self._branch = branch
138
 
        self._weave_store = branch.weave_store
 
140
    def __init__(self, store, inv):
 
141
        self._store = store
139
142
        self._inventory = inv
140
 
        self._revision_id = revision_id
141
 
 
142
 
    def get_weave(self, file_id):
143
 
        return self._weave_store.get_weave(file_id,
144
 
                self._branch.get_transaction())
145
 
 
146
 
    def get_file_lines(self, file_id):
147
 
        ie = self._inventory[file_id]
148
 
        weave = self.get_weave(file_id)
149
 
        return weave.get_lines(ie.revision)
150
 
 
151
 
    def get_file_text(self, file_id):
152
 
        return ''.join(self.get_file_lines(file_id))
153
143
 
154
144
    def get_file(self, file_id):
155
 
        return StringIO(self.get_file_text(file_id))
 
145
        ie = self._inventory[file_id]
 
146
        f = self._store[ie.text_id]
 
147
        mutter("  get fileid{%s} from %r" % (file_id, self))
 
148
        self._check_retrieved(ie, f)
 
149
        return f
156
150
 
157
151
    def get_file_size(self, file_id):
158
152
        return self._inventory[file_id].text_size
159
153
 
160
154
    def get_file_sha1(self, file_id):
161
155
        ie = self._inventory[file_id]
162
 
        if ie.kind == "file":
163
 
            return ie.text_sha1
164
 
 
165
 
    def is_executable(self, file_id):
166
 
        ie = self._inventory[file_id]
167
 
        if ie.kind != "file":
168
 
            return None 
169
 
        return self._inventory[file_id].executable
 
156
        return ie.text_sha1
170
157
 
171
158
    def has_filename(self, filename):
172
159
        return bool(self.inventory.path2id(filename))
174
161
    def list_files(self):
175
162
        # The only files returned by this are those from the version
176
163
        for path, entry in self.inventory.iter_entries():
177
 
            yield path, 'V', entry.kind, entry.file_id, entry
178
 
 
179
 
    def get_symlink_target(self, file_id):
180
 
        ie = self._inventory[file_id]
181
 
        return ie.symlink_target;
182
 
 
183
 
    def kind(self, file_id):
184
 
        return self._inventory[file_id].kind
185
 
 
186
 
    def lock_read(self):
187
 
        self._branch.lock_read()
188
 
 
189
 
    def unlock(self):
190
 
        self._branch.unlock()
 
164
            yield path, 'V', entry.kind, entry.file_id
191
165
 
192
166
 
193
167
class EmptyTree(Tree):
194
168
    def __init__(self):
195
169
        self._inventory = Inventory()
196
170
 
197
 
    def get_symlink_target(self, file_id):
198
 
        return None
199
 
 
200
171
    def has_filename(self, filename):
201
172
        return False
202
173
 
203
 
    def kind(self, file_id):
204
 
        assert self._inventory[file_id].kind == "root_directory"
205
 
        return "root_directory"
206
 
 
207
174
    def list_files(self):
208
 
        return iter([])
 
175
        if False:  # just to make it a generator
 
176
            yield None
209
177
    
210
 
    def __contains__(self, file_id):
211
 
        return file_id in self._inventory
212
 
 
213
 
    def get_file_sha1(self, file_id):
214
 
        assert self._inventory[file_id].kind == "root_directory"
215
 
        return None
216
178
 
217
179
 
218
180
######################################################################
279
241
        if old_name != new_name:
280
242
            yield (old_name, new_name)
281
243
            
282
 
 
283