17
17
"""Tree classes, representing directory at point in time.
21
import os.path, os, fnmatch, time
23
from osutils import pumpfile, filesize, quotefn, sha_file, \
24
joinpath, splitpath, appendpath, isdir, isfile, file_kind, fingerprint_file
26
from stat import S_ISREG, S_ISDIR, ST_MODE, ST_SIZE
21
from cStringIO import StringIO
24
from bzrlib.trace import mutter, note
25
from bzrlib.errors import BzrError, BzrCheckError
28
26
from bzrlib.inventory import Inventory
29
from bzrlib.trace import mutter, note
30
from bzrlib.errors import BzrError
27
from bzrlib.osutils import appendpath, fingerprint_file
74
69
def _get_inventory(self):
75
70
return self._inventory
72
def get_file_by_path(self, path):
73
return self.get_file(self._inventory.path2id(path))
77
75
inventory = property(_get_inventory,
78
76
doc="Inventory of this Tree")
80
78
def _check_retrieved(self, ie, f):
81
81
fp = fingerprint_file(f)
95
95
"store is probably damaged/corrupt"])
98
def print_file(self, fileid):
99
"""Print file with id `fileid` to stdout."""
98
def print_file(self, file_id):
99
"""Print file with id `file_id` to stdout."""
101
pumpfile(self.get_file(fileid), sys.stdout)
104
def export(self, dest, format='dir'):
101
sys.stdout.write(self.get_file_text(file_id))
104
def export(self, dest, format='dir', root=None):
105
105
"""Export this tree."""
107
107
exporter = exporters[format]
109
from bzrlib.errors import BzrCommandError
109
110
raise BzrCommandError("export format %r not supported" % format)
111
exporter(self, dest, root)
121
122
or at least passing a description to the constructor.
124
def __init__(self, store, inv):
125
def __init__(self, weave_store, inv, revision_id):
126
self._weave_store = weave_store
126
127
self._inventory = inv
128
self._revision_id = revision_id
130
def get_weave(self, file_id):
131
# FIXME: RevisionTree should be given a branch
132
# not a store, or the store should know the branch.
133
import bzrlib.transactions as transactions
134
return self._weave_store.get_weave(file_id,
135
transactions.PassThroughTransaction())
138
def get_file_lines(self, file_id):
139
ie = self._inventory[file_id]
140
weave = self.get_weave(file_id)
141
return weave.get(ie.revision)
144
def get_file_text(self, file_id):
145
return ''.join(self.get_file_lines(file_id))
128
148
def get_file(self, file_id):
129
ie = self._inventory[file_id]
130
f = self._store[ie.text_id]
131
mutter(" get fileid{%s} from %r" % (file_id, self))
132
self._check_retrieved(ie, f)
149
return StringIO(self.get_file_text(file_id))
135
151
def get_file_size(self, file_id):
136
152
return self._inventory[file_id].text_size
138
154
def get_file_sha1(self, file_id):
139
155
ie = self._inventory[file_id]
156
if ie.kind == "file":
159
def is_executable(self, file_id):
160
return self._inventory[file_id].executable
142
162
def has_filename(self, filename):
143
163
return bool(self.inventory.path2id(filename))
145
165
def list_files(self):
146
166
# The only files returned by this are those from the version
147
167
for path, entry in self.inventory.iter_entries():
148
yield path, 'V', entry.kind, entry.file_id
168
yield path, 'V', entry.kind, entry.file_id, entry
170
def get_symlink_target(self, file_id):
171
ie = self._inventory[file_id]
172
return ie.symlink_target;
151
175
class EmptyTree(Tree):
152
176
def __init__(self):
153
177
self._inventory = Inventory()
179
def get_symlink_target(self, file_id):
155
182
def has_filename(self, filename):
158
185
def list_files(self):
159
if False: # just to make it a generator
188
def __contains__(self, file_id):
189
return file_id in self._inventory
191
def get_file_sha1(self, file_id):
192
assert self._inventory[file_id].kind == "root_directory"
164
196
######################################################################
230
262
######################################################################
233
def dir_exporter(tree, dest):
265
def dir_exporter(tree, dest, root):
234
266
"""Export this tree to a new directory.
236
268
`dest` should not exist, and will be created holding the
242
274
:note: If the export fails, the destination directory will be
243
275
left in a half-assed state.
246
279
mutter('export version %r' % tree)
247
280
inv = tree.inventory
248
281
for dp, ie in inv.iter_entries():
250
fullpath = appendpath(dest, dp)
251
if kind == 'directory':
254
pumpfile(tree.get_file(ie.file_id), file(fullpath, 'wb'))
256
raise BzrError("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
257
mutter(" export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
282
ie.put_on_disk(dest, dp, tree)
258
284
exporters['dir'] = dir_exporter
262
288
except ImportError:
265
def tar_exporter(tree, dest, compression=None):
291
def get_root_name(dest):
292
"""Get just the root name for a tarball.
294
>>> get_root_name('mytar.tar')
296
>>> get_root_name('mytar.tar.bz2')
298
>>> get_root_name('tar.tar.tar.tgz')
300
>>> get_root_name('bzr-0.0.5.tar.gz')
302
>>> get_root_name('a/long/path/mytar.tgz')
304
>>> get_root_name('../parent/../dir/other.tbz2')
307
endings = ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2']
308
dest = os.path.basename(dest)
310
if dest.endswith(end):
311
return dest[:-len(end)]
313
def tar_exporter(tree, dest, root, compression=None):
266
314
"""Export this tree to a new tar file.
268
316
`dest` will be created holding the contents of this tree; if it
269
317
already exists, it will be clobbered, like with "tar -c".
319
from time import time
272
321
compression = str(compression or '')
323
root = get_root_name(dest)
274
325
ball = tarfile.open(dest, 'w:' + compression)
275
326
except tarfile.CompressionError, e:
278
329
inv = tree.inventory
279
330
for dp, ie in inv.iter_entries():
280
331
mutter(" export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
281
item = tarfile.TarInfo(dp)
282
# TODO: would be cool to actually set it to the timestamp of the
283
# revision it was last changed
285
if ie.kind == 'directory':
286
item.type = tarfile.DIRTYPE
291
elif ie.kind == 'file':
292
item.type = tarfile.REGTYPE
293
fileobj = tree.get_file(ie.file_id)
294
item.size = _find_file_size(fileobj)
297
raise BzrError("don't know how to export {%s} of kind %r" %
298
(ie.file_id, ie.kind))
332
item, fileobj = ie.get_tar_item(root, dp, now, tree)
300
333
ball.addfile(item, fileobj)
302
336
exporters['tar'] = tar_exporter
304
def tgz_exporter(tree, dest):
305
tar_exporter(tree, dest, compression='gz')
338
def tgz_exporter(tree, dest, root):
339
tar_exporter(tree, dest, root, compression='gz')
306
340
exporters['tgz'] = tgz_exporter
308
def tbz_exporter(tree, dest):
309
tar_exporter(tree, dest, compression='bz2')
342
def tbz_exporter(tree, dest, root):
343
tar_exporter(tree, dest, root, compression='bz2')
310
344
exporters['tbz2'] = tbz_exporter
313
def _find_file_size(fileobj):
314
offset = fileobj.tell()
317
size = fileobj.tell()
319
# gzip doesn't accept second argument to seek()
323
nread = len(fileobj.read())