~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

Move working tree initialisation out from  Branch.initialize, deprecated Branch.initialize to Branch.create.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
At the moment every WorkingTree has its own branch.  Remote
26
26
WorkingTrees aren't supported.
27
27
 
28
 
To get a WorkingTree, call Branch.working_tree():
 
28
To get a WorkingTree, call WorkingTree(dir[, branch])
29
29
"""
30
30
 
31
31
 
32
 
# TODO: Don't allow WorkingTrees to be constructed for remote branches if 
33
 
# they don't work.
34
 
 
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.
44
41
 
45
42
from copy import deepcopy
 
43
from cStringIO import StringIO
 
44
import errno
 
45
import fnmatch
46
46
import os
47
47
import stat
48
 
import fnmatch
49
48
 
 
49
 
 
50
from bzrlib.atomicfile import AtomicFile
50
51
from bzrlib.branch import (Branch,
51
52
                           is_control_file,
52
53
                           needs_read_lock,
66
67
                            getcwd,
67
68
                            pathjoin,
68
69
                            pumpfile,
 
70
                            safe_unicode,
69
71
                            splitpath,
70
72
                            rand_bytes,
71
73
                            abspath,
179
181
    not listed in the Inventory and vice versa.
180
182
    """
181
183
 
182
 
    def __init__(self, basedir=u'.', branch=None):
 
184
    def __init__(self, basedir='.', branch=None, _inventory=None):
183
185
        """Construct a WorkingTree for basedir.
184
186
 
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")
213
216
            hc.write()
214
217
 
215
 
        self._set_inventory(self.read_working_inventory())
 
218
        if _inventory is None:
 
219
            self._set_inventory(self.read_working_inventory())
 
220
        else:
 
221
            self._set_inventory(_inventory)
216
222
 
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)
273
279
 
 
280
    @staticmethod
 
281
    def create(branch, directory):
 
282
        """Create a workingtree for branch at directory.
 
283
 
 
284
        If existing_directory already exists it must have a .bzr directory.
 
285
        If it does not exist, it will be created.
 
286
 
 
287
        This returns a new WorkingTree object for the new checkout.
 
288
 
 
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.]
 
292
        """
 
293
        try:
 
294
            os.mkdir(directory)
 
295
        except OSError, e:
 
296
            if e.errno != errno.EEXIST:
 
297
                raise
 
298
        try:
 
299
            os.mkdir(pathjoin(directory, '.bzr'))
 
300
        except OSError, e:
 
301
            if e.errno != errno.EEXIST:
 
302
                raise
 
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([])
 
309
        wt.revert([])
 
310
        return wt
 
311
 
 
312
    @staticmethod
 
313
    def create_standalone(directory):
 
314
        """Create a checkout and a branch at directory.
 
315
 
 
316
        Directory must exist and be empty.
 
317
        """
 
318
        directory = safe_unicode(directory)
 
319
        b = Branch.create(directory)
 
320
        return WorkingTree.create(b, directory)
 
321
 
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.
424
472
        """
425
 
        cfn = self.branch._rel_controlfilename('pending-merges')
426
 
        if not self.branch._transport.has(cfn):
 
473
        try:
 
474
            merges_file = self._controlfile('pending-merges')
 
475
        except OSError, e:
 
476
            if e.errno != errno.ENOENT:
 
477
                raise
427
478
            return []
428
479
        p = []
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'))
431
482
        return p
432
483
 
 
484
    def _abs_controlfilename(self, name):
 
485
        """return the path for the controlfile name in the workingtree."""
 
486
        return pathjoin(self.basedir, '.bzr', name)
 
487
 
 
488
    def _controlfile(self, name, encoding='utf-8'):
 
489
        """Get a control file for the checkout.
 
490
 
 
491
        FIXME RBC 20060123 when storage comes in this should be a lockable
 
492
        files group ?.
 
493
        """
 
494
        import codecs
 
495
        return codecs.open(self._abs_controlfilename(name), encoding=encoding)
 
496
 
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))
 
499
        sio = StringIO()
 
500
        sio.write('\n'.join(rev_list).encode('utf-8'))
 
501
        sio.seek(0)
 
502
        f = AtomicFile(self._abs_controlfilename('pending-merges'))
 
503
        try:
 
504
            pumpfile(sio, f)
 
505
            f.commit()
 
506
        finally:
 
507
            f.close()
436
508
 
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),
 
759
                            this_tree=self)
 
760
                self.set_last_revision(self.branch.last_revision())
687
761
            return count
688
762
        finally:
689
763
            source.unlock()
818
892
        """Read the working inventory."""
819
893
        # ElementTree does its own conversion from UTF-8, so open in
820
894
        # binary.
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))
823
897
 
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,
 
948
                    this_tree=self)
874
949
        if not len(filenames):
875
950
            self.set_pending_merges([])
876
951
 
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)
934
1007
        sio.seek(0)
935
 
        f = AtomicFile(self.branch.controlfilename('inventory'))
 
1008
        f = AtomicFile(self._abs_controlfilename('inventory'))
936
1009
        try:
937
1010
            pumpfile(sio, f)
938
1011
            f.commit()