533
558
__contains__ = has_id
535
560
def get_file_size(self, file_id):
536
return os.path.getsize(self.id2abspath(file_id))
561
"""See Tree.get_file_size"""
563
return os.path.getsize(self.id2abspath(file_id))
565
if e.errno != errno.ENOENT:
539
def get_file_sha1(self, file_id, path=None):
571
def get_file_sha1(self, file_id, path=None, stat_value=None):
541
573
path = self._inventory.id2path(file_id)
542
return self._hashcache.get_sha1(path)
574
return self._hashcache.get_sha1(path, stat_value)
544
576
def get_file_mtime(self, file_id, path=None):
546
path = self._inventory.id2path(file_id)
578
path = self.inventory.id2path(file_id)
547
579
return os.lstat(self.abspath(path)).st_mtime
581
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
582
file_id = self.path2id(path)
583
return self._inventory[file_id].executable
585
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
586
mode = stat_result.st_mode
587
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
549
589
if not supports_executable():
550
590
def is_executable(self, file_id, path=None):
551
591
return self._inventory[file_id].executable
593
_is_executable_from_path_and_stat = \
594
_is_executable_from_path_and_stat_from_basis
553
596
def is_executable(self, file_id, path=None):
555
path = self._inventory.id2path(file_id)
598
path = self.id2path(file_id)
556
599
mode = os.lstat(self.abspath(path)).st_mode
557
600
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
560
def add(self, files, ids=None):
561
"""Make files versioned.
563
Note that the command line normally calls smart_add instead,
564
which can automatically recurse.
566
This adds the files to the inventory, so that they will be
567
recorded by the next commit.
570
List of paths to add, relative to the base of the tree.
573
If set, use these instead of automatically generated ids.
574
Must be the same length as the list of files, but may
575
contain None for ids that are to be autogenerated.
577
TODO: Perhaps have an option to add the ids even if the files do
580
TODO: Perhaps callback with the ids and paths as they're added.
602
_is_executable_from_path_and_stat = \
603
_is_executable_from_path_and_stat_from_stat
605
@needs_tree_write_lock
606
def _add(self, files, ids, kinds):
607
"""See MutableTree._add."""
582
608
# TODO: Re-adding a file that is removed in the working copy
583
609
# should probably put it back with the previous ID.
584
if isinstance(files, basestring):
585
assert(ids is None or isinstance(ids, basestring))
591
ids = [None] * len(files)
593
assert(len(ids) == len(files))
595
inv = self.read_working_inventory()
596
for f,file_id in zip(files, ids):
597
if self.is_control_filename(f):
598
raise BzrError("cannot add control file %s" % quotefn(f))
603
raise BzrError("cannot add top-level %r" % f)
605
fullpath = normpath(self.abspath(f))
608
kind = file_kind(fullpath)
610
if e.errno == errno.ENOENT:
611
raise NoSuchFile(fullpath)
612
# maybe something better?
613
raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
615
if not InventoryEntry.versionable_kind(kind):
616
raise BzrError('cannot add: not a versionable file ('
617
'i.e. regular file, symlink or directory): %s' % quotefn(f))
610
# the read and write working inventory should not occur in this
611
# function - they should be part of lock_write and unlock.
613
for f, file_id, kind in zip(files, ids, kinds):
619
614
if file_id is None:
620
615
inv.add_path(f, kind=kind)
622
617
inv.add_path(f, kind=kind, file_id=file_id)
618
self._inventory_is_modified = True
624
self._write_inventory(inv)
620
@needs_tree_write_lock
621
def _gather_kinds(self, files, kinds):
622
"""See MutableTree._gather_kinds."""
623
for pos, f in enumerate(files):
624
if kinds[pos] is None:
625
fullpath = normpath(self.abspath(f))
627
kinds[pos] = file_kind(fullpath)
629
if e.errno == errno.ENOENT:
630
raise errors.NoSuchFile(fullpath)
626
632
@needs_write_lock
633
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
634
"""Add revision_id as a parent.
636
This is equivalent to retrieving the current list of parent ids
637
and setting the list to its value plus revision_id.
639
:param revision_id: The revision id to add to the parent list. It may
640
be a ghost revision as long as its not the first parent to be added,
641
or the allow_leftmost_as_ghost parameter is set True.
642
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
644
parents = self.get_parent_ids() + [revision_id]
645
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
646
or allow_leftmost_as_ghost)
648
@needs_tree_write_lock
649
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
650
"""Add revision_id, tree tuple as a parent.
652
This is equivalent to retrieving the current list of parent trees
653
and setting the list to its value plus parent_tuple. See also
654
add_parent_tree_id - if you only have a parent id available it will be
655
simpler to use that api. If you have the parent already available, using
656
this api is preferred.
658
:param parent_tuple: The (revision id, tree) to add to the parent list.
659
If the revision_id is a ghost, pass None for the tree.
660
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
662
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
663
if len(parent_ids) > 1:
664
# the leftmost may have already been a ghost, preserve that if it
666
allow_leftmost_as_ghost = True
667
self.set_parent_ids(parent_ids,
668
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
670
@needs_tree_write_lock
627
671
def add_pending_merge(self, *revision_ids):
628
672
# TODO: Perhaps should check at this point that the
629
673
# history of the revision is actually present?
630
p = self.pending_merges()
674
parents = self.get_parent_ids()
632
676
for rev_id in revision_ids:
677
if rev_id in parents:
679
parents.append(rev_id)
638
self.set_pending_merges(p)
641
def pending_merges(self):
642
"""Return a list of pending merges.
644
These are revisions that have been merged into the working
645
directory but not yet committed.
682
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
684
def path_content_summary(self, path, _lstat=os.lstat,
685
_mapper=osutils.file_kind_from_stat_mode):
686
"""See Tree.path_content_summary."""
687
abspath = self.abspath(path)
648
merges_file = self._control_files.get_utf8('pending-merges')
689
stat_result = _lstat(abspath)
649
690
except OSError, e:
650
if e.errno != errno.ENOENT:
654
for l in merges_file.readlines():
655
p.append(l.rstrip('\n'))
691
if getattr(e, 'errno', None) == errno.ENOENT:
693
return ('missing', None, None, None)
694
# propagate other errors
696
kind = _mapper(stat_result.st_mode)
698
size = stat_result.st_size
699
# try for a stat cache lookup
700
executable = self._is_executable_from_path_and_stat(path, stat_result)
701
return (kind, size, executable, self._sha_from_stat(
703
elif kind == 'directory':
704
# perhaps it looks like a plain directory, but it's really a
706
if self._directory_is_tree_reference(path):
707
kind = 'tree-reference'
708
return kind, None, None, None
709
elif kind == 'symlink':
710
return ('symlink', None, None, os.readlink(abspath))
712
return (kind, None, None, None)
714
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
715
"""Common ghost checking functionality from set_parent_*.
717
This checks that the left hand-parent exists if there are any
720
if len(revision_ids) > 0:
721
leftmost_id = revision_ids[0]
722
if (not allow_leftmost_as_ghost and not
723
self.branch.repository.has_revision(leftmost_id)):
724
raise errors.GhostRevisionUnusableHere(leftmost_id)
726
def _set_merges_from_parent_ids(self, parent_ids):
727
merges = parent_ids[1:]
728
self._transport.put_bytes('pending-merges', '\n'.join(merges),
729
mode=self._control_files._file_mode)
731
def _filter_parent_ids_by_ancestry(self, revision_ids):
732
"""Check that all merged revisions are proper 'heads'.
734
This will always return the first revision_id, and any merged revisions
737
if len(revision_ids) == 0:
739
graph = self.branch.repository.get_graph()
740
heads = graph.heads(revision_ids)
741
new_revision_ids = revision_ids[:1]
742
for revision_id in revision_ids[1:]:
743
if revision_id in heads and revision_id not in new_revision_ids:
744
new_revision_ids.append(revision_id)
745
if new_revision_ids != revision_ids:
746
trace.mutter('requested to set revision_ids = %s,'
747
' but filtered to %s', revision_ids, new_revision_ids)
748
return new_revision_ids
750
@needs_tree_write_lock
751
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
752
"""Set the parent ids to revision_ids.
754
See also set_parent_trees. This api will try to retrieve the tree data
755
for each element of revision_ids from the trees repository. If you have
756
tree data already available, it is more efficient to use
757
set_parent_trees rather than set_parent_ids. set_parent_ids is however
758
an easier API to use.
760
:param revision_ids: The revision_ids to set as the parent ids of this
761
working tree. Any of these may be ghosts.
763
self._check_parents_for_ghosts(revision_ids,
764
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
765
for revision_id in revision_ids:
766
_mod_revision.check_not_reserved_id(revision_id)
768
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
770
if len(revision_ids) > 0:
771
self.set_last_revision(revision_ids[0])
773
self.set_last_revision(_mod_revision.NULL_REVISION)
775
self._set_merges_from_parent_ids(revision_ids)
777
@needs_tree_write_lock
778
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
779
"""See MutableTree.set_parent_trees."""
780
parent_ids = [rev for (rev, tree) in parents_list]
781
for revision_id in parent_ids:
782
_mod_revision.check_not_reserved_id(revision_id)
784
self._check_parents_for_ghosts(parent_ids,
785
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
787
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
789
if len(parent_ids) == 0:
790
leftmost_parent_id = _mod_revision.NULL_REVISION
791
leftmost_parent_tree = None
793
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
795
if self._change_last_revision(leftmost_parent_id):
796
if leftmost_parent_tree is None:
797
# If we don't have a tree, fall back to reading the
798
# parent tree from the repository.
799
self._cache_basis_inventory(leftmost_parent_id)
801
inv = leftmost_parent_tree.inventory
802
xml = self._create_basis_xml_from_inventory(
803
leftmost_parent_id, inv)
804
self._write_basis_inventory(xml)
805
self._set_merges_from_parent_ids(parent_ids)
807
@needs_tree_write_lock
659
808
def set_pending_merges(self, rev_list):
660
self._control_files.put_utf8('pending-merges', '\n'.join(rev_list))
809
parents = self.get_parent_ids()
810
leftmost = parents[:1]
811
new_parents = leftmost + rev_list
812
self.set_parent_ids(new_parents)
814
@needs_tree_write_lock
663
815
def set_merge_modified(self, modified_hashes):
664
816
def iter_stanzas():
665
817
for file_id, hash in modified_hashes.iteritems():
666
yield Stanza(file_id=file_id, hash=hash)
818
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
667
819
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
821
def _sha_from_stat(self, path, stat_result):
822
"""Get a sha digest from the tree's stat cache.
824
The default implementation assumes no stat cache is present.
826
:param path: The path.
827
:param stat_result: The stat result being looked up.
670
831
def _put_rio(self, filename, stanzas, header):
832
self._must_be_locked()
671
833
my_file = rio_file(stanzas, header)
672
self._control_files.put(filename, my_file)
834
self._transport.put_file(filename, my_file,
835
mode=self._control_files._file_mode)
837
@needs_write_lock # because merge pulls data into the branch.
838
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
840
"""Merge from a branch into this working tree.
842
:param branch: The branch to merge from.
843
:param to_revision: If non-None, the merge will merge to to_revision,
844
but not beyond it. to_revision does not need to be in the history
845
of the branch when it is supplied. If None, to_revision defaults to
846
branch.last_revision().
848
from bzrlib.merge import Merger, Merge3Merger
849
pb = bzrlib.ui.ui_factory.nested_progress_bar()
851
merger = Merger(self.branch, this_tree=self, pb=pb)
852
merger.pp = ProgressPhase("Merge phase", 5, pb)
853
merger.pp.next_phase()
854
# check that there are no
856
merger.check_basis(check_clean=True, require_commits=False)
857
if to_revision is None:
858
to_revision = _mod_revision.ensure_null(branch.last_revision())
859
merger.other_rev_id = to_revision
860
if _mod_revision.is_null(merger.other_rev_id):
861
raise errors.NoCommits(branch)
862
self.branch.fetch(branch, last_revision=merger.other_rev_id)
863
merger.other_basis = merger.other_rev_id
864
merger.other_tree = self.branch.repository.revision_tree(
866
merger.other_branch = branch
867
merger.pp.next_phase()
868
if from_revision is None:
871
merger.set_base_revision(from_revision, branch)
872
if merger.base_rev_id == merger.other_rev_id:
873
raise errors.PointlessMerge
874
merger.backup_files = False
875
if merge_type is None:
876
merger.merge_type = Merge3Merger
878
merger.merge_type = merge_type
879
merger.set_interesting_files(None)
880
merger.show_base = False
881
merger.reprocess = False
882
conflicts = merger.do_merge()
675
889
def merge_modified(self):
890
"""Return a dictionary of files modified by a merge.
892
The list is initialized by WorkingTree.set_merge_modified, which is
893
typically called after we make some automatic updates to the tree
896
This returns a map of file_id->sha1, containing only files which are
897
still in the working inventory and have that text hash.
677
hashfile = self._control_files.get('merge-hashes')
900
hashfile = self._transport.get('merge-hashes')
901
except errors.NoSuchFile:
682
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
683
raise MergeModifiedFormatError()
684
except StopIteration:
685
raise MergeModifiedFormatError()
686
for s in RioReader(hashfile):
687
file_id = s.get("file_id")
688
if file_id not in self.inventory:
691
if hash == self.get_file_sha1(file_id):
692
merge_hashes[file_id] = hash
906
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
907
raise errors.MergeModifiedFormatError()
908
except StopIteration:
909
raise errors.MergeModifiedFormatError()
910
for s in RioReader(hashfile):
911
# RioReader reads in Unicode, so convert file_ids back to utf8
912
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
913
if file_id not in self.inventory:
915
text_hash = s.get("hash")
916
if text_hash == self.get_file_sha1(file_id):
917
merge_hashes[file_id] = text_hash
923
def mkdir(self, path, file_id=None):
924
"""See MutableTree.mkdir()."""
926
file_id = generate_ids.gen_file_id(os.path.basename(path))
927
os.mkdir(self.abspath(path))
928
self.add(path, file_id, 'directory')
695
931
def get_symlink_target(self, file_id):
696
932
return os.readlink(self.id2abspath(file_id))
698
def file_class(self, filename):
699
if self.path2id(filename):
701
elif self.is_ignored(filename):
706
def list_files(self):
935
def subsume(self, other_tree):
936
def add_children(inventory, entry):
937
for child_entry in entry.children.values():
938
inventory._byid[child_entry.file_id] = child_entry
939
if child_entry.kind == 'directory':
940
add_children(inventory, child_entry)
941
if other_tree.get_root_id() == self.get_root_id():
942
raise errors.BadSubsumeSource(self, other_tree,
943
'Trees have the same root')
945
other_tree_path = self.relpath(other_tree.basedir)
946
except errors.PathNotChild:
947
raise errors.BadSubsumeSource(self, other_tree,
948
'Tree is not contained by the other')
949
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
950
if new_root_parent is None:
951
raise errors.BadSubsumeSource(self, other_tree,
952
'Parent directory is not versioned.')
953
# We need to ensure that the result of a fetch will have a
954
# versionedfile for the other_tree root, and only fetching into
955
# RepositoryKnit2 guarantees that.
956
if not self.branch.repository.supports_rich_root():
957
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
958
other_tree.lock_tree_write()
960
new_parents = other_tree.get_parent_ids()
961
other_root = other_tree.inventory.root
962
other_root.parent_id = new_root_parent
963
other_root.name = osutils.basename(other_tree_path)
964
self.inventory.add(other_root)
965
add_children(self.inventory, other_root)
966
self._write_inventory(self.inventory)
967
# normally we don't want to fetch whole repositories, but i think
968
# here we really do want to consolidate the whole thing.
969
for parent_id in other_tree.get_parent_ids():
970
self.branch.fetch(other_tree.branch, parent_id)
971
self.add_parent_tree_id(parent_id)
974
other_tree.bzrdir.retire_bzrdir()
976
def _setup_directory_is_tree_reference(self):
977
if self._branch.repository._format.supports_tree_reference:
978
self._directory_is_tree_reference = \
979
self._directory_may_be_tree_reference
981
self._directory_is_tree_reference = \
982
self._directory_is_never_tree_reference
984
def _directory_is_never_tree_reference(self, relpath):
987
def _directory_may_be_tree_reference(self, relpath):
988
# as a special case, if a directory contains control files then
989
# it's a tree reference, except that the root of the tree is not
990
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
991
# TODO: We could ask all the control formats whether they
992
# recognize this directory, but at the moment there's no cheap api
993
# to do that. Since we probably can only nest bzr checkouts and
994
# they always use this name it's ok for now. -- mbp 20060306
996
# FIXME: There is an unhandled case here of a subdirectory
997
# containing .bzr but not a branch; that will probably blow up
998
# when you try to commit it. It might happen if there is a
999
# checkout in a subdirectory. This can be avoided by not adding
1002
@needs_tree_write_lock
1003
def extract(self, file_id, format=None):
1004
"""Extract a subtree from this tree.
1006
A new branch will be created, relative to the path for this tree.
1010
segments = osutils.splitpath(path)
1011
transport = self.branch.bzrdir.root_transport
1012
for name in segments:
1013
transport = transport.clone(name)
1014
transport.ensure_base()
1017
sub_path = self.id2path(file_id)
1018
branch_transport = mkdirs(sub_path)
1020
format = self.bzrdir.cloning_metadir()
1021
branch_transport.ensure_base()
1022
branch_bzrdir = format.initialize_on_transport(branch_transport)
1024
repo = branch_bzrdir.find_repository()
1025
except errors.NoRepositoryPresent:
1026
repo = branch_bzrdir.create_repository()
1027
if not repo.supports_rich_root():
1028
raise errors.RootNotRich()
1029
new_branch = branch_bzrdir.create_branch()
1030
new_branch.pull(self.branch)
1031
for parent_id in self.get_parent_ids():
1032
new_branch.fetch(self.branch, parent_id)
1033
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1034
if tree_transport.base != branch_transport.base:
1035
tree_bzrdir = format.initialize_on_transport(tree_transport)
1036
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1038
tree_bzrdir = branch_bzrdir
1039
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1040
wt.set_parent_ids(self.get_parent_ids())
1041
my_inv = self.inventory
1042
child_inv = Inventory(root_id=None)
1043
new_root = my_inv[file_id]
1044
my_inv.remove_recursive_id(file_id)
1045
new_root.parent_id = None
1046
child_inv.add(new_root)
1047
self._write_inventory(my_inv)
1048
wt._write_inventory(child_inv)
1051
def _serialize(self, inventory, out_file):
1052
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1055
def _deserialize(selt, in_file):
1056
return xml5.serializer_v5.read_inventory(in_file)
1059
"""Write the in memory inventory to disk."""
1060
# TODO: Maybe this should only write on dirty ?
1061
if self._control_files._lock_mode != 'w':
1062
raise errors.NotWriteLocked(self)
1064
self._serialize(self._inventory, sio)
1066
self._transport.put_file('inventory', sio,
1067
mode=self._control_files._file_mode)
1068
self._inventory_is_modified = False
1070
def _kind(self, relpath):
1071
return osutils.file_kind(self.abspath(relpath))
1073
def list_files(self, include_root=False):
707
1074
"""Recursively list all files as (path, class, kind, id, entry).
709
1076
Lists, but does not descend into unversioned directories.
788
1174
new_children.sort()
789
1175
new_children = collections.deque(new_children)
790
1176
stack.append((f_ie.file_id, fp, fap, new_children))
791
# Break out of inner loop, so that we start outer loop with child
1177
# Break out of inner loop,
1178
# so that we start outer loop with child
794
1181
# if we finished all children, pop it off the stack
799
def move(self, from_paths, to_name):
1184
@needs_tree_write_lock
1185
def move(self, from_paths, to_dir=None, after=False, **kwargs):
800
1186
"""Rename files.
802
to_name must exist in the inventory.
1188
to_dir must exist in the inventory.
804
If to_name exists and is a directory, the files are moved into
1190
If to_dir exists and is a directory, the files are moved into
805
1191
it, keeping their old names.
807
Note that to_name is only the last component of the new name;
1193
Note that to_dir is only the last component of the new name;
808
1194
this doesn't change the directory.
1196
For each entry in from_paths the move mode will be determined
1199
The first mode moves the file in the filesystem and updates the
1200
inventory. The second mode only updates the inventory without
1201
touching the file on the filesystem. This is the new mode introduced
1204
move uses the second mode if 'after == True' and the target is not
1205
versioned but present in the working tree.
1207
move uses the second mode if 'after == False' and the source is
1208
versioned but no longer in the working tree, and the target is not
1209
versioned but present in the working tree.
1211
move uses the first mode if 'after == False' and the source is
1212
versioned and present in the working tree, and the target is not
1213
versioned and not present in the working tree.
1215
Everything else results in an error.
810
1217
This returns a list of (from_path, to_path) pairs for each
811
1218
entry that is moved.
814
## TODO: Option to move IDs only
815
assert not isinstance(from_paths, basestring)
1223
# check for deprecated use of signature
1225
to_dir = kwargs.get('to_name', None)
1227
raise TypeError('You must supply a target directory')
1229
symbol_versioning.warn('The parameter to_name was deprecated'
1230
' in version 0.13. Use to_dir instead',
1233
# check destination directory
1234
if isinstance(from_paths, basestring):
816
1236
inv = self.inventory
817
to_abs = self.abspath(to_name)
1237
to_abs = self.abspath(to_dir)
818
1238
if not isdir(to_abs):
819
raise BzrError("destination %r is not a directory" % to_abs)
820
if not self.has_filename(to_name):
821
raise BzrError("destination %r not in working directory" % to_abs)
822
to_dir_id = inv.path2id(to_name)
823
if to_dir_id == None and to_name != '':
824
raise BzrError("destination %r is not a versioned directory" % to_name)
1239
raise errors.BzrMoveFailedError('',to_dir,
1240
errors.NotADirectory(to_abs))
1241
if not self.has_filename(to_dir):
1242
raise errors.BzrMoveFailedError('',to_dir,
1243
errors.NotInWorkingDirectory(to_dir))
1244
to_dir_id = inv.path2id(to_dir)
1245
if to_dir_id is None:
1246
raise errors.BzrMoveFailedError('',to_dir,
1247
errors.NotVersionedError(path=str(to_dir)))
825
1249
to_dir_ie = inv[to_dir_id]
826
if to_dir_ie.kind not in ('directory', 'root_directory'):
827
raise BzrError("destination %r is not a directory" % to_abs)
829
to_idpath = inv.get_idpath(to_dir_id)
832
if not self.has_filename(f):
833
raise BzrError("%r does not exist in working tree" % f)
834
f_id = inv.path2id(f)
836
raise BzrError("%r is not versioned" % f)
837
name_tail = splitpath(f)[-1]
838
dest_path = pathjoin(to_name, name_tail)
839
if self.has_filename(dest_path):
840
raise BzrError("destination %r already exists" % dest_path)
841
if f_id in to_idpath:
842
raise BzrError("can't move %r to a subdirectory of itself" % f)
844
# OK, so there's a race here, it's possible that someone will
845
# create a file in this interval and then the rename might be
846
# left half-done. But we should have caught most problems.
847
orig_inv = deepcopy(self.inventory)
1250
if to_dir_ie.kind != 'directory':
1251
raise errors.BzrMoveFailedError('',to_dir,
1252
errors.NotADirectory(to_abs))
1254
# create rename entries and tuples
1255
for from_rel in from_paths:
1256
from_tail = splitpath(from_rel)[-1]
1257
from_id = inv.path2id(from_rel)
1259
raise errors.BzrMoveFailedError(from_rel,to_dir,
1260
errors.NotVersionedError(path=str(from_rel)))
1262
from_entry = inv[from_id]
1263
from_parent_id = from_entry.parent_id
1264
to_rel = pathjoin(to_dir, from_tail)
1265
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1267
from_tail=from_tail,
1268
from_parent_id=from_parent_id,
1269
to_rel=to_rel, to_tail=from_tail,
1270
to_parent_id=to_dir_id)
1271
rename_entries.append(rename_entry)
1272
rename_tuples.append((from_rel, to_rel))
1274
# determine which move mode to use. checks also for movability
1275
rename_entries = self._determine_mv_mode(rename_entries, after)
1277
original_modified = self._inventory_is_modified
850
name_tail = splitpath(f)[-1]
851
dest_path = pathjoin(to_name, name_tail)
852
result.append((f, dest_path))
853
inv.rename(inv.path2id(f), to_dir_id, name_tail)
855
rename(self.abspath(f), self.abspath(dest_path))
857
raise BzrError("failed to rename %r to %r: %s" %
858
(f, dest_path, e[1]),
859
["rename rolled back"])
1280
self._inventory_is_modified = True
1281
self._move(rename_entries)
861
1283
# restore the inventory on error
862
self._set_inventory(orig_inv)
1284
self._inventory_is_modified = original_modified
864
1286
self._write_inventory(inv)
868
def rename_one(self, from_rel, to_rel):
1287
return rename_tuples
1289
def _determine_mv_mode(self, rename_entries, after=False):
1290
"""Determines for each from-to pair if both inventory and working tree
1291
or only the inventory has to be changed.
1293
Also does basic plausability tests.
1295
inv = self.inventory
1297
for rename_entry in rename_entries:
1298
# store to local variables for easier reference
1299
from_rel = rename_entry.from_rel
1300
from_id = rename_entry.from_id
1301
to_rel = rename_entry.to_rel
1302
to_id = inv.path2id(to_rel)
1303
only_change_inv = False
1305
# check the inventory for source and destination
1307
raise errors.BzrMoveFailedError(from_rel,to_rel,
1308
errors.NotVersionedError(path=str(from_rel)))
1309
if to_id is not None:
1310
raise errors.BzrMoveFailedError(from_rel,to_rel,
1311
errors.AlreadyVersionedError(path=str(to_rel)))
1313
# try to determine the mode for rename (only change inv or change
1314
# inv and file system)
1316
if not self.has_filename(to_rel):
1317
raise errors.BzrMoveFailedError(from_id,to_rel,
1318
errors.NoSuchFile(path=str(to_rel),
1319
extra="New file has not been created yet"))
1320
only_change_inv = True
1321
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1322
only_change_inv = True
1323
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1324
only_change_inv = False
1325
elif (not self.case_sensitive
1326
and from_rel.lower() == to_rel.lower()
1327
and self.has_filename(from_rel)):
1328
only_change_inv = False
1330
# something is wrong, so lets determine what exactly
1331
if not self.has_filename(from_rel) and \
1332
not self.has_filename(to_rel):
1333
raise errors.BzrRenameFailedError(from_rel,to_rel,
1334
errors.PathsDoNotExist(paths=(str(from_rel),
1337
raise errors.RenameFailedFilesExist(from_rel, to_rel)
1338
rename_entry.only_change_inv = only_change_inv
1339
return rename_entries
1341
def _move(self, rename_entries):
1342
"""Moves a list of files.
1344
Depending on the value of the flag 'only_change_inv', the
1345
file will be moved on the file system or not.
1347
inv = self.inventory
1350
for entry in rename_entries:
1352
self._move_entry(entry)
1354
self._rollback_move(moved)
1358
def _rollback_move(self, moved):
1359
"""Try to rollback a previous move in case of an filesystem error."""
1360
inv = self.inventory
1363
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1364
entry.to_tail, entry.to_parent_id, entry.from_rel,
1365
entry.from_tail, entry.from_parent_id,
1366
entry.only_change_inv))
1367
except errors.BzrMoveFailedError, e:
1368
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
1369
" The working tree is in an inconsistent state."
1370
" Please consider doing a 'bzr revert'."
1371
" Error message is: %s" % e)
1373
def _move_entry(self, entry):
1374
inv = self.inventory
1375
from_rel_abs = self.abspath(entry.from_rel)
1376
to_rel_abs = self.abspath(entry.to_rel)
1377
if from_rel_abs == to_rel_abs:
1378
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
1379
"Source and target are identical.")
1381
if not entry.only_change_inv:
1383
osutils.rename(from_rel_abs, to_rel_abs)
1385
raise errors.BzrMoveFailedError(entry.from_rel,
1387
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
1389
@needs_tree_write_lock
1390
def rename_one(self, from_rel, to_rel, after=False):
869
1391
"""Rename one file.
871
1393
This can change the directory or the filename or both.
1395
rename_one has several 'modes' to work. First, it can rename a physical
1396
file and change the file_id. That is the normal mode. Second, it can
1397
only change the file_id without touching any physical file. This is
1398
the new mode introduced in version 0.15.
1400
rename_one uses the second mode if 'after == True' and 'to_rel' is not
1401
versioned but present in the working tree.
1403
rename_one uses the second mode if 'after == False' and 'from_rel' is
1404
versioned but no longer in the working tree, and 'to_rel' is not
1405
versioned but present in the working tree.
1407
rename_one uses the first mode if 'after == False' and 'from_rel' is
1408
versioned and present in the working tree, and 'to_rel' is not
1409
versioned and not present in the working tree.
1411
Everything else results in an error.
873
1413
inv = self.inventory
874
if not self.has_filename(from_rel):
875
raise BzrError("can't rename: old working file %r does not exist" % from_rel)
876
if self.has_filename(to_rel):
877
raise BzrError("can't rename: new working file %r already exists" % to_rel)
879
file_id = inv.path2id(from_rel)
881
raise BzrError("can't rename: old name %r is not versioned" % from_rel)
884
from_parent = entry.parent_id
885
from_name = entry.name
887
if inv.path2id(to_rel):
888
raise BzrError("can't rename: new name %r is already versioned" % to_rel)
1416
# create rename entries and tuples
1417
from_tail = splitpath(from_rel)[-1]
1418
from_id = inv.path2id(from_rel)
1420
raise errors.BzrRenameFailedError(from_rel,to_rel,
1421
errors.NotVersionedError(path=str(from_rel)))
1422
from_entry = inv[from_id]
1423
from_parent_id = from_entry.parent_id
890
1424
to_dir, to_tail = os.path.split(to_rel)
891
1425
to_dir_id = inv.path2id(to_dir)
892
if to_dir_id == None and to_dir != '':
893
raise BzrError("can't determine destination directory id for %r" % to_dir)
895
mutter("rename_one:")
896
mutter(" file_id {%s}" % file_id)
897
mutter(" from_rel %r" % from_rel)
898
mutter(" to_rel %r" % to_rel)
899
mutter(" to_dir %r" % to_dir)
900
mutter(" to_dir_id {%s}" % to_dir_id)
902
inv.rename(file_id, to_dir_id, to_tail)
904
from_abs = self.abspath(from_rel)
905
to_abs = self.abspath(to_rel)
907
rename(from_abs, to_abs)
909
inv.rename(file_id, from_parent, from_name)
910
raise BzrError("failed to rename %r to %r: %s"
911
% (from_abs, to_abs, e[1]),
912
["rename rolled back"])
1426
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1428
from_tail=from_tail,
1429
from_parent_id=from_parent_id,
1430
to_rel=to_rel, to_tail=to_tail,
1431
to_parent_id=to_dir_id)
1432
rename_entries.append(rename_entry)
1434
# determine which move mode to use. checks also for movability
1435
rename_entries = self._determine_mv_mode(rename_entries, after)
1437
# check if the target changed directory and if the target directory is
1439
if to_dir_id is None:
1440
raise errors.BzrMoveFailedError(from_rel,to_rel,
1441
errors.NotVersionedError(path=str(to_dir)))
1443
# all checks done. now we can continue with our actual work
1444
mutter('rename_one:\n'
1449
' to_dir_id {%s}\n',
1450
from_id, from_rel, to_rel, to_dir, to_dir_id)
1452
self._move(rename_entries)
913
1453
self._write_inventory(inv)
1455
class _RenameEntry(object):
1456
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
1457
to_rel, to_tail, to_parent_id, only_change_inv=False):
1458
self.from_rel = from_rel
1459
self.from_id = from_id
1460
self.from_tail = from_tail
1461
self.from_parent_id = from_parent_id
1462
self.to_rel = to_rel
1463
self.to_tail = to_tail
1464
self.to_parent_id = to_parent_id
1465
self.only_change_inv = only_change_inv
915
1467
@needs_read_lock
916
1468
def unknowns(self):
917
1469
"""Return all unknown files.
919
1471
These are files in the working directory that are not versioned or
920
1472
control files or ignored.
922
>>> from bzrlib.bzrdir import ScratchDir
923
>>> d = ScratchDir(files=['foo', 'foo~'])
924
>>> b = d.open_branch()
925
>>> tree = d.open_workingtree()
926
>>> map(str, tree.unknowns())
929
>>> list(b.unknowns())
931
>>> tree.remove('foo')
932
>>> list(b.unknowns())
935
for subp in self.extras():
936
if not self.is_ignored(subp):
939
@deprecated_method(zero_eight)
940
def iter_conflicts(self):
941
"""List all files in the tree that have text or content conflicts.
942
DEPRECATED. Use conflicts instead."""
943
return self._iter_conflicts()
1474
# force the extras method to be fully executed before returning, to
1475
# prevent race conditions with the lock
1477
[subp for subp in self.extras() if not self.is_ignored(subp)])
1479
@needs_tree_write_lock
1480
def unversion(self, file_ids):
1481
"""Remove the file ids in file_ids from the current versioned set.
1483
When a file_id is unversioned, all of its children are automatically
1486
:param file_ids: The file ids to stop versioning.
1487
:raises: NoSuchId if any fileid is not currently versioned.
1489
for file_id in file_ids:
1490
if self._inventory.has_id(file_id):
1491
self._inventory.remove_recursive_id(file_id)
1493
raise errors.NoSuchId(self, file_id)
1495
# in the future this should just set a dirty bit to wait for the
1496
# final unlock. However, until all methods of workingtree start
1497
# with the current in -memory inventory rather than triggering
1498
# a read, it is more complex - we need to teach read_inventory
1499
# to know when to read, and when to not read first... and possibly
1500
# to save first when the in memory one may be corrupted.
1501
# so for now, we just only write it if it is indeed dirty.
1503
self._write_inventory(self._inventory)
945
1505
def _iter_conflicts(self):
946
1506
conflicted = set()
947
1507
for info in self.list_files():
1215
1811
# root node id can legitimately look like 'revision_id' but cannot
1216
1812
# contain a '"'.
1217
1813
xml = self.branch.repository.get_inventory_xml(new_revision)
1218
if not 'revision_id="' in xml.split('\n', 1)[0]:
1814
firstline = xml.split('\n', 1)[0]
1815
if (not 'revision_id="' in firstline or
1816
'format="7"' not in firstline):
1219
1817
inv = self.branch.repository.deserialise_inventory(
1220
1818
new_revision, xml)
1221
inv.revision_id = new_revision
1222
xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1223
assert isinstance(xml, str), 'serialised xml must be bytestring.'
1224
path = self._basis_inventory_name()
1226
self._control_files.put(path, sio)
1227
except WeaveRevisionNotPresent:
1819
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1820
self._write_basis_inventory(xml)
1821
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1230
1824
def read_basis_inventory(self):
1231
1825
"""Read the cached basis inventory."""
1232
1826
path = self._basis_inventory_name()
1233
return self._control_files.get(path).read()
1827
return self._transport.get_bytes(path)
1235
1829
@needs_read_lock
1236
1830
def read_working_inventory(self):
1237
"""Read the working inventory."""
1831
"""Read the working inventory.
1833
:raises errors.InventoryModified: read_working_inventory will fail
1834
when the current in memory inventory has been modified.
1836
# conceptually this should be an implementation detail of the tree.
1837
# XXX: Deprecate this.
1238
1838
# ElementTree does its own conversion from UTF-8, so open in
1240
result = bzrlib.xml5.serializer_v5.read_inventory(
1241
self._control_files.get('inventory'))
1242
self._set_inventory(result)
1840
if self._inventory_is_modified:
1841
raise errors.InventoryModified(self)
1842
result = self._deserialize(self._transport.get('inventory'))
1843
self._set_inventory(result, dirty=False)
1246
def remove(self, files, verbose=False, to_file=None):
1247
"""Remove nominated files from the working inventory..
1249
This does not remove their text. This does not run on XXX on what? RBC
1251
TODO: Refuse to remove modified files unless --force is given?
1253
TODO: Do something useful with directories.
1255
TODO: Should this remove the text or not? Tough call; not
1256
removing may be useful and the user can just use use rm, and
1257
is the opposite of add. Removing it is consistent with most
1258
other tools. Maybe an option.
1846
@needs_tree_write_lock
1847
def remove(self, files, verbose=False, to_file=None, keep_files=True,
1849
"""Remove nominated files from the working inventory.
1851
:files: File paths relative to the basedir.
1852
:keep_files: If true, the files will also be kept.
1853
:force: Delete files and directories, even if they are changed and
1854
even if the directories are not empty.
1260
## TODO: Normalize names
1261
## TODO: Remove nested loops; better scalability
1262
1856
if isinstance(files, basestring):
1263
1857
files = [files]
1265
inv = self.inventory
1267
# do this before any modifications
1862
unknown_nested_files=set()
1864
def recurse_directory_to_add_files(directory):
1865
# Recurse directory and add all files
1866
# so we can check if they have changed.
1867
for parent_info, file_infos in\
1868
self.walkdirs(directory):
1869
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1870
# Is it versioned or ignored?
1871
if self.path2id(relpath) or self.is_ignored(relpath):
1872
# Add nested content for deletion.
1873
new_files.add(relpath)
1875
# Files which are not versioned and not ignored
1876
# should be treated as unknown.
1877
unknown_nested_files.add((relpath, None, kind))
1879
for filename in files:
1880
# Get file name into canonical form.
1881
abspath = self.abspath(filename)
1882
filename = self.relpath(abspath)
1883
if len(filename) > 0:
1884
new_files.add(filename)
1885
recurse_directory_to_add_files(filename)
1887
files = list(new_files)
1890
return # nothing to do
1892
# Sort needed to first handle directory content before the directory
1893
files.sort(reverse=True)
1895
# Bail out if we are going to delete files we shouldn't
1896
if not keep_files and not force:
1897
has_changed_files = len(unknown_nested_files) > 0
1898
if not has_changed_files:
1899
for (file_id, path, content_change, versioned, parent_id, name,
1900
kind, executable) in self.iter_changes(self.basis_tree(),
1901
include_unchanged=True, require_versioned=False,
1902
want_unversioned=True, specific_files=files):
1903
if versioned == (False, False):
1904
# The record is unknown ...
1905
if not self.is_ignored(path[1]):
1906
# ... but not ignored
1907
has_changed_files = True
1909
elif content_change and (kind[1] is not None):
1910
# Versioned and changed, but not deleted
1911
has_changed_files = True
1914
if has_changed_files:
1915
# Make delta show ALL applicable changes in error message.
1916
tree_delta = self.changes_from(self.basis_tree(),
1917
require_versioned=False, want_unversioned=True,
1918
specific_files=files)
1919
for unknown_file in unknown_nested_files:
1920
if unknown_file not in tree_delta.unversioned:
1921
tree_delta.unversioned.extend((unknown_file,))
1922
raise errors.BzrRemoveChangedFilesError(tree_delta)
1924
# Build inv_delta and delete files where applicaple,
1925
# do this before any modifications to inventory.
1268
1926
for f in files:
1269
fid = inv.path2id(f)
1927
fid = self.path2id(f)
1271
# TODO: Perhaps make this just a warning, and continue?
1272
# This tends to happen when
1273
raise NotVersionedError(path=f)
1274
mutter("remove inventory entry %s {%s}", quotefn(f), fid)
1276
# having remove it, it must be either ignored or unknown
1277
if self.is_ignored(f):
1281
show_status(new_status, inv[fid].kind, quotefn(f), to_file=to_file)
1284
self._write_inventory(inv)
1287
def revert(self, filenames, old_tree=None, backups=True,
1288
pb=DummyProgress()):
1289
from transform import revert
1290
from conflicts import resolve
1930
message = "%s is not versioned." % (f,)
1933
# having removed it, it must be either ignored or unknown
1934
if self.is_ignored(f):
1938
textui.show_status(new_status, self.kind(fid), f,
1941
inv_delta.append((f, None, fid, None))
1942
message = "removed %s" % (f,)
1945
abs_path = self.abspath(f)
1946
if osutils.lexists(abs_path):
1947
if (osutils.isdir(abs_path) and
1948
len(os.listdir(abs_path)) > 0):
1950
osutils.rmtree(abs_path)
1952
message = "%s is not an empty directory "\
1953
"and won't be deleted." % (f,)
1955
osutils.delete_any(abs_path)
1956
message = "deleted %s" % (f,)
1957
elif message is not None:
1958
# Only care if we haven't done anything yet.
1959
message = "%s does not exist." % (f,)
1961
# Print only one message (if any) per file.
1962
if message is not None:
1964
self.apply_inventory_delta(inv_delta)
1966
@needs_tree_write_lock
1967
def revert(self, filenames=None, old_tree=None, backups=True,
1968
pb=DummyProgress(), report_changes=False):
1969
from bzrlib.conflicts import resolve
1972
symbol_versioning.warn('Using [] to revert all files is deprecated'
1973
' as of bzr 0.91. Please use None (the default) instead.',
1974
DeprecationWarning, stacklevel=2)
1291
1975
if old_tree is None:
1292
old_tree = self.basis_tree()
1293
conflicts = revert(self, old_tree, filenames, backups, pb)
1294
if not len(filenames):
1295
self.set_pending_merges([])
1976
basis_tree = self.basis_tree()
1977
basis_tree.lock_read()
1978
old_tree = basis_tree
1298
resolve(self, filenames, ignore_misses=True)
1982
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1984
if filenames is None and len(self.get_parent_ids()) > 1:
1986
last_revision = self.last_revision()
1987
if last_revision != NULL_REVISION:
1988
if basis_tree is None:
1989
basis_tree = self.basis_tree()
1990
basis_tree.lock_read()
1991
parent_trees.append((last_revision, basis_tree))
1992
self.set_parent_trees(parent_trees)
1995
resolve(self, filenames, ignore_misses=True, recursive=True)
1997
if basis_tree is not None:
1299
1999
return conflicts
2001
def revision_tree(self, revision_id):
2002
"""See Tree.revision_tree.
2004
WorkingTree can supply revision_trees for the basis revision only
2005
because there is only one cached inventory in the bzr directory.
2007
if revision_id == self.last_revision():
2009
xml = self.read_basis_inventory()
2010
except errors.NoSuchFile:
2014
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2015
# dont use the repository revision_tree api because we want
2016
# to supply the inventory.
2017
if inv.revision_id == revision_id:
2018
return revisiontree.RevisionTree(self.branch.repository,
2020
except errors.BadInventoryFormat:
2022
# raise if there was no inventory, or if we read the wrong inventory.
2023
raise errors.NoSuchRevisionInTree(self, revision_id)
1301
2025
# XXX: This method should be deprecated in favour of taking in a proper
1302
2026
# new Inventory object.
2027
@needs_tree_write_lock
1304
2028
def set_inventory(self, new_inventory_list):
1305
2029
from bzrlib.inventory import (Inventory,
1306
2030
InventoryDirectory,
1346
2092
between multiple working trees, i.e. via shared storage, then we
1347
2093
would probably want to lock both the local tree, and the branch.
1349
# FIXME: We want to write out the hashcache only when the last lock on
1350
# this working copy is released. Peeking at the lock count is a bit
1351
# of a nasty hack; probably it's better to have a transaction object,
1352
# which can do some finalization when it's either successfully or
1353
# unsuccessfully completed. (Denys's original patch did that.)
1354
# RBC 20060206 hooking into transaction will couple lock and transaction
1355
# wrongly. Hooking into unlock on the control files object is fine though.
1357
# TODO: split this per format so there is no ugly if block
1358
if self._hashcache.needs_write and (
1359
# dedicated lock files
1360
self._control_files._lock_count==1 or
1362
(self._control_files is self.branch.control_files and
1363
self._control_files._lock_count==3)):
1364
self._hashcache.write()
1365
# reverse order of locking.
1367
return self._control_files.unlock()
1369
self.branch.unlock()
2095
raise NotImplementedError(self.unlock)
2097
def update(self, change_reporter=None, possible_transports=None):
1373
2098
"""Update a working tree along its branch.
1375
This will update the branch if its bound too, which means we have multiple trees involved:
1376
The new basis tree of the master.
1377
The old basis tree of the branch.
1378
The old basis tree of the working tree.
1379
The current working tree state.
1380
pathologically all three may be different, and non ancestors of each other.
1381
Conceptually we want to:
1382
Preserve the wt.basis->wt.state changes
1383
Transform the wt.basis to the new master basis.
1384
Apply a merge of the old branch basis to get any 'local' changes from it into the tree.
1385
Restore the wt.basis->wt.state changes.
2100
This will update the branch if its bound too, which means we have
2101
multiple trees involved:
2103
- The new basis tree of the master.
2104
- The old basis tree of the branch.
2105
- The old basis tree of the working tree.
2106
- The current working tree state.
2108
Pathologically, all three may be different, and non-ancestors of each
2109
other. Conceptually we want to:
2111
- Preserve the wt.basis->wt.state changes
2112
- Transform the wt.basis to the new master basis.
2113
- Apply a merge of the old branch basis to get any 'local' changes from
2115
- Restore the wt.basis->wt.state changes.
1387
2117
There isn't a single operation at the moment to do that, so we:
1388
Merge current state -> basis tree of the master w.r.t. the old tree basis.
1389
Do a 'normal' merge of the old branch basis if it is relevant.
1391
old_tip = self.branch.update()
1392
if old_tip is not None:
1393
self.add_pending_merge(old_tip)
1394
self.branch.lock_read()
1397
if self.last_revision() != self.branch.last_revision():
1398
# merge tree state up to new branch tip.
1399
basis = self.basis_tree()
2118
- Merge current state -> basis tree of the master w.r.t. the old tree
2120
- Do a 'normal' merge of the old branch basis if it is relevant.
2122
if self.branch.get_bound_location() is not None:
2124
update_branch = True
2126
self.lock_tree_write()
2127
update_branch = False
2130
old_tip = self.branch.update(possible_transports)
2133
return self._update_tree(old_tip, change_reporter)
2137
@needs_tree_write_lock
2138
def _update_tree(self, old_tip=None, change_reporter=None):
2139
"""Update a tree to the master branch.
2141
:param old_tip: if supplied, the previous tip revision the branch,
2142
before it was changed to the master branch's tip.
2144
# here if old_tip is not None, it is the old tip of the branch before
2145
# it was updated from the master branch. This should become a pending
2146
# merge in the working tree to preserve the user existing work. we
2147
# cant set that until we update the working trees last revision to be
2148
# one from the new branch, because it will just get absorbed by the
2149
# parent de-duplication logic.
2151
# We MUST save it even if an error occurs, because otherwise the users
2152
# local work is unreferenced and will appear to have been lost.
2156
last_rev = self.get_parent_ids()[0]
2158
last_rev = _mod_revision.NULL_REVISION
2159
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2160
# merge tree state up to new branch tip.
2161
basis = self.basis_tree()
1400
2164
to_tree = self.branch.basis_tree()
1401
result += merge_inner(self.branch,
2165
if basis.inventory.root is None:
2166
self.set_root_id(to_tree.get_root_id())
2168
result += merge.merge_inner(
1405
self.set_last_revision(self.branch.last_revision())
1406
if old_tip and old_tip != self.last_revision():
1407
# our last revision was not the prior branch last revision
1408
# and we have converted that last revision to a pending merge.
1409
# base is somewhere between the branch tip now
1410
# and the now pending merge
1411
from bzrlib.revision import common_ancestor
1413
base_rev_id = common_ancestor(self.branch.last_revision(),
1415
self.branch.repository)
1416
except errors.NoCommonAncestor:
1418
base_tree = self.branch.repository.revision_tree(base_rev_id)
1419
other_tree = self.branch.repository.revision_tree(old_tip)
1420
result += merge_inner(self.branch,
1426
self.branch.unlock()
2173
change_reporter=change_reporter)
2176
# TODO - dedup parents list with things merged by pull ?
2177
# reuse the tree we've updated to to set the basis:
2178
parent_trees = [(self.branch.last_revision(), to_tree)]
2179
merges = self.get_parent_ids()[1:]
2180
# Ideally we ask the tree for the trees here, that way the working
2181
# tree can decide whether to give us teh entire tree or give us a
2182
# lazy initialised tree. dirstate for instance will have the trees
2183
# in ram already, whereas a last-revision + basis-inventory tree
2184
# will not, but also does not need them when setting parents.
2185
for parent in merges:
2186
parent_trees.append(
2187
(parent, self.branch.repository.revision_tree(parent)))
2188
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2189
parent_trees.append(
2190
(old_tip, self.branch.repository.revision_tree(old_tip)))
2191
self.set_parent_trees(parent_trees)
2192
last_rev = parent_trees[0][0]
2194
# the working tree had the same last-revision as the master
2195
# branch did. We may still have pivot local work from the local
2196
# branch into old_tip:
2197
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2198
self.add_parent_tree_id(old_tip)
2199
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2200
and old_tip != last_rev):
2201
# our last revision was not the prior branch last revision
2202
# and we have converted that last revision to a pending merge.
2203
# base is somewhere between the branch tip now
2204
# and the now pending merge
2206
# Since we just modified the working tree and inventory, flush out
2207
# the current state, before we modify it again.
2208
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2209
# requires it only because TreeTransform directly munges the
2210
# inventory and calls tree._write_inventory(). Ultimately we
2211
# should be able to remove this extra flush.
2213
graph = self.branch.repository.get_graph()
2214
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2216
base_tree = self.branch.repository.revision_tree(base_rev_id)
2217
other_tree = self.branch.repository.revision_tree(old_tip)
2218
result += merge.merge_inner(
2223
change_reporter=change_reporter)
2226
def _write_hashcache_if_dirty(self):
2227
"""Write out the hashcache if it is dirty."""
2228
if self._hashcache.needs_write:
2230
self._hashcache.write()
2232
if e.errno not in (errno.EPERM, errno.EACCES):
2234
# TODO: jam 20061219 Should this be a warning? A single line
2235
# warning might be sufficient to let the user know what
2237
mutter('Could not write hashcache for %s\nError: %s',
2238
self._hashcache.cache_file_name(), e)
2240
@needs_tree_write_lock
1429
2241
def _write_inventory(self, inv):
1430
2242
"""Write inventory as the current inventory."""
1432
bzrlib.xml5.serializer_v5.write_inventory(inv, sio)
1434
self._control_files.put('inventory', sio)
1435
self._set_inventory(inv)
1436
mutter('wrote working inventory')
2243
self._set_inventory(inv, dirty=True)
1438
2246
def set_conflicts(self, arg):
1439
raise UnsupportedOperation(self.set_conflicts, self)
2247
raise errors.UnsupportedOperation(self.set_conflicts, self)
2249
def add_conflicts(self, arg):
2250
raise errors.UnsupportedOperation(self.add_conflicts, self)
1441
2252
@needs_read_lock
1442
2253
def conflicts(self):
1443
conflicts = ConflictList()
2254
conflicts = _mod_conflicts.ConflictList()
1444
2255
for conflicted in self._iter_conflicts():
1459
2270
if text == False:
1461
2272
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
1462
conflicts.append(Conflict.factory(ctype, path=conflicted,
2273
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
1463
2275
file_id=self.path2id(conflicted)))
1464
2276
return conflicts
2278
def walkdirs(self, prefix=""):
2279
"""Walk the directories of this tree.
2281
returns a generator which yields items in the form:
2282
((curren_directory_path, fileid),
2283
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
2286
This API returns a generator, which is only valid during the current
2287
tree transaction - within a single lock_read or lock_write duration.
2289
If the tree is not locked, it may cause an error to be raised,
2290
depending on the tree implementation.
2292
disk_top = self.abspath(prefix)
2293
if disk_top.endswith('/'):
2294
disk_top = disk_top[:-1]
2295
top_strip_len = len(disk_top) + 1
2296
inventory_iterator = self._walkdirs(prefix)
2297
disk_iterator = osutils.walkdirs(disk_top, prefix)
2299
current_disk = disk_iterator.next()
2300
disk_finished = False
2302
if not (e.errno == errno.ENOENT or
2303
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
2306
disk_finished = True
2308
current_inv = inventory_iterator.next()
2309
inv_finished = False
2310
except StopIteration:
2313
while not inv_finished or not disk_finished:
2315
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2316
cur_disk_dir_content) = current_disk
2318
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2319
cur_disk_dir_content) = ((None, None), None)
2320
if not disk_finished:
2321
# strip out .bzr dirs
2322
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2323
len(cur_disk_dir_content) > 0):
2324
# osutils.walkdirs can be made nicer -
2325
# yield the path-from-prefix rather than the pathjoined
2327
bzrdir_loc = bisect_left(cur_disk_dir_content,
2329
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2330
# we dont yield the contents of, or, .bzr itself.
2331
del cur_disk_dir_content[bzrdir_loc]
2333
# everything is unknown
2336
# everything is missing
2339
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2341
# disk is before inventory - unknown
2342
dirblock = [(relpath, basename, kind, stat, None, None) for
2343
relpath, basename, kind, stat, top_path in
2344
cur_disk_dir_content]
2345
yield (cur_disk_dir_relpath, None), dirblock
2347
current_disk = disk_iterator.next()
2348
except StopIteration:
2349
disk_finished = True
2351
# inventory is before disk - missing.
2352
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2353
for relpath, basename, dkind, stat, fileid, kind in
2355
yield (current_inv[0][0], current_inv[0][1]), dirblock
2357
current_inv = inventory_iterator.next()
2358
except StopIteration:
2361
# versioned present directory
2362
# merge the inventory and disk data together
2364
for relpath, subiterator in itertools.groupby(sorted(
2365
current_inv[1] + cur_disk_dir_content,
2366
key=operator.itemgetter(0)), operator.itemgetter(1)):
2367
path_elements = list(subiterator)
2368
if len(path_elements) == 2:
2369
inv_row, disk_row = path_elements
2370
# versioned, present file
2371
dirblock.append((inv_row[0],
2372
inv_row[1], disk_row[2],
2373
disk_row[3], inv_row[4],
2375
elif len(path_elements[0]) == 5:
2377
dirblock.append((path_elements[0][0],
2378
path_elements[0][1], path_elements[0][2],
2379
path_elements[0][3], None, None))
2380
elif len(path_elements[0]) == 6:
2381
# versioned, absent file.
2382
dirblock.append((path_elements[0][0],
2383
path_elements[0][1], 'unknown', None,
2384
path_elements[0][4], path_elements[0][5]))
2386
raise NotImplementedError('unreachable code')
2387
yield current_inv[0], dirblock
2389
current_inv = inventory_iterator.next()
2390
except StopIteration:
2393
current_disk = disk_iterator.next()
2394
except StopIteration:
2395
disk_finished = True
2397
def _walkdirs(self, prefix=""):
2398
"""Walk the directories of this tree.
2400
:prefix: is used as the directrory to start with.
2401
returns a generator which yields items in the form:
2402
((curren_directory_path, fileid),
2403
[(file1_path, file1_name, file1_kind, None, file1_id,
2406
_directory = 'directory'
2407
# get the root in the inventory
2408
inv = self.inventory
2409
top_id = inv.path2id(prefix)
2413
pending = [(prefix, '', _directory, None, top_id, None)]
2416
currentdir = pending.pop()
2417
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2418
top_id = currentdir[4]
2420
relroot = currentdir[0] + '/'
2423
# FIXME: stash the node in pending
2425
if entry.kind == 'directory':
2426
for name, child in entry.sorted_children():
2427
dirblock.append((relroot + name, name, child.kind, None,
2428
child.file_id, child.kind
2430
yield (currentdir[0], entry.file_id), dirblock
2431
# push the user specified dirs from dirblock
2432
for dir in reversed(dirblock):
2433
if dir[2] == _directory:
2436
@needs_tree_write_lock
2437
def auto_resolve(self):
2438
"""Automatically resolve text conflicts according to contents.
2440
Only text conflicts are auto_resolvable. Files with no conflict markers
2441
are considered 'resolved', because bzr always puts conflict markers
2442
into files that have text conflicts. The corresponding .THIS .BASE and
2443
.OTHER files are deleted, as per 'resolve'.
2444
:return: a tuple of ConflictLists: (un_resolved, resolved).
2446
un_resolved = _mod_conflicts.ConflictList()
2447
resolved = _mod_conflicts.ConflictList()
2448
conflict_re = re.compile('^(<{7}|={7}|>{7})')
2449
for conflict in self.conflicts():
2450
if (conflict.typestring != 'text conflict' or
2451
self.kind(conflict.file_id) != 'file'):
2452
un_resolved.append(conflict)
2454
my_file = open(self.id2abspath(conflict.file_id), 'rb')
2456
for line in my_file:
2457
if conflict_re.search(line):
2458
un_resolved.append(conflict)
2461
resolved.append(conflict)
2464
resolved.remove_files(self)
2465
self.set_conflicts(un_resolved)
2466
return un_resolved, resolved
2470
tree_basis = self.basis_tree()
2471
tree_basis.lock_read()
2473
repo_basis = self.branch.repository.revision_tree(
2474
self.last_revision())
2475
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2476
raise errors.BzrCheckError(
2477
"Mismatched basis inventory content.")
2482
def _validate(self):
2483
"""Validate internal structures.
2485
This is meant mostly for the test suite. To give it a chance to detect
2486
corruption after actions have occurred. The default implementation is a
2489
:return: None. An exception should be raised if there is an error.
2494
def _get_rules_searcher(self, default_searcher):
2495
"""See Tree._get_rules_searcher."""
2496
if self._rules_searcher is None:
2497
self._rules_searcher = super(WorkingTree,
2498
self)._get_rules_searcher(default_searcher)
2499
return self._rules_searcher
2502
class WorkingTree2(WorkingTree):
2503
"""This is the Format 2 working tree.
2505
This was the first weave based working tree.
2506
- uses os locks for locking.
2507
- uses the branch last-revision.
2510
def __init__(self, *args, **kwargs):
2511
super(WorkingTree2, self).__init__(*args, **kwargs)
2512
# WorkingTree2 has more of a constraint that self._inventory must
2513
# exist. Because this is an older format, we don't mind the overhead
2514
# caused by the extra computation here.
2516
# Newer WorkingTree's should only have self._inventory set when they
2518
if self._inventory is None:
2519
self.read_working_inventory()
2521
def lock_tree_write(self):
2522
"""See WorkingTree.lock_tree_write().
2524
In Format2 WorkingTrees we have a single lock for the branch and tree
2525
so lock_tree_write() degrades to lock_write().
2527
self.branch.lock_write()
2529
return self._control_files.lock_write()
2531
self.branch.unlock()
2535
# do non-implementation specific cleanup
2538
# we share control files:
2539
if self._control_files._lock_count == 3:
2540
# _inventory_is_modified is always False during a read lock.
2541
if self._inventory_is_modified:
2543
self._write_hashcache_if_dirty()
2545
# reverse order of locking.
2547
return self._control_files.unlock()
2549
self.branch.unlock()
1467
2552
class WorkingTree3(WorkingTree):
1468
2553
"""This is the Format 3 working tree.