~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

Give branch its own basis tree and last_revision methods; deprecated branch.working_tree()

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
                           is_control_file,
56
56
                           quotefn)
57
57
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
58
import bzrlib.errors as errors
58
59
from bzrlib.errors import (BzrCheckError,
59
60
                           BzrError,
60
61
                           DivergedBranches,
294
295
 
295
296
    def abspath(self, filename):
296
297
        return pathjoin(self.basedir, filename)
 
298
    
 
299
    def basis_tree(self):
 
300
        """Return RevisionTree for the current last revision."""
 
301
        revision_id = self.last_revision()
 
302
        if revision_id is not None:
 
303
            try:
 
304
                xml = self.read_basis_inventory(revision_id)
 
305
                inv = bzrlib.xml5.serializer_v5.read_inventory_from_string(xml)
 
306
                return bzrlib.tree.RevisionTree(self.branch.repository, inv,
 
307
                                                revision_id)
 
308
            except NoSuchFile:
 
309
                pass
 
310
        return self.branch.repository.revision_tree(revision_id)
297
311
 
298
312
    @staticmethod
299
313
    def create(branch, directory):
318
332
        except OSError, e:
319
333
            if e.errno != errno.EEXIST:
320
334
                raise
321
 
        inv = branch.repository.revision_tree(branch.last_revision()).inventory
 
335
        revision_tree = branch.repository.revision_tree(branch.last_revision())
 
336
        inv = revision_tree.inventory
322
337
        wt = WorkingTree(directory, branch, inv)
323
338
        wt._write_inventory(inv)
 
339
        wt.set_root_id(revision_tree.inventory.root.file_id)
324
340
        if branch.last_revision() is not None:
325
341
            wt.set_last_revision(branch.last_revision())
326
342
        wt.set_pending_merges([])
359
375
        ## XXX: badly named; this is not in the store at all
360
376
        return self.abspath(self.id2path(file_id))
361
377
 
 
378
    @needs_read_lock
 
379
    def clone(self, to_directory, revision=None):
 
380
        """Copy this working tree to a new directory.
 
381
        
 
382
        Currently this will make a new standalone branch at to_directory,
 
383
        but it is planned to change this to use the same branch style that this
 
384
        current tree uses (standalone if standalone, repository if repository)
 
385
        - so that this really is a clone. FIXME RBC 20060127 do this.
 
386
        FIXME MORE RBC 20060127 failed to reach consensus on this in #bzr.
 
387
 
 
388
        If you want a standalone branch, please use branch.clone(to_directory)
 
389
        followed by WorkingTree.create(cloned_branch, to_directory) which is
 
390
        the supported api to produce that.
 
391
 
 
392
        revision
 
393
            If not None, the cloned tree will have its last revision set to 
 
394
            revision, and if a branch is being copied it will be informed
 
395
            of the revision to result in. 
 
396
    
 
397
        to_directory -- The destination directory: Must not exist.
 
398
        """
 
399
        to_directory = safe_unicode(to_directory)
 
400
        os.mkdir(to_directory)
 
401
        # FIXME here is where the decision to clone the branch should happen.
 
402
        if revision is None:
 
403
            revision = self.last_revision()
 
404
        cloned_branch = self.branch.clone(to_directory, revision)
 
405
        return  WorkingTree.create(cloned_branch, to_directory)
 
406
 
362
407
    @needs_write_lock
363
408
    def commit(self, *args, **kwargs):
364
409
        from bzrlib.commit import Commit
453
498
 
454
499
            try:
455
500
                kind = file_kind(fullpath)
456
 
            except OSError:
 
501
            except OSError, e:
 
502
                if e.errno == errno.ENOENT:
 
503
                    raise NoSuchFile(fullpath)
457
504
                # maybe something better?
458
505
                raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
459
506
 
753
800
                    other_revision = None
754
801
                repository = self.branch.repository
755
802
                merge_inner(self.branch,
756
 
                            self.branch.basis_tree(), 
 
803
                            self.basis_tree(), 
757
804
                            repository.revision_tree(other_revision),
758
805
                            this_tree=self)
759
806
                self.set_last_revision(self.branch.last_revision())
855
902
    def kind(self, file_id):
856
903
        return file_kind(self.id2abspath(file_id))
857
904
 
 
905
    def last_revision(self):
 
906
        """Return the last revision id of this working tree.
 
907
 
 
908
        In early branch formats this was == the branch last_revision,
 
909
        but that cannot be relied upon - for working tree operations,
 
910
        always use tree.last_revision().
 
911
        """
 
912
        return self.branch.last_revision()
 
913
 
858
914
    def lock_read(self):
859
915
        """See Branch.lock_read, and WorkingTree.unlock."""
860
916
        return self.branch.lock_read()
870
926
        if old_revision is not None:
871
927
            try:
872
928
                path = self._basis_inventory_name(old_revision)
873
 
                path = self.branch.control_files._escape(path)
874
 
                self.branch.control_files._transport.delete(path)
 
929
                path = self._control_files._escape(path)
 
930
                self._control_files._transport.delete(path)
875
931
            except NoSuchFile:
876
932
                pass
 
933
        if new_revision is None:
 
934
            self.branch.set_revision_history([])
 
935
            return
 
936
        # current format is locked in with the branch
 
937
        revision_history = self.branch.revision_history()
 
938
        try:
 
939
            position = revision_history.index(new_revision)
 
940
        except ValueError:
 
941
            raise errors.NoSuchRevision(self.branch, new_revision)
 
942
        self.branch.set_revision_history(revision_history[:position + 1])
877
943
        try:
878
944
            xml = self.branch.repository.get_inventory_xml(new_revision)
879
945
            path = self._basis_inventory_name(new_revision)
880
 
            self.branch.control_files.put_utf8(path, xml)
 
946
            self._control_files.put_utf8(path, xml)
881
947
        except WeaveRevisionNotPresent:
882
948
            pass
883
949
 
884
950
    def read_basis_inventory(self, revision_id):
885
951
        """Read the cached basis inventory."""
886
952
        path = self._basis_inventory_name(revision_id)
887
 
        return self.branch.control_files.get_utf8(path).read()
 
953
        return self._control_files.get_utf8(path).read()
888
954
        
889
955
    @needs_read_lock
890
956
    def read_working_inventory(self):
891
957
        """Read the working inventory."""
892
958
        # ElementTree does its own conversion from UTF-8, so open in
893
959
        # binary.
894
 
        return bzrlib.xml5.serializer_v5.read_inventory(
 
960
        result = bzrlib.xml5.serializer_v5.read_inventory(
895
961
            self._control_files.get('inventory'))
 
962
        self._set_inventory(result)
 
963
        return result
896
964
 
897
965
    @needs_write_lock
898
966
    def remove(self, files, verbose=False):
939
1007
    def revert(self, filenames, old_tree=None, backups=True):
940
1008
        from bzrlib.merge import merge_inner
941
1009
        if old_tree is None:
942
 
            old_tree = self.branch.basis_tree()
 
1010
            old_tree = self.basis_tree()
943
1011
        merge_inner(self.branch, old_tree,
944
1012
                    self, ignore_zero=True,
945
1013
                    backup_files=backups, 
981
1049
        inv._byid[inv.root.file_id] = inv.root
982
1050
        for fid in inv:
983
1051
            entry = inv[fid]
984
 
            if entry.parent_id in (None, orig_root_id):
 
1052
            if entry.parent_id == orig_root_id:
985
1053
                entry.parent_id = inv.root.file_id
986
1054
        self._write_inventory(inv)
987
1055
 
999
1067
        # of a nasty hack; probably it's better to have a transaction object,
1000
1068
        # which can do some finalization when it's either successfully or
1001
1069
        # unsuccessfully completed.  (Denys's original patch did that.)
1002
 
        if self._hashcache.needs_write and self.branch.control_files._lock_count==1:
 
1070
        if self._hashcache.needs_write and self._control_files._lock_count==1:
1003
1071
            self._hashcache.write()
1004
1072
        return self.branch.unlock()
1005
1073