17
17
"""Tree classes, representing directory at point in time.
21
import os.path, os, fnmatch
23
from osutils import pumpfile, compare_files, 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
28
from inventory import Inventory
29
from trace import mutter, note
30
from errors import bailout
23
from bzrlib.trace import mutter, note
24
from bzrlib.errors import BzrError
25
from bzrlib.inventory import Inventory
26
from bzrlib.osutils import pumpfile, appendpath, fingerprint_file
32
36
"""Abstract file tree.
34
38
There are several subclasses:
81
86
if ie.text_size != None:
82
87
if ie.text_size != fp['size']:
83
raise BzrError("mismatched size for file %r in %r" % (ie.file_id, self._store),
88
bailout("mismatched size for file %r in %r" % (ie.file_id, self._store),
84
89
["inventory expects %d bytes" % ie.text_size,
85
90
"file is actually %d bytes" % fp['size'],
86
91
"store is probably damaged/corrupt"])
88
93
if ie.text_sha1 != fp['sha1']:
89
raise BzrError("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
94
bailout("wrong SHA-1 for file %r in %r" % (ie.file_id, self._store),
90
95
["inventory expects %s" % ie.text_sha1,
91
96
"file is actually %s" % fp['sha1'],
92
97
"store is probably damaged/corrupt"])
98
103
pumpfile(self.get_file(fileid), sys.stdout)
101
def export(self, dest, format='dir', root=None):
102
"""Export this tree."""
104
exporter = exporters[format]
106
from bzrlib.errors import BzrCommandError
107
raise BzrCommandError("export format %r not supported" % format)
108
exporter(self, dest, root)
106
def export(self, dest):
107
"""Export this tree to a new directory.
109
`dest` should not exist, and will be created holding the
110
contents of this tree.
112
TODO: To handle subdirectories we need to create the
115
:note: If the export fails, the destination directory will be
116
left in a half-assed state.
119
mutter('export version %r' % self)
121
for dp, ie in inv.iter_entries():
123
fullpath = appendpath(dest, dp)
124
if kind == 'directory':
127
pumpfile(self.get_file(ie.file_id), file(fullpath, 'wb'))
129
bailout("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
130
mutter(" export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
223
245
if old_name != new_name:
224
246
yield (old_name, new_name)
228
######################################################################
231
def dir_exporter(tree, dest, root):
232
"""Export this tree to a new directory.
234
`dest` should not exist, and will be created holding the
235
contents of this tree.
237
TODO: To handle subdirectories we need to create the
240
:note: If the export fails, the destination directory will be
241
left in a half-assed state.
245
mutter('export version %r' % tree)
247
for dp, ie in inv.iter_entries():
249
fullpath = appendpath(dest, dp)
250
if kind == 'directory':
253
pumpfile(tree.get_file(ie.file_id), file(fullpath, 'wb'))
255
raise BzrError("don't know how to export {%s} of kind %r" % (ie.file_id, kind))
256
mutter(" export {%s} kind %s to %s" % (ie.file_id, kind, fullpath))
257
exporters['dir'] = dir_exporter
264
def get_root_name(dest):
265
"""Get just the root name for a tarball.
267
>>> get_root_name('mytar.tar')
269
>>> get_root_name('mytar.tar.bz2')
271
>>> get_root_name('tar.tar.tar.tgz')
273
>>> get_root_name('bzr-0.0.5.tar.gz')
275
>>> get_root_name('a/long/path/mytar.tgz')
277
>>> get_root_name('../parent/../dir/other.tbz2')
280
endings = ['.tar', '.tar.gz', '.tgz', '.tar.bz2', '.tbz2']
281
dest = os.path.basename(dest)
283
if dest.endswith(end):
284
return dest[:-len(end)]
286
def tar_exporter(tree, dest, root, compression=None):
287
"""Export this tree to a new tar file.
289
`dest` will be created holding the contents of this tree; if it
290
already exists, it will be clobbered, like with "tar -c".
292
from time import time
294
compression = str(compression or '')
296
root = get_root_name(dest)
298
ball = tarfile.open(dest, 'w:' + compression)
299
except tarfile.CompressionError, e:
300
raise BzrError(str(e))
301
mutter('export version %r' % tree)
303
for dp, ie in inv.iter_entries():
304
mutter(" export {%s} kind %s to %s" % (ie.file_id, ie.kind, dest))
305
item = tarfile.TarInfo(os.path.join(root, dp))
306
# TODO: would be cool to actually set it to the timestamp of the
307
# revision it was last changed
309
if ie.kind == 'directory':
310
item.type = tarfile.DIRTYPE
315
elif ie.kind == 'file':
316
item.type = tarfile.REGTYPE
317
fileobj = tree.get_file(ie.file_id)
318
item.size = _find_file_size(fileobj)
321
raise BzrError("don't know how to export {%s} of kind %r" %
322
(ie.file_id, ie.kind))
324
ball.addfile(item, fileobj)
326
exporters['tar'] = tar_exporter
328
def tgz_exporter(tree, dest, root):
329
tar_exporter(tree, dest, root, compression='gz')
330
exporters['tgz'] = tgz_exporter
332
def tbz_exporter(tree, dest, root):
333
tar_exporter(tree, dest, root, compression='bz2')
334
exporters['tbz2'] = tbz_exporter
337
def _find_file_size(fileobj):
338
offset = fileobj.tell()
341
size = fileobj.tell()
343
# gzip doesn't accept second argument to seek()
347
nread = len(fileobj.read())