90
89
from bzrlib.lockdir import LockDir
91
90
import bzrlib.mutabletree
92
91
from bzrlib.mutabletree import needs_tree_write_lock
92
from bzrlib import osutils
93
93
from bzrlib.osutils import (
454
454
def get_file(self, file_id, path=None):
456
file_id = osutils.safe_file_id(file_id)
457
456
path = self.id2path(file_id)
458
457
return self.get_file_byname(path)
460
459
def get_file_text(self, file_id):
461
file_id = osutils.safe_file_id(file_id)
462
460
return self.get_file(file_id).read()
464
462
def get_file_byname(self, filename):
572
568
tree.set_parent_ids([revision_id])
574
570
def id2abspath(self, file_id):
575
file_id = osutils.safe_file_id(file_id)
576
571
return self.abspath(self.id2path(file_id))
578
573
def has_id(self, file_id):
579
574
# files that have been deleted are excluded
580
file_id = osutils.safe_file_id(file_id)
581
575
inv = self.inventory
582
576
if not inv.has_id(file_id):
585
579
return osutils.lexists(self.abspath(path))
587
581
def has_or_had_id(self, file_id):
588
file_id = osutils.safe_file_id(file_id)
589
582
if file_id == self.inventory.root.file_id:
591
584
return self.inventory.has_id(file_id)
593
586
__contains__ = has_id
595
588
def get_file_size(self, file_id):
596
file_id = osutils.safe_file_id(file_id)
597
589
return os.path.getsize(self.id2abspath(file_id))
600
592
def get_file_sha1(self, file_id, path=None, stat_value=None):
601
file_id = osutils.safe_file_id(file_id)
603
594
path = self._inventory.id2path(file_id)
604
595
return self._hashcache.get_sha1(path, stat_value)
606
597
def get_file_mtime(self, file_id, path=None):
607
file_id = osutils.safe_file_id(file_id)
609
599
path = self.inventory.id2path(file_id)
610
600
return os.lstat(self.abspath(path)).st_mtime
602
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
603
file_id = self.path2id(path)
604
return self._inventory[file_id].executable
606
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
607
mode = stat_result.st_mode
608
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
612
610
if not supports_executable():
613
611
def is_executable(self, file_id, path=None):
614
file_id = osutils.safe_file_id(file_id)
615
612
return self._inventory[file_id].executable
614
_is_executable_from_path_and_stat = \
615
_is_executable_from_path_and_stat_from_basis
617
617
def is_executable(self, file_id, path=None):
619
file_id = osutils.safe_file_id(file_id)
620
619
path = self.id2path(file_id)
621
620
mode = os.lstat(self.abspath(path)).st_mode
622
621
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
623
_is_executable_from_path_and_stat = \
624
_is_executable_from_path_and_stat_from_stat
624
626
@needs_tree_write_lock
625
627
def _add(self, files, ids, kinds):
626
628
"""See MutableTree._add."""
634
636
if file_id is None:
635
637
inv.add_path(f, kind=kind)
637
file_id = osutils.safe_file_id(file_id)
638
639
inv.add_path(f, kind=kind, file_id=file_id)
639
640
self._inventory_is_modified = True
703
704
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
706
def path_content_summary(self, path, _lstat=os.lstat,
707
_mapper=osutils.file_kind_from_stat_mode):
708
"""See Tree.path_content_summary."""
709
abspath = self.abspath(path)
711
stat_result = _lstat(abspath)
713
if getattr(e, 'errno', None) == errno.ENOENT:
715
return ('missing', None, None, None)
716
# propagate other errors
718
kind = _mapper(stat_result.st_mode)
720
size = stat_result.st_size
721
# try for a stat cache lookup
722
executable = self._is_executable_from_path_and_stat(path, stat_result)
723
return (kind, size, executable, self._sha_from_stat(
725
elif kind == 'directory':
726
# perhaps it looks like a plain directory, but it's really a
728
if self._directory_is_tree_reference(path):
729
kind = 'tree-reference'
730
return kind, None, None, None
731
elif kind == 'symlink':
732
return ('symlink', None, None, os.readlink(abspath))
734
return (kind, None, None, None)
705
736
@deprecated_method(zero_eleven)
707
738
def pending_merges(self):
744
775
:param revision_ids: The revision_ids to set as the parent ids of this
745
776
working tree. Any of these may be ghosts.
747
revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
748
778
self._check_parents_for_ghosts(revision_ids,
749
779
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
750
780
for revision_id in revision_ids:
760
790
@needs_tree_write_lock
761
791
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
762
792
"""See MutableTree.set_parent_trees."""
763
parent_ids = [osutils.safe_revision_id(rev) for (rev, tree) in parents_list]
793
parent_ids = [rev for (rev, tree) in parents_list]
764
794
for revision_id in parent_ids:
765
795
_mod_revision.check_not_reserved_id(revision_id)
799
829
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
800
830
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
832
def _sha_from_stat(self, path, stat_result):
833
"""Get a sha digest from the tree's stat cache.
835
The default implementation assumes no stat cache is present.
837
:param path: The path.
838
:param stat_result: The stat result being looked up.
802
842
def _put_rio(self, filename, stanzas, header):
803
843
self._must_be_locked()
804
844
my_file = rio_file(stanzas, header)
826
866
merger.check_basis(check_clean=True, require_commits=False)
827
867
if to_revision is None:
828
868
to_revision = _mod_revision.ensure_null(branch.last_revision())
830
to_revision = osutils.safe_revision_id(to_revision)
831
869
merger.other_rev_id = to_revision
832
870
if _mod_revision.is_null(merger.other_rev_id):
833
871
raise errors.NoCommits(branch)
943
980
other_tree.unlock()
944
981
other_tree.bzrdir.retire_bzrdir()
983
def _directory_is_tree_reference(self, relpath):
984
# as a special case, if a directory contains control files then
985
# it's a tree reference, except that the root of the tree is not
986
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
987
# TODO: We could ask all the control formats whether they
988
# recognize this directory, but at the moment there's no cheap api
989
# to do that. Since we probably can only nest bzr checkouts and
990
# they always use this name it's ok for now. -- mbp 20060306
992
# FIXME: There is an unhandled case here of a subdirectory
993
# containing .bzr but not a branch; that will probably blow up
994
# when you try to commit it. It might happen if there is a
995
# checkout in a subdirectory. This can be avoided by not adding
946
998
@needs_tree_write_lock
947
999
def extract(self, file_id, format=None):
948
1000
"""Extract a subtree from this tree.
1464
1515
@needs_write_lock
1465
1516
def pull(self, source, overwrite=False, stop_revision=None,
1466
change_reporter=None):
1517
change_reporter=None, possible_transports=None):
1467
1518
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1468
1519
source.lock_read()
1471
1522
pp.next_phase()
1472
1523
old_revision_info = self.branch.last_revision_info()
1473
1524
basis_tree = self.basis_tree()
1474
count = self.branch.pull(source, overwrite, stop_revision)
1525
count = self.branch.pull(source, overwrite, stop_revision,
1526
possible_transports=possible_transports)
1475
1527
new_revision_info = self.branch.last_revision_info()
1476
1528
if new_revision_info != old_revision_info:
1477
1529
pp.next_phase()
1515
1567
@needs_write_lock
1516
1568
def put_file_bytes_non_atomic(self, file_id, bytes):
1517
1569
"""See MutableTree.put_file_bytes_non_atomic."""
1518
file_id = osutils.safe_file_id(file_id)
1519
1570
stream = file(self.id2abspath(file_id), 'wb')
1521
1572
stream.write(bytes)
1700
1751
@needs_tree_write_lock
1701
1752
def set_last_revision(self, new_revision):
1702
1753
"""Change the last revision in the working tree."""
1703
new_revision = osutils.safe_revision_id(new_revision)
1704
1754
if self._change_last_revision(new_revision):
1705
1755
self._cache_basis_inventory(new_revision)
1730
1780
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1731
1781
"""Create the text that will be saved in basis-inventory"""
1732
# TODO: jam 20070209 This should be redundant, as the revision_id
1733
# as all callers should have already converted the revision_id to
1735
inventory.revision_id = osutils.safe_revision_id(revision_id)
1782
inventory.revision_id = revision_id
1736
1783
return xml7.serializer_v7.write_inventory_to_string(inventory)
1738
1785
def _cache_basis_inventory(self, new_revision):
1913
1960
' as of bzr 0.91. Please use None (the default) instead.',
1914
1961
DeprecationWarning, stacklevel=2)
1915
1962
if old_tree is None:
1916
old_tree = self.basis_tree()
1917
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1919
if filenames is None:
1920
self.set_parent_ids(self.get_parent_ids()[:1])
1963
basis_tree = self.basis_tree()
1964
basis_tree.lock_read()
1965
old_tree = basis_tree
1923
resolve(self, filenames, ignore_misses=True)
1969
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1971
if filenames is None and len(self.get_parent_ids()) > 1:
1973
last_revision = self.last_revision()
1974
if last_revision != NULL_REVISION:
1975
if basis_tree is None:
1976
basis_tree = self.basis_tree()
1977
basis_tree.lock_read()
1978
parent_trees.append((last_revision, basis_tree))
1979
self.set_parent_trees(parent_trees)
1982
resolve(self, filenames, ignore_misses=True)
1984
if basis_tree is not None:
1924
1986
return conflicts
1926
1988
def revision_tree(self, revision_id):
2459
2521
def _last_revision(self):
2460
2522
"""See Mutable.last_revision."""
2462
return osutils.safe_revision_id(
2463
self._control_files.get('last-revision').read())
2524
return self._control_files.get('last-revision').read()
2464
2525
except errors.NoSuchFile:
2465
2526
return _mod_revision.NULL_REVISION
2755
2814
branch = a_bzrdir.open_branch()
2756
2815
if revision_id is None:
2757
2816
revision_id = _mod_revision.ensure_null(branch.last_revision())
2759
revision_id = osutils.safe_revision_id(revision_id)
2760
2817
# WorkingTree3 can handle an inventory which has a unique root id.
2761
2818
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2762
2819
# those trees. And because there isn't a format bump inbetween, we