~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Martin Pool
  • Date: 2006-02-01 12:24:35 UTC
  • mfrom: (1534.4.32 branch-formats)
  • mto: This revision was merged to the branch mainline in revision 1553.
  • Revision ID: mbp@sourcefrog.net-20060201122435-53f3efb1b5749fe1
[merge] branch-formats branch, and reconcile changes

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,
 
52
                           BzrBranchFormat4,
 
53
                           BzrBranchFormat5,
 
54
                           BzrBranchFormat6,
51
55
                           is_control_file,
52
56
                           quotefn)
 
57
from bzrlib.decorators import needs_read_lock, needs_write_lock
53
58
from bzrlib.errors import (BzrCheckError,
54
59
                           BzrError,
55
60
                           DivergedBranches,
58
63
                           NoSuchFile,
59
64
                           NotVersionedError)
60
65
from bzrlib.inventory import InventoryEntry
 
66
from bzrlib.lockable_files import LockableFiles
61
67
from bzrlib.osutils import (appendpath,
62
68
                            compact_date,
63
69
                            file_kind,
65
71
                            getcwd,
66
72
                            pathjoin,
67
73
                            pumpfile,
 
74
                            safe_unicode,
68
75
                            splitpath,
69
76
                            rand_bytes,
70
77
                            abspath,
72
79
                            realpath,
73
80
                            relpath,
74
81
                            rename)
 
82
from bzrlib.symbol_versioning import *
75
83
from bzrlib.textui import show_status
76
84
import bzrlib.tree
77
85
from bzrlib.trace import mutter
 
86
from bzrlib.transport import get_transport
78
87
import bzrlib.xml5
79
 
from bzrlib.decorators import needs_read_lock, needs_write_lock
80
88
 
81
89
 
82
90
def gen_file_id(name):
178
186
    not listed in the Inventory and vice versa.
179
187
    """
180
188
 
181
 
    def __init__(self, basedir=u'.', branch=None):
 
189
    def __init__(self, basedir='.', branch=None, _inventory=None, _control_files=None):
182
190
        """Construct a WorkingTree for basedir.
183
191
 
184
192
        If the branch is not supplied, it is opened automatically.
190
198
        from bzrlib.trace import note, mutter
191
199
        assert isinstance(basedir, basestring), \
192
200
            "base directory %r is not a string" % basedir
 
201
        basedir = safe_unicode(basedir)
 
202
        mutter("openeing working tree %r", basedir)
193
203
        if branch is None:
194
204
            branch = Branch.open(basedir)
195
205
        assert isinstance(branch, Branch), \
196
206
            "branch %r is not a Branch" % branch
197
207
        self.branch = branch
198
208
        self.basedir = realpath(basedir)
 
209
        # if branch is at our basedir and is a format 6 or less
 
210
        if (isinstance(self.branch._branch_format,
 
211
                       (BzrBranchFormat4, BzrBranchFormat5, BzrBranchFormat6))
 
212
            # might be able to share control object
 
213
            and self.branch.base.split('/')[-2] == self.basedir.split('/')[-1]):
 
214
            self._control_files = self.branch.control_files
 
215
        elif _control_files is not None:
 
216
            assert False, "not done yet"
 
217
#            self._control_files = _control_files
 
218
        else:
 
219
            self._control_files = LockableFiles(
 
220
                get_transport(self.basedir).clone(bzrlib.BZRDIR), 'branch-lock')
199
221
 
200
222
        # update the whole cache up front and write to disk if anything changed;
201
223
        # in the future we might want to do this more selectively
211
233
            mutter("write hc")
212
234
            hc.write()
213
235
 
214
 
        self._set_inventory(self.read_working_inventory())
 
236
        if _inventory is None:
 
237
            self._set_inventory(self.read_working_inventory())
 
238
        else:
 
239
            self._set_inventory(_inventory)
215
240
 
216
241
    def _set_inventory(self, inv):
217
242
        self._inventory = inv
270
295
    def abspath(self, filename):
271
296
        return pathjoin(self.basedir, filename)
272
297
 
 
298
    @staticmethod
 
299
    def create(branch, directory):
 
300
        """Create a workingtree for branch at directory.
 
301
 
 
302
        If existing_directory already exists it must have a .bzr directory.
 
303
        If it does not exist, it will be created.
 
304
 
 
305
        This returns a new WorkingTree object for the new checkout.
 
306
 
 
307
        TODO FIXME RBC 20060124 when we have checkout formats in place this
 
308
        should accept an optional revisionid to checkout [and reject this if
 
309
        checking out into the same dir as a pre-checkout-aware branch format.]
 
310
        """
 
311
        try:
 
312
            os.mkdir(directory)
 
313
        except OSError, e:
 
314
            if e.errno != errno.EEXIST:
 
315
                raise
 
316
        try:
 
317
            os.mkdir(pathjoin(directory, '.bzr'))
 
318
        except OSError, e:
 
319
            if e.errno != errno.EEXIST:
 
320
                raise
 
321
        inv = branch.repository.revision_tree(branch.last_revision()).inventory
 
322
        wt = WorkingTree(directory, branch, inv)
 
323
        wt._write_inventory(inv)
 
324
        if branch.last_revision() is not None:
 
325
            wt.set_last_revision(branch.last_revision())
 
326
        wt.set_pending_merges([])
 
327
        wt.revert([])
 
328
        return wt
 
329
 
 
330
    @staticmethod
 
331
    def create_standalone(directory):
 
332
        """Create a checkout and a branch at directory.
 
333
 
 
334
        Directory must exist and be empty.
 
335
        """
 
336
        directory = safe_unicode(directory)
 
337
        b = Branch.create(directory)
 
338
        return WorkingTree.create(b, directory)
 
339
 
273
340
    def relpath(self, abs):
274
341
        """Return the local path portion from a given absolute path."""
275
342
        return relpath(self.basedir, abs)
293
360
        return self.abspath(self.id2path(file_id))
294
361
 
295
362
    @needs_write_lock
296
 
    def commit(self, *args, **kw):
 
363
    def commit(self, *args, **kwargs):
297
364
        from bzrlib.commit import Commit
298
 
        Commit().commit(self.branch, *args, **kw)
 
365
        # args for wt.commit start at message from the Commit.commit method,
 
366
        # but with branch a kwarg now, passing in args as is results in the
 
367
        #message being used for the branch
 
368
        args = (DEPRECATED_PARAMETER, ) + args
 
369
        Commit().commit(working_tree=self, *args, **kwargs)
299
370
        self._set_inventory(self.read_working_inventory())
300
371
 
301
372
    def id2abspath(self, file_id):
419
490
        directory but not yet committed.
420
491
        """
421
492
        try:
422
 
            f = self.branch.control_files.get_utf8('pending-merges')
423
 
        except NoSuchFile:
 
493
            merges_file = self._control_files.get_utf8('pending-merges')
 
494
        except OSError, e:
 
495
            if e.errno != errno.ENOENT:
 
496
                raise
424
497
            return []
425
498
        p = []
426
 
        for l in f.readlines():
 
499
        for l in merges_file.readlines():
427
500
            p.append(l.rstrip('\n'))
428
501
        return p
429
502
 
430
503
    @needs_write_lock
431
504
    def set_pending_merges(self, rev_list):
432
 
        self.branch.control_files.put_utf8('pending-merges', '\n'.join(rev_list))
 
505
        self._control_files.put_utf8('pending-merges', '\n'.join(rev_list))
433
506
 
434
507
    def get_symlink_target(self, file_id):
435
508
        return os.readlink(self.id2abspath(file_id))
681
754
                repository = self.branch.repository
682
755
                merge_inner(self.branch,
683
756
                            self.branch.basis_tree(), 
684
 
                            repository.revision_tree(other_revision))
 
757
                            repository.revision_tree(other_revision),
 
758
                            this_tree=self)
 
759
                self.set_last_revision(self.branch.last_revision())
685
760
            return count
686
761
        finally:
687
762
            source.unlock()
816
891
        """Read the working inventory."""
817
892
        # ElementTree does its own conversion from UTF-8, so open in
818
893
        # binary.
819
 
        f = self.branch.control_files.get('inventory')
820
 
        return bzrlib.xml5.serializer_v5.read_inventory(f)
 
894
        return bzrlib.xml5.serializer_v5.read_inventory(
 
895
            self._control_files.get('inventory'))
821
896
 
822
897
    @needs_write_lock
823
898
    def remove(self, files, verbose=False):
868
943
        merge_inner(self.branch, old_tree,
869
944
                    self, ignore_zero=True,
870
945
                    backup_files=backups, 
871
 
                    interesting_files=filenames)
 
946
                    interesting_files=filenames,
 
947
                    this_tree=self)
872
948
        if not len(filenames):
873
949
            self.set_pending_merges([])
874
950
 
930
1006
    @needs_write_lock
931
1007
    def _write_inventory(self, inv):
932
1008
        """Write inventory as the current inventory."""
933
 
        from cStringIO import StringIO
934
 
        from bzrlib.atomicfile import AtomicFile
935
1009
        sio = StringIO()
936
1010
        bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
937
1011
        sio.seek(0)
938
 
        f = AtomicFile(self.branch.control_files.controlfilename('inventory'))
939
 
        try:
940
 
            pumpfile(sio, f)
941
 
            f.commit()
942
 
        finally:
943
 
            f.close()
 
1012
        self._control_files.put('inventory', sio)
944
1013
        self._set_inventory(inv)
945
1014
        mutter('wrote working inventory')
946
1015