17
17
"""Tree classes, representing directory at point in time.
20
from osutils import pumpfile, appendpath, fingerprint_file
21
from cStringIO import StringIO
23
24
from bzrlib.trace import mutter, note
24
from bzrlib.errors import BzrError
25
from bzrlib.errors import BzrError, BzrCheckError
26
from bzrlib.inventory import Inventory
27
from bzrlib.osutils import appendpath, fingerprint_file
56
58
def has_id(self, file_id):
57
59
return self.inventory.has_id(file_id)
61
def has_or_had_id(self, file_id):
62
if file_id == self.inventory.root.file_id:
64
return self.inventory.has_id(file_id)
59
66
__contains__ = has_id
61
68
def __iter__(self):
64
71
def id2path(self, file_id):
65
72
return self.inventory.id2path(file_id)
74
def kind(self, file_id):
75
raise NotImplementedError("subclasses must implement kind")
67
77
def _get_inventory(self):
68
78
return self._inventory
80
def get_file_by_path(self, path):
81
return self.get_file(self._inventory.path2id(path))
70
83
inventory = property(_get_inventory,
71
84
doc="Inventory of this Tree")
73
86
def _check_retrieved(self, ie, f):
74
89
fp = fingerprint_file(f)
88
103
"store is probably damaged/corrupt"])
91
def print_file(self, fileid):
92
"""Print file with id `fileid` to stdout."""
106
def print_file(self, file_id):
107
"""Print file with id `file_id` to stdout."""
94
pumpfile(self.get_file(fileid), sys.stdout)
109
sys.stdout.write(self.get_file_text(file_id))
97
112
def export(self, dest, format='dir', root=None):
115
130
or at least passing a description to the constructor.
118
def __init__(self, store, inv):
133
def __init__(self, weave_store, inv, revision_id):
134
self._weave_store = weave_store
120
135
self._inventory = inv
136
self._revision_id = revision_id
138
def get_weave(self, file_id):
139
# FIXME: RevisionTree should be given a branch
140
# not a store, or the store should know the branch.
141
import bzrlib.transactions as transactions
142
return self._weave_store.get_weave(file_id,
143
transactions.PassThroughTransaction())
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(ie.revision)
152
def get_file_text(self, file_id):
153
return ''.join(self.get_file_lines(file_id))
122
156
def get_file(self, file_id):
123
ie = self._inventory[file_id]
124
f = self._store[ie.text_id]
125
mutter(" get fileid{%s} from %r" % (file_id, self))
126
self._check_retrieved(ie, f)
157
return StringIO(self.get_file_text(file_id))
129
159
def get_file_size(self, file_id):
130
160
return self._inventory[file_id].text_size
132
162
def get_file_sha1(self, file_id):
133
163
ie = self._inventory[file_id]
164
if ie.kind == "file":
167
def is_executable(self, file_id):
168
ie = self._inventory[file_id]
169
if ie.kind != "file":
171
return self._inventory[file_id].executable
136
173
def has_filename(self, filename):
137
174
return bool(self.inventory.path2id(filename))
139
176
def list_files(self):
140
177
# The only files returned by this are those from the version
141
178
for path, entry in self.inventory.iter_entries():
142
yield path, 'V', entry.kind, entry.file_id
179
yield path, 'V', entry.kind, entry.file_id, entry
181
def get_symlink_target(self, file_id):
182
ie = self._inventory[file_id]
183
return ie.symlink_target;
185
def kind(self, file_id):
186
return self._inventory[file_id].kind
145
189
class EmptyTree(Tree):
146
def __init__(self, root_id):
147
from bzrlib.inventory import Inventory
148
self._inventory = Inventory(root_id)
191
self._inventory = Inventory()
193
def get_symlink_target(self, file_id):
150
196
def has_filename(self, filename):
199
def kind(self, file_id):
200
assert self._inventory[file_id].kind == "root_directory"
201
return "root_directory"
153
203
def list_files(self):
154
if False: # just to make it a generator
206
def __contains__(self, file_id):
207
return file_id in self._inventory
209
def get_file_sha1(self, file_id):
210
assert self._inventory[file_id].kind == "root_directory"
159
214
######################################################################
242
mutter('export version %r' % tree)
297
mutter('export version %r', tree)
243
298
inv = tree.inventory
244
299
for dp, ie in inv.iter_entries():
246
fullpath = appendpath(dest, dp)
247
if kind == 'directory':
250
pumpfile(tree.get_file(ie.file_id), file(fullpath, 'wb'))
252
raise BzrError("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
253
mutter(" export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
300
if dp != ".bzrignore":
301
ie.put_on_disk(dest, dp, tree)
254
303
exporters['dir'] = dir_exporter
295
344
ball = tarfile.open(dest, 'w:' + compression)
296
345
except tarfile.CompressionError, e:
297
346
raise BzrError(str(e))
298
mutter('export version %r' % tree)
347
mutter('export version %r', tree)
299
348
inv = tree.inventory
300
349
for dp, ie in inv.iter_entries():
301
mutter(" export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
302
item = tarfile.TarInfo(os.path.join(root, dp))
303
# TODO: would be cool to actually set it to the timestamp of the
304
# revision it was last changed
306
if ie.kind == 'directory':
307
item.type = tarfile.DIRTYPE
312
elif ie.kind == 'file':
313
item.type = tarfile.REGTYPE
314
fileobj = tree.get_file(ie.file_id)
315
item.size = _find_file_size(fileobj)
318
raise BzrError("don't know how to export {%s} of kind %r" %
319
(ie.file_id, ie.kind))
321
ball.addfile(item, fileobj)
350
if dp != ".bzrignore":
351
mutter(" export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
352
item, fileobj = ie.get_tar_item(root, dp, now, tree)
353
ball.addfile(item, fileobj)
323
356
exporters['tar'] = tar_exporter
325
358
def tgz_exporter(tree, dest, root):
329
362
def tbz_exporter(tree, dest, root):
330
363
tar_exporter(tree, dest, root, compression='bz2')
331
364
exporters['tbz2'] = tbz_exporter
334
def _find_file_size(fileobj):
335
offset = fileobj.tell()
338
size = fileobj.tell()
340
# gzip doesn't accept second argument to seek()
344
nread = len(fileobj.read())