13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
"""WorkingTree object and friends.
19
19
A WorkingTree represents the editable working copy of a branch.
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
23
23
new revision based on the workingtree and its inventory.
25
25
At the moment every WorkingTree has its own branch. Remote
57
59
conflicts as _mod_conflicts,
66
68
revision as _mod_revision,
76
80
import bzrlib.branch
77
81
from bzrlib.transport import get_transport
78
from bzrlib.workingtree_4 import (
83
from bzrlib.workingtree_4 import WorkingTreeFormat4
85
86
from bzrlib import symbol_versioning
86
87
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
from bzrlib.lockable_files import LockableFiles
88
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
89
from bzrlib.lockable_files import LockableFiles, TransportLock
88
90
from bzrlib.lockdir import LockDir
89
91
import bzrlib.mutabletree
90
92
from bzrlib.mutabletree import needs_tree_write_lock
91
from bzrlib import osutils
92
93
from bzrlib.osutils import (
100
103
supports_executable,
102
from bzrlib.filters import filtered_input_file
103
105
from bzrlib.trace import mutter, note
104
106
from bzrlib.transport.local import LocalTransport
105
107
from bzrlib.progress import DummyProgress, ProgressPhase
106
from bzrlib.revision import CURRENT_REVISION
108
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
107
109
from bzrlib.rio import RioReader, rio_file, Stanza
108
from bzrlib.symbol_versioning import (
110
DEPRECATED_PARAMETER,
110
from bzrlib.symbol_versioning import (deprecated_passed,
113
DEPRECATED_PARAMETER,
114
120
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
117
123
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
126
@deprecated_function(zero_thirteen)
127
def gen_file_id(name):
128
"""Return new file id for the basename 'name'.
130
Use bzrlib.generate_ids.gen_file_id() instead
132
return generate_ids.gen_file_id(name)
135
@deprecated_function(zero_thirteen)
137
"""Return a new tree-root file id.
139
This has been deprecated in favor of bzrlib.generate_ids.gen_root_id()
141
return generate_ids.gen_root_id()
120
144
class TreeEntry(object):
121
145
"""An entry that implements the minimum interface used by commands.
123
This needs further inspection, it may be better to have
147
This needs further inspection, it may be better to have
124
148
InventoryEntries without ids - though that seems wrong. For now,
125
149
this is a parallel hierarchy to InventoryEntry, and needs to become
126
150
one of several things: decorates to that hierarchy, children of, or
215
237
self._control_files = self.branch.control_files
217
239
# assume all other formats have their own control files.
240
assert isinstance(_control_files, LockableFiles), \
241
"_control_files must be a LockableFiles, not %r" \
218
243
self._control_files = _control_files
219
self._transport = self._control_files._transport
220
244
# update the whole cache up front and write to disk if anything changed;
221
245
# in the future we might want to do this more selectively
222
246
# two possible ways offer themselves : in self._unlock, write the cache
247
270
# the Format factory and creation methods that are
248
271
# permitted to do this.
249
272
self._set_inventory(_inventory, dirty=False)
250
self._detect_case_handling()
251
self._rules_searcher = None
252
self.views = self._make_views()
254
def _detect_case_handling(self):
255
wt_trans = self.bzrdir.get_workingtree_transport(None)
257
wt_trans.stat("FoRMaT")
258
except errors.NoSuchFile:
259
self.case_sensitive = True
261
self.case_sensitive = False
263
self._setup_directory_is_tree_reference()
265
274
branch = property(
266
275
fget=lambda self: self._branch,
281
290
self._control_files.break_lock()
282
291
self.branch.break_lock()
284
def _get_check_refs(self):
285
"""Return the references needed to perform a check of this tree.
287
The default implementation returns no refs, and is only suitable for
288
trees that have no local caching and can commit on ghosts at any time.
290
:seealso: bzrlib.check for details about check_refs.
294
293
def requires_rich_root(self):
295
294
return self._format.requires_rich_root
297
296
def supports_tree_reference(self):
300
def supports_content_filtering(self):
301
return self._format.supports_content_filtering()
303
def supports_views(self):
304
return self.views.supports_views()
306
299
def _set_inventory(self, inv, dirty):
307
300
"""Set the internal cached inventory.
354
348
return WorkingTree.open(path, _unsupported=True)
357
def find_trees(location):
358
def list_current(transport):
359
return [d for d in transport.list_dir('') if d != '.bzr']
360
def evaluate(bzrdir):
362
tree = bzrdir.open_workingtree()
363
except errors.NoWorkingTree:
367
transport = get_transport(location)
368
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
369
list_current=list_current)
370
return [t for t in iterator if t is not None]
372
350
# should be deprecated - this is slow and in any case treating them as a
373
351
# container is (we now know) bad style -- mbp 20070302
374
352
## @deprecated_method(zero_fifteen)
418
390
# at this point ?
420
392
return self.branch.repository.revision_tree(revision_id)
421
except (errors.RevisionNotPresent, errors.NoSuchRevision):
393
except errors.RevisionNotPresent:
422
394
# the basis tree *may* be a ghost or a low level error may have
423
# occurred. If the revision is present, its a problem, if its not
395
# occured. If the revision is present, its a problem, if its not
425
397
if self.branch.repository.has_revision(revision_id):
427
399
# the basis tree is a ghost so return an empty tree.
428
return self.branch.repository.revision_tree(
429
_mod_revision.NULL_REVISION)
432
self._flush_ignore_list_cache()
400
return self.branch.repository.revision_tree(None)
403
@deprecated_method(zero_eight)
404
def create(branch, directory):
405
"""Create a workingtree for branch at directory.
407
If existing_directory already exists it must have a .bzr directory.
408
If it does not exist, it will be created.
410
This returns a new WorkingTree object for the new checkout.
412
TODO FIXME RBC 20060124 when we have checkout formats in place this
413
should accept an optional revisionid to checkout [and reject this if
414
checking out into the same dir as a pre-checkout-aware branch format.]
416
XXX: When BzrDir is present, these should be created through that
419
warnings.warn('delete WorkingTree.create', stacklevel=3)
420
transport = get_transport(directory)
421
if branch.bzrdir.root_transport.base == transport.base:
423
return branch.bzrdir.create_workingtree()
424
# different directory,
425
# create a branch reference
426
# and now a working tree.
427
raise NotImplementedError
430
@deprecated_method(zero_eight)
431
def create_standalone(directory):
432
"""Create a checkout and a branch and a repo at directory.
434
Directory must exist and be empty.
436
please use BzrDir.create_standalone_workingtree
438
return bzrdir.BzrDir.create_standalone_workingtree(directory)
434
440
def relpath(self, path):
435
441
"""Return the local path portion from a given path.
437
The path may be absolute or relative. If its a relative path it is
443
The path may be absolute or relative. If its a relative path it is
438
444
interpreted relative to the python current working directory.
440
446
return osutils.relpath(self.basedir, path)
442
448
def has_filename(self, filename):
443
449
return osutils.lexists(self.abspath(filename))
445
def get_file(self, file_id, path=None, filtered=True):
446
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
448
def get_file_with_stat(self, file_id, path=None, filtered=True,
450
"""See Tree.get_file_with_stat."""
452
path = self.id2path(file_id)
453
file_obj = self.get_file_byname(path, filtered=False)
454
stat_value = _fstat(file_obj.fileno())
455
if filtered and self.supports_content_filtering():
456
filters = self._content_filter_stack(path)
457
file_obj = filtered_input_file(file_obj, filters)
458
return (file_obj, stat_value)
460
def get_file_text(self, file_id, path=None, filtered=True):
461
return self.get_file(file_id, path=path, filtered=filtered).read()
463
def get_file_byname(self, filename, filtered=True):
464
path = self.abspath(filename)
466
if filtered and self.supports_content_filtering():
467
filters = self._content_filter_stack(filename)
468
return filtered_input_file(f, filters)
472
def get_file_lines(self, file_id, path=None, filtered=True):
473
"""See Tree.get_file_lines()"""
474
file = self.get_file(file_id, path, filtered=filtered)
476
return file.readlines()
451
def get_file(self, file_id):
452
file_id = osutils.safe_file_id(file_id)
453
return self.get_file_byname(self.id2path(file_id))
455
def get_file_text(self, file_id):
456
file_id = osutils.safe_file_id(file_id)
457
return self.get_file(file_id).read()
459
def get_file_byname(self, filename):
460
return file(self.abspath(filename), 'rb')
481
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
463
def annotate_iter(self, file_id):
482
464
"""See Tree.annotate_iter
484
466
This implementation will use the basis tree implementation if possible.
488
470
incorrectly attributed to CURRENT_REVISION (but after committing, the
489
471
attribution will be correct).
491
maybe_file_parent_keys = []
492
for parent_id in self.get_parent_ids():
494
parent_tree = self.revision_tree(parent_id)
495
except errors.NoSuchRevisionInTree:
496
parent_tree = self.branch.repository.revision_tree(parent_id)
497
parent_tree.lock_read()
499
if file_id not in parent_tree:
501
ie = parent_tree.inventory[file_id]
502
if ie.kind != 'file':
503
# Note: this is slightly unnecessary, because symlinks and
504
# directories have a "text" which is the empty text, and we
505
# know that won't mess up annotations. But it seems cleaner
507
parent_text_key = (file_id, ie.revision)
508
if parent_text_key not in maybe_file_parent_keys:
509
maybe_file_parent_keys.append(parent_text_key)
512
graph = _mod_graph.Graph(self.branch.repository.texts)
513
heads = graph.heads(maybe_file_parent_keys)
514
file_parent_keys = []
515
for key in maybe_file_parent_keys:
517
file_parent_keys.append(key)
519
# Now we have the parents of this content
520
annotator = self.branch.repository.texts.get_annotator()
521
text = self.get_file(file_id).read()
522
this_key =(file_id, default_revision)
523
annotator.add_special_text(this_key, file_parent_keys, text)
524
annotations = [(key[-1], line)
525
for key, line in annotator.annotate_flat(this_key)]
528
def _get_ancestors(self, default_revision):
529
ancestors = set([default_revision])
530
for parent_id in self.get_parent_ids():
531
ancestors.update(self.branch.repository.get_ancestry(
532
parent_id, topo_sorted=False))
473
file_id = osutils.safe_file_id(file_id)
474
basis = self.basis_tree()
477
changes = self._iter_changes(basis, True, [self.id2path(file_id)],
478
require_versioned=True).next()
479
changed_content, kind = changes[2], changes[6]
480
if not changed_content:
481
return basis.annotate_iter(file_id)
485
if kind[0] != 'file':
488
old_lines = list(basis.annotate_iter(file_id))
490
for tree in self.branch.repository.revision_trees(
491
self.get_parent_ids()[1:]):
492
if file_id not in tree:
494
old.append(list(tree.annotate_iter(file_id)))
495
return annotate.reannotate(old, self.get_file(file_id).readlines(),
535
500
def get_parent_ids(self):
536
501
"""See Tree.get_parent_ids.
538
503
This implementation reads the pending merges list and last_revision
539
504
value and uses that to decide what the parents list should be.
557
522
def get_root_id(self):
558
523
"""Return the id of this trees root"""
559
524
return self._inventory.root.file_id
561
526
def _get_store_filename(self, file_id):
562
527
## XXX: badly named; this is not in the store at all
528
file_id = osutils.safe_file_id(file_id)
563
529
return self.abspath(self.id2path(file_id))
566
532
def clone(self, to_bzrdir, revision_id=None):
567
533
"""Duplicate this working tree into to_bzr, including all state.
569
535
Specifically modified files are kept as modified, but
570
536
ignored and unknown files are discarded.
572
538
If you want to make a new line of development, see bzrdir.sprout()
575
If not None, the cloned tree will have its last revision set to
576
revision, and difference between the source trees last revision
541
If not None, the cloned tree will have its last revision set to
542
revision, and and difference between the source trees last revision
577
543
and this one merged in.
579
545
# assumes the target bzr dir format is compatible.
580
result = to_bzrdir.create_workingtree()
546
result = self._format.initialize(to_bzrdir)
581
547
self.copy_content_into(result, revision_id)
612
581
__contains__ = has_id
614
583
def get_file_size(self, file_id):
615
"""See Tree.get_file_size"""
617
return os.path.getsize(self.id2abspath(file_id))
619
if e.errno != errno.ENOENT:
584
file_id = osutils.safe_file_id(file_id)
585
return os.path.getsize(self.id2abspath(file_id))
625
588
def get_file_sha1(self, file_id, path=None, stat_value=None):
589
file_id = osutils.safe_file_id(file_id)
627
591
path = self._inventory.id2path(file_id)
628
592
return self._hashcache.get_sha1(path, stat_value)
630
594
def get_file_mtime(self, file_id, path=None):
595
file_id = osutils.safe_file_id(file_id)
632
597
path = self.inventory.id2path(file_id)
633
598
return os.lstat(self.abspath(path)).st_mtime
635
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
636
file_id = self.path2id(path)
637
return self._inventory[file_id].executable
639
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
640
mode = stat_result.st_mode
641
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
643
600
if not supports_executable():
644
601
def is_executable(self, file_id, path=None):
602
file_id = osutils.safe_file_id(file_id)
645
603
return self._inventory[file_id].executable
647
_is_executable_from_path_and_stat = \
648
_is_executable_from_path_and_stat_from_basis
650
605
def is_executable(self, file_id, path=None):
607
file_id = osutils.safe_file_id(file_id)
652
608
path = self.id2path(file_id)
653
609
mode = os.lstat(self.abspath(path)).st_mode
654
610
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
656
_is_executable_from_path_and_stat = \
657
_is_executable_from_path_and_stat_from_stat
659
612
@needs_tree_write_lock
660
613
def _add(self, files, ids, kinds):
661
614
"""See MutableTree._add."""
662
615
# TODO: Re-adding a file that is removed in the working copy
663
616
# should probably put it back with the previous ID.
664
# the read and write working inventory should not occur in this
617
# the read and write working inventory should not occur in this
665
618
# function - they should be part of lock_write and unlock.
666
619
inv = self.inventory
667
620
for f, file_id, kind in zip(files, ids, kinds):
621
assert kind is not None
668
622
if file_id is None:
669
623
inv.add_path(f, kind=kind)
625
file_id = osutils.safe_file_id(file_id)
671
626
inv.add_path(f, kind=kind, file_id=file_id)
672
627
self._inventory_is_modified = True
736
691
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
738
def path_content_summary(self, path, _lstat=os.lstat,
739
_mapper=osutils.file_kind_from_stat_mode):
740
"""See Tree.path_content_summary."""
741
abspath = self.abspath(path)
743
stat_result = _lstat(abspath)
745
if getattr(e, 'errno', None) == errno.ENOENT:
747
return ('missing', None, None, None)
748
# propagate other errors
750
kind = _mapper(stat_result.st_mode)
752
size = stat_result.st_size
753
# try for a stat cache lookup
754
executable = self._is_executable_from_path_and_stat(path, stat_result)
755
return (kind, size, executable, self._sha_from_stat(
757
elif kind == 'directory':
758
# perhaps it looks like a plain directory, but it's really a
760
if self._directory_is_tree_reference(path):
761
kind = 'tree-reference'
762
return kind, None, None, None
763
elif kind == 'symlink':
764
target = osutils.readlink(abspath)
765
return ('symlink', None, None, target)
767
return (kind, None, None, None)
693
@deprecated_method(zero_eleven)
695
def pending_merges(self):
696
"""Return a list of pending merges.
698
These are revisions that have been merged into the working
699
directory but not yet committed.
701
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
702
instead - which is available on all tree objects.
704
return self.get_parent_ids()[1:]
769
706
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
770
707
"""Common ghost checking functionality from set_parent_*.
781
718
def _set_merges_from_parent_ids(self, parent_ids):
782
719
merges = parent_ids[1:]
783
self._transport.put_bytes('pending-merges', '\n'.join(merges),
784
mode=self.bzrdir._get_file_mode())
786
def _filter_parent_ids_by_ancestry(self, revision_ids):
787
"""Check that all merged revisions are proper 'heads'.
789
This will always return the first revision_id, and any merged revisions
792
if len(revision_ids) == 0:
794
graph = self.branch.repository.get_graph()
795
heads = graph.heads(revision_ids)
796
new_revision_ids = revision_ids[:1]
797
for revision_id in revision_ids[1:]:
798
if revision_id in heads and revision_id not in new_revision_ids:
799
new_revision_ids.append(revision_id)
800
if new_revision_ids != revision_ids:
801
trace.mutter('requested to set revision_ids = %s,'
802
' but filtered to %s', revision_ids, new_revision_ids)
803
return new_revision_ids
720
self._control_files.put_bytes('pending-merges', '\n'.join(merges))
805
722
@needs_tree_write_lock
806
723
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
807
724
"""Set the parent ids to revision_ids.
809
726
See also set_parent_trees. This api will try to retrieve the tree data
810
727
for each element of revision_ids from the trees repository. If you have
811
728
tree data already available, it is more efficient to use
815
732
:param revision_ids: The revision_ids to set as the parent ids of this
816
733
working tree. Any of these may be ghosts.
735
revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
818
736
self._check_parents_for_ghosts(revision_ids,
819
737
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
820
738
for revision_id in revision_ids:
821
739
_mod_revision.check_not_reserved_id(revision_id)
823
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
825
741
if len(revision_ids) > 0:
826
742
self.set_last_revision(revision_ids[0])
832
748
@needs_tree_write_lock
833
749
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
834
750
"""See MutableTree.set_parent_trees."""
835
parent_ids = [rev for (rev, tree) in parents_list]
751
parent_ids = [osutils.safe_revision_id(rev) for (rev, tree) in parents_list]
836
752
for revision_id in parent_ids:
837
753
_mod_revision.check_not_reserved_id(revision_id)
839
755
self._check_parents_for_ghosts(parent_ids,
840
756
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
842
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
844
758
if len(parent_ids) == 0:
845
759
leftmost_parent_id = _mod_revision.NULL_REVISION
846
760
leftmost_parent_tree = None
873
787
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
874
788
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
876
def _sha_from_stat(self, path, stat_result):
877
"""Get a sha digest from the tree's stat cache.
879
The default implementation assumes no stat cache is present.
881
:param path: The path.
882
:param stat_result: The stat result being looked up.
886
790
def _put_rio(self, filename, stanzas, header):
887
791
self._must_be_locked()
888
792
my_file = rio_file(stanzas, header)
889
self._transport.put_file(filename, my_file,
890
mode=self.bzrdir._get_file_mode())
793
self._control_files.put(filename, my_file)
892
795
@needs_write_lock # because merge pulls data into the branch.
893
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
796
def merge_from_branch(self, branch, to_revision=None):
895
797
"""Merge from a branch into this working tree.
897
799
:param branch: The branch to merge from.
920
824
merger.other_rev_id)
921
825
merger.other_branch = branch
922
826
merger.pp.next_phase()
923
if from_revision is None:
926
merger.set_base_revision(from_revision, branch)
927
828
if merger.base_rev_id == merger.other_rev_id:
928
829
raise errors.PointlessMerge
929
830
merger.backup_files = False
930
if merge_type is None:
931
merger.merge_type = Merge3Merger
933
merger.merge_type = merge_type
831
merger.merge_type = Merge3Merger
934
832
merger.set_interesting_files(None)
935
833
merger.show_base = False
936
834
merger.reprocess = False
952
850
still in the working inventory and have that text hash.
955
hashfile = self._transport.get('merge-hashes')
853
hashfile = self._control_files.get('merge-hashes')
956
854
except errors.NoSuchFile:
961
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
962
raise errors.MergeModifiedFormatError()
963
except StopIteration:
858
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
964
859
raise errors.MergeModifiedFormatError()
965
for s in RioReader(hashfile):
966
# RioReader reads in Unicode, so convert file_ids back to utf8
967
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
968
if file_id not in self.inventory:
970
text_hash = s.get("hash")
971
if text_hash == self.get_file_sha1(file_id):
972
merge_hashes[file_id] = text_hash
860
except StopIteration:
861
raise errors.MergeModifiedFormatError()
862
for s in RioReader(hashfile):
863
# RioReader reads in Unicode, so convert file_ids back to utf8
864
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
865
if file_id not in self.inventory:
867
text_hash = s.get("hash")
868
if text_hash == self.get_file_sha1(file_id):
869
merge_hashes[file_id] = text_hash
977
872
@needs_write_lock
978
873
def mkdir(self, path, file_id=None):
1030
924
other_tree.unlock()
1031
925
other_tree.bzrdir.retire_bzrdir()
1033
def _setup_directory_is_tree_reference(self):
1034
if self._branch.repository._format.supports_tree_reference:
1035
self._directory_is_tree_reference = \
1036
self._directory_may_be_tree_reference
1038
self._directory_is_tree_reference = \
1039
self._directory_is_never_tree_reference
1041
def _directory_is_never_tree_reference(self, relpath):
1044
def _directory_may_be_tree_reference(self, relpath):
1045
# as a special case, if a directory contains control files then
1046
# it's a tree reference, except that the root of the tree is not
1047
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1048
# TODO: We could ask all the control formats whether they
1049
# recognize this directory, but at the moment there's no cheap api
1050
# to do that. Since we probably can only nest bzr checkouts and
1051
# they always use this name it's ok for now. -- mbp 20060306
1053
# FIXME: There is an unhandled case here of a subdirectory
1054
# containing .bzr but not a branch; that will probably blow up
1055
# when you try to commit it. It might happen if there is a
1056
# checkout in a subdirectory. This can be avoided by not adding
1059
927
@needs_tree_write_lock
1060
928
def extract(self, file_id, format=None):
1061
929
"""Extract a subtree from this tree.
1063
931
A new branch will be created, relative to the path for this tree.
1070
938
transport = transport.clone(name)
1071
939
transport.ensure_base()
1072
940
return transport
1074
942
sub_path = self.id2path(file_id)
1075
943
branch_transport = mkdirs(sub_path)
1076
944
if format is None:
1077
format = self.bzrdir.cloning_metadir()
945
format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
1078
946
branch_transport.ensure_base()
1079
947
branch_bzrdir = format.initialize_on_transport(branch_transport)
1081
949
repo = branch_bzrdir.find_repository()
1082
950
except errors.NoRepositoryPresent:
1083
951
repo = branch_bzrdir.create_repository()
1084
if not repo.supports_rich_root():
1085
raise errors.RootNotRich()
952
assert repo.supports_rich_root()
954
if not repo.supports_rich_root():
955
raise errors.RootNotRich()
1086
956
new_branch = branch_bzrdir.create_branch()
1087
957
new_branch.pull(self.branch)
1088
958
for parent_id in self.get_parent_ids():
1093
963
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1095
965
tree_bzrdir = branch_bzrdir
1096
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
966
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1097
967
wt.set_parent_ids(self.get_parent_ids())
1098
968
my_inv = self.inventory
1099
child_inv = inventory.Inventory(root_id=None)
969
child_inv = Inventory(root_id=None)
1100
970
new_root = my_inv[file_id]
1101
971
my_inv.remove_recursive_id(file_id)
1102
972
new_root.parent_id = None
1120
989
sio = StringIO()
1121
990
self._serialize(self._inventory, sio)
1123
self._transport.put_file('inventory', sio,
1124
mode=self.bzrdir._get_file_mode())
992
self._control_files.put('inventory', sio)
1125
993
self._inventory_is_modified = False
1127
995
def _kind(self, relpath):
1128
996
return osutils.file_kind(self.abspath(relpath))
1130
def list_files(self, include_root=False, from_dir=None, recursive=True):
1131
"""List all files as (path, class, kind, id, entry).
998
def list_files(self, include_root=False):
999
"""Recursively list all files as (path, class, kind, id, entry).
1133
1001
Lists, but does not descend into unversioned directories.
1134
1003
This does not include files that have been deleted in this
1135
tree. Skips the control directory.
1137
:param include_root: if True, do not return an entry for the root
1138
:param from_dir: start from this directory or None for the root
1139
:param recursive: whether to recurse into subdirectories or not
1006
Skips the control directory.
1141
1008
# list_files is an iterator, so @needs_read_lock doesn't work properly
1142
1009
# with it. So callers should be careful to always read_lock the tree.
1157
1024
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1159
1026
# directory file_id, relative path, absolute path, reverse sorted children
1160
if from_dir is not None:
1161
from_dir_id = inv.path2id(from_dir)
1162
if from_dir_id is None:
1163
# Directory not versioned
1165
from_dir_abspath = pathjoin(self.basedir, from_dir)
1167
from_dir_id = inv.root.file_id
1168
from_dir_abspath = self.basedir
1169
children = os.listdir(from_dir_abspath)
1027
children = os.listdir(self.basedir)
1170
1028
children.sort()
1171
# jam 20060527 The kernel sized tree seems equivalent whether we
1029
# jam 20060527 The kernel sized tree seems equivalent whether we
1172
1030
# use a deque and popleft to keep them sorted, or if we use a plain
1173
1031
# list and just reverse() them.
1174
1032
children = collections.deque(children)
1175
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1033
stack = [(inv.root.file_id, u'', self.basedir, children)]
1177
1035
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1232
1090
except KeyError:
1233
1091
yield fp[1:], c, fk, None, TreeEntry()
1236
1094
if fk != 'directory':
1239
# But do this child first if recursing down
1241
new_children = os.listdir(fap)
1243
new_children = collections.deque(new_children)
1244
stack.append((f_ie.file_id, fp, fap, new_children))
1245
# Break out of inner loop,
1246
# so that we start outer loop with child
1097
# But do this child first
1098
new_children = os.listdir(fap)
1100
new_children = collections.deque(new_children)
1101
stack.append((f_ie.file_id, fp, fap, new_children))
1102
# Break out of inner loop,
1103
# so that we start outer loop with child
1249
1106
# if we finished all children, pop it off the stack
1486
1338
from_tail = splitpath(from_rel)[-1]
1487
1339
from_id = inv.path2id(from_rel)
1488
1340
if from_id is None:
1489
# if file is missing in the inventory maybe it's in the basis_tree
1490
basis_tree = self.branch.basis_tree()
1491
from_id = basis_tree.path2id(from_rel)
1493
raise errors.BzrRenameFailedError(from_rel,to_rel,
1494
errors.NotVersionedError(path=str(from_rel)))
1495
# put entry back in the inventory so we can rename it
1496
from_entry = basis_tree.inventory[from_id].copy()
1499
from_entry = inv[from_id]
1341
raise errors.BzrRenameFailedError(from_rel,to_rel,
1342
errors.NotVersionedError(path=str(from_rel)))
1343
from_entry = inv[from_id]
1500
1344
from_parent_id = from_entry.parent_id
1501
1345
to_dir, to_tail = os.path.split(to_rel)
1502
1346
to_dir_id = inv.path2id(to_dir)
1564
1408
:raises: NoSuchId if any fileid is not currently versioned.
1566
1410
for file_id in file_ids:
1567
if file_id not in self._inventory:
1568
raise errors.NoSuchId(self, file_id)
1569
for file_id in file_ids:
1411
file_id = osutils.safe_file_id(file_id)
1570
1412
if self._inventory.has_id(file_id):
1571
1413
self._inventory.remove_recursive_id(file_id)
1415
raise errors.NoSuchId(self, file_id)
1572
1416
if len(file_ids):
1573
# in the future this should just set a dirty bit to wait for the
1417
# in the future this should just set a dirty bit to wait for the
1574
1418
# final unlock. However, until all methods of workingtree start
1575
# with the current in -memory inventory rather than triggering
1419
# with the current in -memory inventory rather than triggering
1576
1420
# a read, it is more complex - we need to teach read_inventory
1577
1421
# to know when to read, and when to not read first... and possibly
1578
1422
# to save first when the in memory one may be corrupted.
1579
1423
# so for now, we just only write it if it is indeed dirty.
1580
1424
# - RBC 20060907
1581
1425
self._write_inventory(self._inventory)
1427
@deprecated_method(zero_eight)
1428
def iter_conflicts(self):
1429
"""List all files in the tree that have text or content conflicts.
1430
DEPRECATED. Use conflicts instead."""
1431
return self._iter_conflicts()
1583
1433
def _iter_conflicts(self):
1584
1434
conflicted = set()
1594
1444
@needs_write_lock
1595
1445
def pull(self, source, overwrite=False, stop_revision=None,
1596
change_reporter=None, possible_transports=None, local=False):
1597
top_pb = ui.ui_factory.nested_progress_bar()
1446
change_reporter=None):
1447
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1598
1448
source.lock_read()
1600
1450
pp = ProgressPhase("Pull phase", 2, top_pb)
1601
1451
pp.next_phase()
1602
1452
old_revision_info = self.branch.last_revision_info()
1603
1453
basis_tree = self.basis_tree()
1604
count = self.branch.pull(source, overwrite, stop_revision,
1605
possible_transports=possible_transports,
1454
count = self.branch.pull(source, overwrite, stop_revision)
1607
1455
new_revision_info = self.branch.last_revision_info()
1608
1456
if new_revision_info != old_revision_info:
1609
1457
pp.next_phase()
1610
1458
repository = self.branch.repository
1611
pb = ui.ui_factory.nested_progress_bar()
1459
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1612
1460
basis_tree.lock_read()
1614
1462
new_basis_tree = self.branch.basis_tree()
1629
1477
# reuse the revisiontree we merged against to set the new
1631
1479
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1632
# we have to pull the merge trees out again, because
1633
# merge_inner has set the ids. - this corner is not yet
1480
# we have to pull the merge trees out again, because
1481
# merge_inner has set the ids. - this corner is not yet
1634
1482
# layered well enough to prevent double handling.
1635
1483
# XXX TODO: Fix the double handling: telling the tree about
1636
1484
# the already known parent data is wasteful.
1676
1525
for subf in os.listdir(dirabs):
1677
if self.bzrdir.is_control_filename(subf):
1679
1528
if subf not in dir_entry.children:
1682
can_access) = osutils.normalized_filename(subf)
1683
except UnicodeDecodeError:
1684
path_os_enc = path.encode(osutils._fs_enc)
1685
relpath = path_os_enc + '/' + subf
1686
raise errors.BadFilenameEncoding(relpath,
1529
subf_norm, can_access = osutils.normalized_filename(subf)
1688
1530
if subf_norm != subf and can_access:
1689
1531
if subf_norm not in dir_entry.children:
1690
1532
fl.append(subf_norm)
1692
1534
fl.append(subf)
1695
1537
for subf in fl:
1696
1538
subp = pathjoin(path, subf)
1836
1674
def _reset_data(self):
1837
1675
"""Reset transient data that cannot be revalidated."""
1838
1676
self._inventory_is_modified = False
1839
result = self._deserialize(self._transport.get('inventory'))
1677
result = self._deserialize(self._control_files.get('inventory'))
1840
1678
self._set_inventory(result, dirty=False)
1842
1680
@needs_tree_write_lock
1843
1681
def set_last_revision(self, new_revision):
1844
1682
"""Change the last revision in the working tree."""
1683
new_revision = osutils.safe_revision_id(new_revision)
1845
1684
if self._change_last_revision(new_revision):
1846
1685
self._cache_basis_inventory(new_revision)
1848
1687
def _change_last_revision(self, new_revision):
1849
1688
"""Template method part of set_last_revision to perform the change.
1851
1690
This is used to allow WorkingTree3 instances to not affect branch
1852
1691
when their last revision is set.
1864
1703
def _write_basis_inventory(self, xml):
1865
1704
"""Write the basis inventory XML to the basis-inventory file"""
1705
assert isinstance(xml, str), 'serialised xml must be bytestring.'
1866
1706
path = self._basis_inventory_name()
1867
1707
sio = StringIO(xml)
1868
self._transport.put_file(path, sio,
1869
mode=self.bzrdir._get_file_mode())
1708
self._control_files.put(path, sio)
1871
1710
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1872
1711
"""Create the text that will be saved in basis-inventory"""
1873
inventory.revision_id = revision_id
1712
# TODO: jam 20070209 This should be redundant, as the revision_id
1713
# as all callers should have already converted the revision_id to
1715
inventory.revision_id = osutils.safe_revision_id(revision_id)
1874
1716
return xml7.serializer_v7.write_inventory_to_string(inventory)
1876
1718
def _cache_basis_inventory(self, new_revision):
1879
1721
# as commit already has that ready-to-use [while the format is the
1880
1722
# same, that is].
1882
# this double handles the inventory - unpack and repack -
1724
# this double handles the inventory - unpack and repack -
1883
1725
# but is easier to understand. We can/should put a conditional
1884
1726
# in here based on whether the inventory is in the latest format
1885
1727
# - perhaps we should repack all inventories on a repository
1887
1729
# the fast path is to copy the raw xml from the repository. If the
1888
# xml contains 'revision_id="', then we assume the right
1730
# xml contains 'revision_id="', then we assume the right
1889
1731
# revision_id is set. We must check for this full string, because a
1890
1732
# root node id can legitimately look like 'revision_id' but cannot
1891
1733
# contain a '"'.
1892
1734
xml = self.branch.repository.get_inventory_xml(new_revision)
1893
1735
firstline = xml.split('\n', 1)[0]
1894
if (not 'revision_id="' in firstline or
1736
if (not 'revision_id="' in firstline or
1895
1737
'format="7"' not in firstline):
1896
1738
inv = self.branch.repository.deserialise_inventory(
1897
1739
new_revision, xml)
1903
1745
def read_basis_inventory(self):
1904
1746
"""Read the cached basis inventory."""
1905
1747
path = self._basis_inventory_name()
1906
return self._transport.get_bytes(path)
1748
return self._control_files.get(path).read()
1908
1750
@needs_read_lock
1909
1751
def read_working_inventory(self):
1910
1752
"""Read the working inventory.
1912
1754
:raises errors.InventoryModified: read_working_inventory will fail
1913
1755
when the current in memory inventory has been modified.
1915
# conceptually this should be an implementation detail of the tree.
1757
# conceptually this should be an implementation detail of the tree.
1916
1758
# XXX: Deprecate this.
1917
1759
# ElementTree does its own conversion from UTF-8, so open in
1919
1761
if self._inventory_is_modified:
1920
1762
raise errors.InventoryModified(self)
1921
result = self._deserialize(self._transport.get('inventory'))
1763
result = self._deserialize(self._control_files.get('inventory'))
1922
1764
self._set_inventory(result, dirty=False)
1932
1774
:force: Delete files and directories, even if they are changed and
1933
1775
even if the directories are not empty.
1777
## TODO: Normalize names
1935
1779
if isinstance(files, basestring):
1936
1780
files = [files]
1940
1784
new_files=set()
1941
unknown_nested_files=set()
1785
unknown_files_in_directory=set()
1943
1787
def recurse_directory_to_add_files(directory):
1944
# Recurse directory and add all files
1788
# recurse directory and add all files
1945
1789
# so we can check if they have changed.
1946
1790
for parent_info, file_infos in\
1947
self.walkdirs(directory):
1948
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1949
# Is it versioned or ignored?
1950
if self.path2id(relpath) or self.is_ignored(relpath):
1951
# Add nested content for deletion.
1952
new_files.add(relpath)
1954
# Files which are not versioned and not ignored
1955
# should be treated as unknown.
1956
unknown_nested_files.add((relpath, None, kind))
1791
osutils.walkdirs(self.abspath(directory),
1793
for relpath, basename, kind, lstat, abspath in file_infos:
1795
if self.path2id(relpath): #is it versioned?
1796
new_files.add(relpath)
1798
unknown_files_in_directory.add(
1799
(relpath, None, kind))
1958
1801
for filename in files:
1959
1802
# Get file name into canonical form.
1961
1804
filename = self.relpath(abspath)
1962
1805
if len(filename) > 0:
1963
1806
new_files.add(filename)
1964
recurse_directory_to_add_files(filename)
1966
files = list(new_files)
1807
if osutils.isdir(abspath):
1808
recurse_directory_to_add_files(filename)
1809
files = [f for f in new_files]
1968
1811
if len(files) == 0:
1969
1812
return # nothing to do
1971
1814
# Sort needed to first handle directory content before the directory
1972
1815
files.sort(reverse=True)
1974
# Bail out if we are going to delete files we shouldn't
1975
1816
if not keep_files and not force:
1976
has_changed_files = len(unknown_nested_files) > 0
1817
has_changed_files = len(unknown_files_in_directory) > 0
1977
1818
if not has_changed_files:
1978
1819
for (file_id, path, content_change, versioned, parent_id, name,
1979
kind, executable) in self.iter_changes(self.basis_tree(),
1820
kind, executable) in self._iter_changes(self.basis_tree(),
1980
1821
include_unchanged=True, require_versioned=False,
1981
1822
want_unversioned=True, specific_files=files):
1982
if versioned == (False, False):
1983
# The record is unknown ...
1984
if not self.is_ignored(path[1]):
1985
# ... but not ignored
1986
has_changed_files = True
1988
elif content_change and (kind[1] is not None):
1989
# Versioned and changed, but not deleted
1823
# check if it's unknown OR changed but not deleted:
1824
if (versioned == (False, False)
1825
or (content_change and kind[1] != None)):
1990
1826
has_changed_files = True
1993
1829
if has_changed_files:
1994
# Make delta show ALL applicable changes in error message.
1830
# make delta to show ALL applicable changes in error message.
1995
1831
tree_delta = self.changes_from(self.basis_tree(),
1996
require_versioned=False, want_unversioned=True,
1997
1832
specific_files=files)
1998
for unknown_file in unknown_nested_files:
1999
if unknown_file not in tree_delta.unversioned:
2000
tree_delta.unversioned.extend((unknown_file,))
1833
for unknown_file in unknown_files_in_directory:
1834
tree_delta.unversioned.extend((unknown_file,))
2001
1835
raise errors.BzrRemoveChangedFilesError(tree_delta)
2003
# Build inv_delta and delete files where applicable,
2004
# do this before any modifications to inventory.
1837
# do this before any modifications
2005
1838
for f in files:
2006
1839
fid = self.path2id(f)
2009
message = "%s is not versioned." % (f,)
1842
message="%s is not versioned." % (f,)
2012
1845
# having removed it, it must be either ignored or unknown
2016
1849
new_status = '?'
2017
1850
textui.show_status(new_status, self.kind(fid), f,
2018
1851
to_file=to_file)
2020
1853
inv_delta.append((f, None, fid, None))
2021
message = "removed %s" % (f,)
1854
message="removed %s" % (f,)
2023
1856
if not keep_files:
2024
1857
abs_path = self.abspath(f)
2025
1858
if osutils.lexists(abs_path):
2026
1859
if (osutils.isdir(abs_path) and
2027
1860
len(os.listdir(abs_path)) > 0):
2029
osutils.rmtree(abs_path)
2031
message = "%s is not an empty directory "\
2032
"and won't be deleted." % (f,)
1861
message="%s is not empty directory "\
1862
"and won't be deleted." % (f,)
2034
1864
osutils.delete_any(abs_path)
2035
message = "deleted %s" % (f,)
1865
message="deleted %s" % (f,)
2036
1866
elif message is not None:
2037
# Only care if we haven't done anything yet.
2038
message = "%s does not exist." % (f,)
1867
# only care if we haven't done anything yet.
1868
message="%s does not exist." % (f,)
2040
# Print only one message (if any) per file.
1870
# print only one message (if any) per file.
2041
1871
if message is not None:
2043
1873
self.apply_inventory_delta(inv_delta)
2045
1875
@needs_tree_write_lock
2046
def revert(self, filenames=None, old_tree=None, backups=True,
1876
def revert(self, filenames, old_tree=None, backups=True,
2047
1877
pb=DummyProgress(), report_changes=False):
2048
1878
from bzrlib.conflicts import resolve
2051
symbol_versioning.warn('Using [] to revert all files is deprecated'
2052
' as of bzr 0.91. Please use None (the default) instead.',
2053
DeprecationWarning, stacklevel=2)
2054
1879
if old_tree is None:
2055
basis_tree = self.basis_tree()
2056
basis_tree.lock_read()
2057
old_tree = basis_tree
1880
old_tree = self.basis_tree()
1881
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1883
if not len(filenames):
1884
self.set_parent_ids(self.get_parent_ids()[:1])
2061
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
2063
if filenames is None and len(self.get_parent_ids()) > 1:
2065
last_revision = self.last_revision()
2066
if last_revision != _mod_revision.NULL_REVISION:
2067
if basis_tree is None:
2068
basis_tree = self.basis_tree()
2069
basis_tree.lock_read()
2070
parent_trees.append((last_revision, basis_tree))
2071
self.set_parent_trees(parent_trees)
2074
resolve(self, filenames, ignore_misses=True, recursive=True)
2076
if basis_tree is not None:
1887
resolve(self, filenames, ignore_misses=True)
2078
1888
return conflicts
2080
1890
def revision_tree(self, revision_id):
2128
1939
@needs_tree_write_lock
2129
1940
def set_root_id(self, file_id):
2130
1941
"""Set the root id for this tree."""
2132
1943
if file_id is None:
2134
'WorkingTree.set_root_id with fileid=None')
2135
file_id = osutils.safe_file_id(file_id)
1944
symbol_versioning.warn(symbol_versioning.zero_twelve
1945
% 'WorkingTree.set_root_id with fileid=None',
1950
file_id = osutils.safe_file_id(file_id)
2136
1951
self._set_root_id(file_id)
2138
1953
def _set_root_id(self, file_id):
2139
1954
"""Set the root id for this tree, in a format specific manner.
2141
:param file_id: The file id to assign to the root. It must not be
1956
:param file_id: The file id to assign to the root. It must not be
2142
1957
present in the current inventory or an error will occur. It must
2143
1958
not be None, but rather a valid file id.
2164
1979
def unlock(self):
2165
1980
"""See Branch.unlock.
2167
1982
WorkingTree locking just uses the Branch locking facilities.
2168
1983
This is current because all working trees have an embedded branch
2169
1984
within them. IF in the future, we were to make branch data shareable
2170
between multiple working trees, i.e. via shared storage, then we
1985
between multiple working trees, i.e. via shared storage, then we
2171
1986
would probably want to lock both the local tree, and the branch.
2173
1988
raise NotImplementedError(self.unlock)
2175
def update(self, change_reporter=None, possible_transports=None):
1990
def update(self, change_reporter=None):
2176
1991
"""Update a working tree along its branch.
2178
1993
This will update the branch if its bound too, which means we have
2256
2071
parent_trees = [(self.branch.last_revision(), to_tree)]
2257
2072
merges = self.get_parent_ids()[1:]
2258
2073
# Ideally we ask the tree for the trees here, that way the working
2259
# tree can decide whether to give us the entire tree or give us a
2074
# tree can decide whether to give us teh entire tree or give us a
2260
2075
# lazy initialised tree. dirstate for instance will have the trees
2261
2076
# in ram already, whereas a last-revision + basis-inventory tree
2262
2077
# will not, but also does not need them when setting parents.
2389
2204
current_inv = None
2390
2205
inv_finished = True
2391
2206
while not inv_finished or not disk_finished:
2393
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2394
cur_disk_dir_content) = current_disk
2396
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2397
cur_disk_dir_content) = ((None, None), None)
2398
2207
if not disk_finished:
2399
2208
# strip out .bzr dirs
2400
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2401
len(cur_disk_dir_content) > 0):
2402
# osutils.walkdirs can be made nicer -
2209
if current_disk[0][1][top_strip_len:] == '':
2210
# osutils.walkdirs can be made nicer -
2403
2211
# yield the path-from-prefix rather than the pathjoined
2405
bzrdir_loc = bisect_left(cur_disk_dir_content,
2407
if (bzrdir_loc < len(cur_disk_dir_content)
2408
and self.bzrdir.is_control_filename(
2409
cur_disk_dir_content[bzrdir_loc][0])):
2213
bzrdir_loc = bisect_left(current_disk[1], ('.bzr', '.bzr'))
2214
if current_disk[1][bzrdir_loc][0] == '.bzr':
2410
2215
# we dont yield the contents of, or, .bzr itself.
2411
del cur_disk_dir_content[bzrdir_loc]
2216
del current_disk[1][bzrdir_loc]
2412
2217
if inv_finished:
2413
2218
# everything is unknown
2416
2221
# everything is missing
2419
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2224
direction = cmp(current_inv[0][0], current_disk[0][0])
2420
2225
if direction > 0:
2421
2226
# disk is before inventory - unknown
2422
2227
dirblock = [(relpath, basename, kind, stat, None, None) for
2423
relpath, basename, kind, stat, top_path in
2424
cur_disk_dir_content]
2425
yield (cur_disk_dir_relpath, None), dirblock
2228
relpath, basename, kind, stat, top_path in current_disk[1]]
2229
yield (current_disk[0][0], None), dirblock
2427
2231
current_disk = disk_iterator.next()
2428
2232
except StopIteration:
2430
2234
elif direction < 0:
2431
2235
# inventory is before disk - missing.
2432
2236
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2433
for relpath, basename, dkind, stat, fileid, kind in
2237
for relpath, basename, dkind, stat, fileid, kind in
2434
2238
current_inv[1]]
2435
2239
yield (current_inv[0][0], current_inv[0][1]), dirblock
2442
2246
# merge the inventory and disk data together
2444
2248
for relpath, subiterator in itertools.groupby(sorted(
2445
current_inv[1] + cur_disk_dir_content,
2446
key=operator.itemgetter(0)), operator.itemgetter(1)):
2249
current_inv[1] + current_disk[1], key=operator.itemgetter(0)), operator.itemgetter(1)):
2447
2250
path_elements = list(subiterator)
2448
2251
if len(path_elements) == 2:
2449
2252
inv_row, disk_row = path_elements
2503
2306
# FIXME: stash the node in pending
2504
2307
entry = inv[top_id]
2505
if entry.kind == 'directory':
2506
for name, child in entry.sorted_children():
2507
dirblock.append((relroot + name, name, child.kind, None,
2508
child.file_id, child.kind
2308
for name, child in entry.sorted_children():
2309
dirblock.append((relroot + name, name, child.kind, None,
2310
child.file_id, child.kind
2510
2312
yield (currentdir[0], entry.file_id), dirblock
2511
2313
# push the user specified dirs from dirblock
2512
2314
for dir in reversed(dirblock):
2545
2347
self.set_conflicts(un_resolved)
2546
2348
return un_resolved, resolved
2549
def _check(self, references):
2550
"""Check the tree for consistency.
2552
:param references: A dict with keys matching the items returned by
2553
self._get_check_refs(), and values from looking those keys up in
2556
tree_basis = self.basis_tree()
2557
tree_basis.lock_read()
2559
repo_basis = references[('trees', self.last_revision())]
2560
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2561
raise errors.BzrCheckError(
2562
"Mismatched basis inventory content.")
2567
2350
def _validate(self):
2568
2351
"""Validate internal structures.
2579
def _get_rules_searcher(self, default_searcher):
2580
"""See Tree._get_rules_searcher."""
2581
if self._rules_searcher is None:
2582
self._rules_searcher = super(WorkingTree,
2583
self)._get_rules_searcher(default_searcher)
2584
return self._rules_searcher
2586
def get_shelf_manager(self):
2587
"""Return the ShelfManager for this WorkingTree."""
2588
from bzrlib.shelf import ShelfManager
2589
return ShelfManager(self, self._transport)
2592
2362
class WorkingTree2(WorkingTree):
2593
2363
"""This is the Format 2 working tree.
2595
This was the first weave based working tree.
2365
This was the first weave based working tree.
2596
2366
- uses os locks for locking.
2597
2367
- uses the branch last-revision.
2657
2420
def _last_revision(self):
2658
2421
"""See Mutable.last_revision."""
2660
return self._transport.get_bytes('last-revision')
2423
return osutils.safe_revision_id(
2424
self._control_files.get('last-revision').read())
2661
2425
except errors.NoSuchFile:
2662
return _mod_revision.NULL_REVISION
2664
2428
def _change_last_revision(self, revision_id):
2665
2429
"""See WorkingTree._change_last_revision."""
2666
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2430
if revision_id is None or revision_id == NULL_REVISION:
2668
self._transport.delete('last-revision')
2432
self._control_files._transport.delete('last-revision')
2669
2433
except errors.NoSuchFile:
2673
self._transport.put_bytes('last-revision', revision_id,
2674
mode=self.bzrdir._get_file_mode())
2437
self._control_files.put_bytes('last-revision', revision_id)
2677
def _get_check_refs(self):
2678
"""Return the references needed to perform a check of this tree."""
2679
return [('trees', self.last_revision())]
2681
2440
@needs_tree_write_lock
2682
2441
def set_conflicts(self, conflicts):
2683
self._put_rio('conflicts', conflicts.to_stanzas(),
2442
self._put_rio('conflicts', conflicts.to_stanzas(),
2684
2443
CONFLICT_HEADER_1)
2686
2445
@needs_tree_write_lock
2693
2452
@needs_read_lock
2694
2453
def conflicts(self):
2696
confile = self._transport.get('conflicts')
2455
confile = self._control_files.get('conflicts')
2697
2456
except errors.NoSuchFile:
2698
2457
return _mod_conflicts.ConflictList()
2701
if confile.next() != CONFLICT_HEADER_1 + '\n':
2702
raise errors.ConflictFormatError()
2703
except StopIteration:
2459
if confile.next() != CONFLICT_HEADER_1 + '\n':
2704
2460
raise errors.ConflictFormatError()
2705
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2461
except StopIteration:
2462
raise errors.ConflictFormatError()
2463
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2709
2465
def unlock(self):
2710
# do non-implementation specific cleanup
2712
2466
if self._control_files._lock_count == 1:
2713
2467
# _inventory_is_modified is always False during a read lock.
2714
2468
if self._inventory_is_modified:
2727
2481
return path[:-len(suffix)]
2484
@deprecated_function(zero_eight)
2485
def is_control_file(filename):
2486
"""See WorkingTree.is_control_filename(filename)."""
2487
## FIXME: better check
2488
filename = normpath(filename)
2489
while filename != '':
2490
head, tail = os.path.split(filename)
2491
## mutter('check %r for control file' % ((head, tail),))
2494
if filename == head:
2730
2500
class WorkingTreeFormat(object):
2731
2501
"""An encapsulation of the initialization and open routines for a format.
2735
2505
* a format string,
2736
2506
* an open routine.
2738
Formats are placed in an dict by their format string for reference
2508
Formats are placed in an dict by their format string for reference
2739
2509
during workingtree opening. Its not required that these be instances, they
2740
can be classes themselves with class methods - it simply depends on
2510
can be classes themselves with class methods - it simply depends on
2741
2511
whether state is needed for a given format or not.
2743
2513
Once a format is deprecated, just deprecate the initialize and open
2744
methods on the format class. Do not deprecate the object, as the
2514
methods on the format class. Do not deprecate the object, as the
2745
2515
object will be created every time regardless.
2791
2560
"""Is this format supported?
2793
2562
Supported formats can be initialized and opened.
2794
Unsupported formats may not support initialization or committing or
2563
Unsupported formats may not support initialization or committing or
2795
2564
some other features depending on the reason for not being supported.
2799
def supports_content_filtering(self):
2800
"""True if this format supports content filtering."""
2803
def supports_views(self):
2804
"""True if this format supports stored views."""
2808
2569
def register_format(klass, format):
2809
2570
klass._formats[format.get_format_string()] = format
2829
2591
"""See WorkingTreeFormat.get_format_description()."""
2830
2592
return "Working tree format 2"
2832
def _stub_initialize_on_transport(self, transport, file_mode):
2833
"""Workaround: create control files for a remote working tree.
2594
def stub_initialize_remote(self, control_files):
2595
"""As a special workaround create critical control files for a remote working tree
2835
2597
This ensures that it can later be updated and dealt with locally,
2836
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2598
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2837
2599
no working tree. (See bug #43064).
2839
2601
sio = StringIO()
2840
inv = inventory.Inventory()
2841
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2603
xml5.serializer_v5.write_inventory(inv, sio)
2843
transport.put_file('inventory', sio, file_mode)
2844
transport.put_bytes('pending-merges', '', file_mode)
2846
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2847
accelerator_tree=None, hardlink=False):
2605
control_files.put('inventory', sio)
2607
control_files.put_bytes('pending-merges', '')
2610
def initialize(self, a_bzrdir, revision_id=None):
2848
2611
"""See WorkingTreeFormat.initialize()."""
2849
2612
if not isinstance(a_bzrdir.transport, LocalTransport):
2850
2613
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2851
if from_branch is not None:
2852
branch = from_branch
2854
branch = a_bzrdir.open_branch()
2614
branch = a_bzrdir.open_branch()
2855
2615
if revision_id is None:
2856
2616
revision_id = _mod_revision.ensure_null(branch.last_revision())
2618
revision_id = osutils.safe_revision_id(revision_id)
2857
2619
branch.lock_write()
2859
2621
branch.generate_revision_history(revision_id)
2861
2623
branch.unlock()
2862
inv = inventory.Inventory()
2863
2625
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2934
2696
def _open_control_files(self, a_bzrdir):
2935
2697
transport = a_bzrdir.get_workingtree_transport(None)
2936
return LockableFiles(transport, self._lock_file_name,
2698
return LockableFiles(transport, self._lock_file_name,
2937
2699
self._lock_class)
2939
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2940
accelerator_tree=None, hardlink=False):
2701
def initialize(self, a_bzrdir, revision_id=None):
2941
2702
"""See WorkingTreeFormat.initialize().
2943
:param revision_id: if supplied, create a working tree at a different
2944
revision than the branch is at.
2945
:param accelerator_tree: A tree which can be used for retrieving file
2946
contents more quickly than the revision tree, i.e. a workingtree.
2947
The revision tree will be used for cases where accelerator_tree's
2948
content is different.
2949
:param hardlink: If true, hard-link files from accelerator_tree,
2704
revision_id allows creating a working tree at a different
2705
revision than the branch is at.
2952
2707
if not isinstance(a_bzrdir.transport, LocalTransport):
2953
2708
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2955
2710
control_files = self._open_control_files(a_bzrdir)
2956
2711
control_files.create_lock()
2957
2712
control_files.lock_write()
2958
transport.put_bytes('format', self.get_format_string(),
2959
mode=a_bzrdir._get_file_mode())
2960
if from_branch is not None:
2961
branch = from_branch
2963
branch = a_bzrdir.open_branch()
2713
control_files.put_utf8('format', self.get_format_string())
2714
branch = a_bzrdir.open_branch()
2964
2715
if revision_id is None:
2965
2716
revision_id = _mod_revision.ensure_null(branch.last_revision())
2718
revision_id = osutils.safe_revision_id(revision_id)
2966
2719
# WorkingTree3 can handle an inventory which has a unique root id.
2967
2720
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2968
2721
# those trees. And because there isn't a format bump inbetween, we