25
25
At the moment every WorkingTree has its own branch. Remote
26
26
WorkingTrees aren't supported.
28
To get a WorkingTree, call Branch.working_tree():
28
To get a WorkingTree, call WorkingTree(dir[, branch])
32
# TODO: Don't allow WorkingTrees to be constructed for remote branches if
35
32
# FIXME: I don't know if writing out the cache from the destructor is really a
36
33
# good idea, because destructors are considered poor taste in Python, and it's
37
34
# not predictable when it will be written out.
43
40
# At the momenthey may alias the inventory and have old copies of it in memory.
45
42
from copy import deepcopy
43
from cStringIO import StringIO
50
from bzrlib.atomicfile import AtomicFile
50
51
from bzrlib.branch import (Branch,
179
181
not listed in the Inventory and vice versa.
182
def __init__(self, basedir=u'.', branch=None):
184
def __init__(self, basedir='.', branch=None, _inventory=None):
183
185
"""Construct a WorkingTree for basedir.
185
187
If the branch is not supplied, it is opened automatically.
191
193
from bzrlib.trace import note, mutter
192
194
assert isinstance(basedir, basestring), \
193
195
"base directory %r is not a string" % basedir
196
basedir = safe_unicode(basedir)
194
197
if branch is None:
195
198
branch = Branch.open(basedir)
196
199
assert isinstance(branch, Branch), \
212
215
mutter("write hc")
215
self._set_inventory(self.read_working_inventory())
218
if _inventory is None:
219
self._set_inventory(self.read_working_inventory())
221
self._set_inventory(_inventory)
217
223
def _set_inventory(self, inv):
218
224
self._inventory = inv
271
277
def abspath(self, filename):
272
278
return pathjoin(self.basedir, filename)
281
def create(branch, directory):
282
"""Create a workingtree for branch at directory.
284
If existing_directory already exists it must have a .bzr directory.
285
If it does not exist, it will be created.
287
This returns a new WorkingTree object for the new checkout.
289
TODO FIXME RBC 20060124 when we have checkout formats in place this
290
should accept an optional revisionid to checkout [and reject this if
291
checking out into the same dir as a pre-checkout-aware branch format.]
296
if e.errno != errno.EEXIST:
299
os.mkdir(pathjoin(directory, '.bzr'))
301
if e.errno != errno.EEXIST:
303
inv = branch.revision_tree(branch.last_revision()).inventory
304
wt = WorkingTree(directory, branch, inv)
305
wt._write_inventory(inv)
306
if branch.last_revision() is not None:
307
wt.set_last_revision(branch.last_revision())
308
wt.set_pending_merges([])
313
def create_standalone(directory):
314
"""Create a checkout and a branch at directory.
316
Directory must exist and be empty.
318
directory = safe_unicode(directory)
319
b = Branch.create(directory)
320
return WorkingTree.create(b, directory)
274
322
def relpath(self, abs):
275
323
"""Return the local path portion from a given absolute path."""
276
324
return relpath(self.basedir, abs)
422
470
These are revisions that have been merged into the working
423
471
directory but not yet committed.
425
cfn = self.branch._rel_controlfilename('pending-merges')
426
if not self.branch._transport.has(cfn):
474
merges_file = self._controlfile('pending-merges')
476
if e.errno != errno.ENOENT:
429
for l in self.branch.controlfile('pending-merges', 'r').readlines():
480
for l in merges_file.readlines():
430
481
p.append(l.rstrip('\n'))
484
def _abs_controlfilename(self, name):
485
"""return the path for the controlfile name in the workingtree."""
486
return pathjoin(self.basedir, '.bzr', name)
488
def _controlfile(self, name, encoding='utf-8'):
489
"""Get a control file for the checkout.
491
FIXME RBC 20060123 when storage comes in this should be a lockable
495
return codecs.open(self._abs_controlfilename(name), encoding=encoding)
433
497
@needs_write_lock
434
498
def set_pending_merges(self, rev_list):
435
self.branch.put_controlfile('pending-merges', '\n'.join(rev_list))
500
sio.write('\n'.join(rev_list).encode('utf-8'))
502
f = AtomicFile(self._abs_controlfilename('pending-merges'))
437
509
def get_symlink_target(self, file_id):
438
510
return os.readlink(self.id2abspath(file_id))
683
755
other_revision = None
684
756
merge_inner(self.branch,
685
757
self.branch.basis_tree(),
686
self.branch.revision_tree(other_revision))
758
self.branch.revision_tree(other_revision),
760
self.set_last_revision(self.branch.last_revision())
818
892
"""Read the working inventory."""
819
893
# ElementTree does its own conversion from UTF-8, so open in
821
f = self.branch.controlfile('inventory', 'rb')
822
return bzrlib.xml5.serializer_v5.read_inventory(f)
895
return bzrlib.xml5.serializer_v5.read_inventory(
896
self._controlfile('inventory', encoding=None))
824
898
@needs_write_lock
825
899
def remove(self, files, verbose=False):
870
944
merge_inner(self.branch, old_tree,
871
945
self, ignore_zero=True,
872
946
backup_files=backups,
873
interesting_files=filenames)
947
interesting_files=filenames,
874
949
if not len(filenames):
875
950
self.set_pending_merges([])
927
1002
@needs_write_lock
928
1003
def _write_inventory(self, inv):
929
1004
"""Write inventory as the current inventory."""
930
from cStringIO import StringIO
931
from bzrlib.atomicfile import AtomicFile
932
1005
sio = StringIO()
933
1006
bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
935
f = AtomicFile(self.branch.controlfilename('inventory'))
1008
f = AtomicFile(self._abs_controlfilename('inventory'))
937
1010
pumpfile(sio, f)