120
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()
123
144
class TreeEntry(object):
124
145
"""An entry that implements the minimum interface used by commands.
201
222
if not _internal:
202
223
raise errors.BzrError("Please use bzrdir.open_workingtree or "
203
224
"WorkingTree.open() to obtain a WorkingTree.")
225
assert isinstance(basedir, basestring), \
226
"base directory %r is not a string" % basedir
204
227
basedir = safe_unicode(basedir)
205
228
mutter("opening working tree %r", basedir)
206
229
if deprecated_passed(branch):
214
237
self._control_files = self.branch.control_files
216
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" \
217
243
self._control_files = _control_files
218
self._transport = self._control_files._transport
219
244
# update the whole cache up front and write to disk if anything changed;
220
245
# in the future we might want to do this more selectively
221
246
# two possible ways offer themselves : in self._unlock, write the cache
225
250
wt_trans = self.bzrdir.get_workingtree_transport(None)
226
251
cache_filename = wt_trans.local_abspath('stat-cache')
227
252
self._hashcache = hashcache.HashCache(basedir, cache_filename,
228
self.bzrdir._get_file_mode())
253
self._control_files._file_mode)
229
254
hc = self._hashcache
231
256
# is this scan needed ? it makes things kinda slow.
245
270
# the Format factory and creation methods that are
246
271
# permitted to do this.
247
272
self._set_inventory(_inventory, dirty=False)
248
self._detect_case_handling()
249
self._rules_searcher = None
251
def _detect_case_handling(self):
252
wt_trans = self.bzrdir.get_workingtree_transport(None)
254
wt_trans.stat("FoRMaT")
255
except errors.NoSuchFile:
256
self.case_sensitive = True
258
self.case_sensitive = False
260
self._setup_directory_is_tree_reference()
262
274
branch = property(
263
275
fget=lambda self: self._branch,
335
348
return WorkingTree.open(path, _unsupported=True)
338
def find_trees(location):
339
def list_current(transport):
340
return [d for d in transport.list_dir('') if d != '.bzr']
341
def evaluate(bzrdir):
343
tree = bzrdir.open_workingtree()
344
except errors.NoWorkingTree:
348
transport = get_transport(location)
349
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
350
list_current=list_current)
351
return [t for t in iterator if t is not None]
353
350
# should be deprecated - this is slow and in any case treating them as a
354
351
# container is (we now know) bad style -- mbp 20070302
355
352
## @deprecated_method(zero_fifteen)
364
361
if osutils.lexists(self.abspath(path)):
367
def all_file_ids(self):
368
"""See Tree.iter_all_file_ids"""
369
return set(self.inventory)
371
364
def __repr__(self):
372
365
return "<%s of %s>" % (self.__class__.__name__,
373
366
getattr(self, 'basedir', None))
397
390
# at this point ?
399
392
return self.branch.repository.revision_tree(revision_id)
400
except (errors.RevisionNotPresent, errors.NoSuchRevision):
393
except errors.RevisionNotPresent:
401
394
# the basis tree *may* be a ghost or a low level error may have
402
395
# occured. If the revision is present, its a problem, if its not
409
402
def _cleanup(self):
410
403
self._flush_ignore_list_cache()
406
@deprecated_method(zero_eight)
407
def create(branch, directory):
408
"""Create a workingtree for branch at directory.
410
If existing_directory already exists it must have a .bzr directory.
411
If it does not exist, it will be created.
413
This returns a new WorkingTree object for the new checkout.
415
TODO FIXME RBC 20060124 when we have checkout formats in place this
416
should accept an optional revisionid to checkout [and reject this if
417
checking out into the same dir as a pre-checkout-aware branch format.]
419
XXX: When BzrDir is present, these should be created through that
422
warnings.warn('delete WorkingTree.create', stacklevel=3)
423
transport = get_transport(directory)
424
if branch.bzrdir.root_transport.base == transport.base:
426
return branch.bzrdir.create_workingtree()
427
# different directory,
428
# create a branch reference
429
# and now a working tree.
430
raise NotImplementedError
433
@deprecated_method(zero_eight)
434
def create_standalone(directory):
435
"""Create a checkout and a branch and a repo at directory.
437
Directory must exist and be empty.
439
please use BzrDir.create_standalone_workingtree
441
return bzrdir.BzrDir.create_standalone_workingtree(directory)
412
443
def relpath(self, path):
413
444
"""Return the local path portion from a given path.
423
454
def get_file(self, file_id, path=None):
456
file_id = osutils.safe_file_id(file_id)
425
457
path = self.id2path(file_id)
426
458
return self.get_file_byname(path)
428
460
def get_file_text(self, file_id):
461
file_id = osutils.safe_file_id(file_id)
429
462
return self.get_file(file_id).read()
431
464
def get_file_byname(self, filename):
442
475
incorrectly attributed to CURRENT_REVISION (but after committing, the
443
476
attribution will be correct).
478
file_id = osutils.safe_file_id(file_id)
445
479
basis = self.basis_tree()
446
480
basis.lock_read()
448
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
482
changes = self._iter_changes(basis, True, [self.id2path(file_id)],
449
483
require_versioned=True).next()
450
484
changed_content, kind = changes[2], changes[6]
451
485
if not changed_content:
488
522
parents = [last_rev]
490
merges_file = self._transport.get('pending-merges')
524
merges_file = self._control_files.get('pending-merges')
491
525
except errors.NoSuchFile:
494
528
for l in merges_file.readlines():
495
revision_id = l.rstrip('\n')
529
revision_id = osutils.safe_revision_id(l.rstrip('\n'))
496
530
parents.append(revision_id)
537
572
tree.set_parent_ids([revision_id])
539
574
def id2abspath(self, file_id):
575
file_id = osutils.safe_file_id(file_id)
540
576
return self.abspath(self.id2path(file_id))
542
578
def has_id(self, file_id):
543
579
# files that have been deleted are excluded
580
file_id = osutils.safe_file_id(file_id)
544
581
inv = self.inventory
545
582
if not inv.has_id(file_id):
548
585
return osutils.lexists(self.abspath(path))
550
587
def has_or_had_id(self, file_id):
588
file_id = osutils.safe_file_id(file_id)
551
589
if file_id == self.inventory.root.file_id:
553
591
return self.inventory.has_id(file_id)
555
593
__contains__ = has_id
557
595
def get_file_size(self, file_id):
558
"""See Tree.get_file_size"""
560
return os.path.getsize(self.id2abspath(file_id))
562
if e.errno != errno.ENOENT:
596
file_id = osutils.safe_file_id(file_id)
597
return os.path.getsize(self.id2abspath(file_id))
568
600
def get_file_sha1(self, file_id, path=None, stat_value=None):
601
file_id = osutils.safe_file_id(file_id)
570
603
path = self._inventory.id2path(file_id)
571
604
return self._hashcache.get_sha1(path, stat_value)
573
606
def get_file_mtime(self, file_id, path=None):
607
file_id = osutils.safe_file_id(file_id)
575
609
path = self.inventory.id2path(file_id)
576
610
return os.lstat(self.abspath(path)).st_mtime
578
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
579
file_id = self.path2id(path)
580
return self._inventory[file_id].executable
582
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
583
mode = stat_result.st_mode
584
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
586
612
if not supports_executable():
587
613
def is_executable(self, file_id, path=None):
614
file_id = osutils.safe_file_id(file_id)
588
615
return self._inventory[file_id].executable
590
_is_executable_from_path_and_stat = \
591
_is_executable_from_path_and_stat_from_basis
593
617
def is_executable(self, file_id, path=None):
619
file_id = osutils.safe_file_id(file_id)
595
620
path = self.id2path(file_id)
596
621
mode = os.lstat(self.abspath(path)).st_mode
597
622
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
599
_is_executable_from_path_and_stat = \
600
_is_executable_from_path_and_stat_from_stat
602
624
@needs_tree_write_lock
603
625
def _add(self, files, ids, kinds):
604
626
"""See MutableTree._add."""
608
630
# function - they should be part of lock_write and unlock.
609
631
inv = self.inventory
610
632
for f, file_id, kind in zip(files, ids, kinds):
633
assert kind is not None
611
634
if file_id is None:
612
635
inv.add_path(f, kind=kind)
637
file_id = osutils.safe_file_id(file_id)
614
638
inv.add_path(f, kind=kind, file_id=file_id)
615
639
self._inventory_is_modified = True
688
712
if getattr(e, 'errno', None) == errno.ENOENT:
690
714
return ('missing', None, None, None)
691
# propagate other errors
715
# propogate other errors
693
717
kind = _mapper(stat_result.st_mode)
694
718
if kind == 'file':
695
719
size = stat_result.st_size
696
720
# try for a stat cache lookup
697
executable = self._is_executable_from_path_and_stat(path, stat_result)
698
return (kind, size, executable, self._sha_from_stat(
721
if not supports_executable():
722
executable = None # caller can decide policy.
724
mode = stat_result.st_mode
725
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
726
sha1 = None # 'stat-hit-check' here
727
return (kind, size, executable, sha1)
700
728
elif kind == 'directory':
701
729
# perhaps it looks like a plain directory, but it's really a
709
737
return (kind, None, None, None)
739
@deprecated_method(zero_eleven)
741
def pending_merges(self):
742
"""Return a list of pending merges.
744
These are revisions that have been merged into the working
745
directory but not yet committed.
747
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
748
instead - which is available on all tree objects.
750
return self.get_parent_ids()[1:]
711
752
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
712
753
"""Common ghost checking functionality from set_parent_*.
723
764
def _set_merges_from_parent_ids(self, parent_ids):
724
765
merges = parent_ids[1:]
725
self._transport.put_bytes('pending-merges', '\n'.join(merges),
726
mode=self._control_files._file_mode)
728
def _filter_parent_ids_by_ancestry(self, revision_ids):
729
"""Check that all merged revisions are proper 'heads'.
731
This will always return the first revision_id, and any merged revisions
734
if len(revision_ids) == 0:
736
graph = self.branch.repository.get_graph()
737
heads = graph.heads(revision_ids)
738
new_revision_ids = revision_ids[:1]
739
for revision_id in revision_ids[1:]:
740
if revision_id in heads and revision_id not in new_revision_ids:
741
new_revision_ids.append(revision_id)
742
if new_revision_ids != revision_ids:
743
trace.mutter('requested to set revision_ids = %s,'
744
' but filtered to %s', revision_ids, new_revision_ids)
745
return new_revision_ids
766
self._control_files.put_bytes('pending-merges', '\n'.join(merges))
747
768
@needs_tree_write_lock
748
769
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
757
778
:param revision_ids: The revision_ids to set as the parent ids of this
758
779
working tree. Any of these may be ghosts.
781
revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
760
782
self._check_parents_for_ghosts(revision_ids,
761
783
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
762
784
for revision_id in revision_ids:
763
785
_mod_revision.check_not_reserved_id(revision_id)
765
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
767
787
if len(revision_ids) > 0:
768
788
self.set_last_revision(revision_ids[0])
774
794
@needs_tree_write_lock
775
795
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
776
796
"""See MutableTree.set_parent_trees."""
777
parent_ids = [rev for (rev, tree) in parents_list]
797
parent_ids = [osutils.safe_revision_id(rev) for (rev, tree) in parents_list]
778
798
for revision_id in parent_ids:
779
799
_mod_revision.check_not_reserved_id(revision_id)
781
801
self._check_parents_for_ghosts(parent_ids,
782
802
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
784
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
786
804
if len(parent_ids) == 0:
787
805
leftmost_parent_id = _mod_revision.NULL_REVISION
788
806
leftmost_parent_tree = None
815
833
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
816
834
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
818
def _sha_from_stat(self, path, stat_result):
819
"""Get a sha digest from the tree's stat cache.
821
The default implementation assumes no stat cache is present.
823
:param path: The path.
824
:param stat_result: The stat result being looked up.
828
836
def _put_rio(self, filename, stanzas, header):
829
837
self._must_be_locked()
830
838
my_file = rio_file(stanzas, header)
831
self._transport.put_file(filename, my_file,
832
mode=self._control_files._file_mode)
839
self._control_files.put(filename, my_file)
834
841
@needs_write_lock # because merge pulls data into the branch.
835
842
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
853
860
merger.check_basis(check_clean=True, require_commits=False)
854
861
if to_revision is None:
855
862
to_revision = _mod_revision.ensure_null(branch.last_revision())
864
to_revision = osutils.safe_revision_id(to_revision)
856
865
merger.other_rev_id = to_revision
857
866
if _mod_revision.is_null(merger.other_rev_id):
858
867
raise errors.NoCommits(branch)
967
977
other_tree.unlock()
968
978
other_tree.bzrdir.retire_bzrdir()
970
def _setup_directory_is_tree_reference(self):
971
if self._branch.repository._format.supports_tree_reference:
972
self._directory_is_tree_reference = \
973
self._directory_may_be_tree_reference
975
self._directory_is_tree_reference = \
976
self._directory_is_never_tree_reference
978
def _directory_is_never_tree_reference(self, relpath):
981
def _directory_may_be_tree_reference(self, relpath):
980
def _directory_is_tree_reference(self, relpath):
982
981
# as a special case, if a directory contains control files then
983
982
# it's a tree reference, except that the root of the tree is not
984
983
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1011
1010
sub_path = self.id2path(file_id)
1012
1011
branch_transport = mkdirs(sub_path)
1013
1012
if format is None:
1014
format = self.bzrdir.cloning_metadir()
1013
format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
1015
1014
branch_transport.ensure_base()
1016
1015
branch_bzrdir = format.initialize_on_transport(branch_transport)
1018
1017
repo = branch_bzrdir.find_repository()
1019
1018
except errors.NoRepositoryPresent:
1020
1019
repo = branch_bzrdir.create_repository()
1021
if not repo.supports_rich_root():
1022
raise errors.RootNotRich()
1020
assert repo.supports_rich_root()
1022
if not repo.supports_rich_root():
1023
raise errors.RootNotRich()
1023
1024
new_branch = branch_bzrdir.create_branch()
1024
1025
new_branch.pull(self.branch)
1025
1026
for parent_id in self.get_parent_ids():
1045
1046
def _serialize(self, inventory, out_file):
1046
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1047
xml5.serializer_v5.write_inventory(self._inventory, out_file)
1049
1049
def _deserialize(selt, in_file):
1050
1050
return xml5.serializer_v5.read_inventory(in_file)
1057
1057
sio = StringIO()
1058
1058
self._serialize(self._inventory, sio)
1060
self._transport.put_file('inventory', sio,
1061
mode=self._control_files._file_mode)
1060
self._control_files.put('inventory', sio)
1062
1061
self._inventory_is_modified = False
1064
1063
def _kind(self, relpath):
1316
1314
only_change_inv = True
1317
1315
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1318
1316
only_change_inv = False
1319
elif (not self.case_sensitive
1320
and from_rel.lower() == to_rel.lower()
1321
and self.has_filename(from_rel)):
1322
only_change_inv = False
1324
1318
# something is wrong, so lets determine what exactly
1325
1319
if not self.has_filename(from_rel) and \
1328
1322
errors.PathsDoNotExist(paths=(str(from_rel),
1331
raise errors.RenameFailedFilesExist(from_rel, to_rel)
1325
raise errors.RenameFailedFilesExist(from_rel, to_rel,
1326
extra="(Use --after to update the Bazaar id)")
1332
1327
rename_entry.only_change_inv = only_change_inv
1333
1328
return rename_entries
1496
1492
# - RBC 20060907
1497
1493
self._write_inventory(self._inventory)
1495
@deprecated_method(zero_eight)
1496
def iter_conflicts(self):
1497
"""List all files in the tree that have text or content conflicts.
1498
DEPRECATED. Use conflicts instead."""
1499
return self._iter_conflicts()
1499
1501
def _iter_conflicts(self):
1500
1502
conflicted = set()
1501
1503
for info in self.list_files():
1510
1512
@needs_write_lock
1511
1513
def pull(self, source, overwrite=False, stop_revision=None,
1512
change_reporter=None, possible_transports=None):
1514
change_reporter=None):
1513
1515
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1514
1516
source.lock_read()
1517
1519
pp.next_phase()
1518
1520
old_revision_info = self.branch.last_revision_info()
1519
1521
basis_tree = self.basis_tree()
1520
count = self.branch.pull(source, overwrite, stop_revision,
1521
possible_transports=possible_transports)
1522
count = self.branch.pull(source, overwrite, stop_revision)
1522
1523
new_revision_info = self.branch.last_revision_info()
1523
1524
if new_revision_info != old_revision_info:
1524
1525
pp.next_phase()
1562
1563
@needs_write_lock
1563
1564
def put_file_bytes_non_atomic(self, file_id, bytes):
1564
1565
"""See MutableTree.put_file_bytes_non_atomic."""
1566
file_id = osutils.safe_file_id(file_id)
1565
1567
stream = file(self.id2abspath(file_id), 'wb')
1567
1569
stream.write(bytes)
1592
1594
if subf == '.bzr':
1594
1596
if subf not in dir_entry.children:
1597
can_access) = osutils.normalized_filename(subf)
1598
except UnicodeDecodeError:
1599
path_os_enc = path.encode(osutils._fs_enc)
1600
relpath = path_os_enc + '/' + subf
1601
raise errors.BadFilenameEncoding(relpath,
1597
subf_norm, can_access = osutils.normalized_filename(subf)
1603
1598
if subf_norm != subf and can_access:
1604
1599
if subf_norm not in dir_entry.children:
1605
1600
fl.append(subf_norm)
1660
1655
def kind(self, file_id):
1661
1656
return file_kind(self.id2abspath(file_id))
1663
def stored_kind(self, file_id):
1664
"""See Tree.stored_kind"""
1665
return self.inventory[file_id].kind
1667
1658
def _comparison_data(self, entry, path):
1668
1659
abspath = self.abspath(path)
1751
1742
def _reset_data(self):
1752
1743
"""Reset transient data that cannot be revalidated."""
1753
1744
self._inventory_is_modified = False
1754
result = self._deserialize(self._transport.get('inventory'))
1745
result = self._deserialize(self._control_files.get('inventory'))
1755
1746
self._set_inventory(result, dirty=False)
1757
1748
@needs_tree_write_lock
1758
1749
def set_last_revision(self, new_revision):
1759
1750
"""Change the last revision in the working tree."""
1751
new_revision = osutils.safe_revision_id(new_revision)
1760
1752
if self._change_last_revision(new_revision):
1761
1753
self._cache_basis_inventory(new_revision)
1779
1771
def _write_basis_inventory(self, xml):
1780
1772
"""Write the basis inventory XML to the basis-inventory file"""
1773
assert isinstance(xml, str), 'serialised xml must be bytestring.'
1781
1774
path = self._basis_inventory_name()
1782
1775
sio = StringIO(xml)
1783
self._transport.put_file(path, sio,
1784
mode=self._control_files._file_mode)
1776
self._control_files.put(path, sio)
1786
1778
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1787
1779
"""Create the text that will be saved in basis-inventory"""
1788
inventory.revision_id = revision_id
1780
# TODO: jam 20070209 This should be redundant, as the revision_id
1781
# as all callers should have already converted the revision_id to
1783
inventory.revision_id = osutils.safe_revision_id(revision_id)
1789
1784
return xml7.serializer_v7.write_inventory_to_string(inventory)
1791
1786
def _cache_basis_inventory(self, new_revision):
1818
1813
def read_basis_inventory(self):
1819
1814
"""Read the cached basis inventory."""
1820
1815
path = self._basis_inventory_name()
1821
return self._transport.get_bytes(path)
1816
return self._control_files.get(path).read()
1823
1818
@needs_read_lock
1824
1819
def read_working_inventory(self):
1834
1829
if self._inventory_is_modified:
1835
1830
raise errors.InventoryModified(self)
1836
result = self._deserialize(self._transport.get('inventory'))
1831
result = self._deserialize(self._control_files.get('inventory'))
1837
1832
self._set_inventory(result, dirty=False)
1859
1854
# Recurse directory and add all files
1860
1855
# so we can check if they have changed.
1861
1856
for parent_info, file_infos in\
1862
self.walkdirs(directory):
1863
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1857
osutils.walkdirs(self.abspath(directory),
1859
for relpath, basename, kind, lstat, abspath in file_infos:
1864
1860
# Is it versioned or ignored?
1865
1861
if self.path2id(relpath) or self.is_ignored(relpath):
1866
1862
# Add nested content for deletion.
1891
1888
has_changed_files = len(unknown_nested_files) > 0
1892
1889
if not has_changed_files:
1893
1890
for (file_id, path, content_change, versioned, parent_id, name,
1894
kind, executable) in self.iter_changes(self.basis_tree(),
1891
kind, executable) in self._iter_changes(self.basis_tree(),
1895
1892
include_unchanged=True, require_versioned=False,
1896
1893
want_unversioned=True, specific_files=files):
1897
if versioned == (False, False):
1898
# The record is unknown ...
1899
if not self.is_ignored(path[1]):
1900
# ... but not ignored
1901
has_changed_files = True
1903
elif content_change and (kind[1] is not None):
1904
# Versioned and changed, but not deleted
1894
# Check if it's an unknown (but not ignored) OR
1895
# changed (but not deleted) :
1896
if not self.is_ignored(path[1]) and (
1897
versioned == (False, False) or
1898
content_change and kind[1] != None):
1905
1899
has_changed_files = True
1958
1952
self.apply_inventory_delta(inv_delta)
1960
1954
@needs_tree_write_lock
1961
def revert(self, filenames=None, old_tree=None, backups=True,
1955
def revert(self, filenames, old_tree=None, backups=True,
1962
1956
pb=DummyProgress(), report_changes=False):
1963
1957
from bzrlib.conflicts import resolve
1966
symbol_versioning.warn('Using [] to revert all files is deprecated'
1967
' as of bzr 0.91. Please use None (the default) instead.',
1968
DeprecationWarning, stacklevel=2)
1969
1958
if old_tree is None:
1970
basis_tree = self.basis_tree()
1971
basis_tree.lock_read()
1972
old_tree = basis_tree
1959
old_tree = self.basis_tree()
1960
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1962
if not len(filenames):
1963
self.set_parent_ids(self.get_parent_ids()[:1])
1976
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1978
if filenames is None and len(self.get_parent_ids()) > 1:
1980
last_revision = self.last_revision()
1981
if last_revision != NULL_REVISION:
1982
if basis_tree is None:
1983
basis_tree = self.basis_tree()
1984
basis_tree.lock_read()
1985
parent_trees.append((last_revision, basis_tree))
1986
self.set_parent_trees(parent_trees)
1989
resolve(self, filenames, ignore_misses=True, recursive=True)
1991
if basis_tree is not None:
1966
resolve(self, filenames, ignore_misses=True)
1993
1967
return conflicts
1995
1969
def revision_tree(self, revision_id):
2046
2020
"""Set the root id for this tree."""
2047
2021
# for compatability
2048
2022
if file_id is None:
2050
'WorkingTree.set_root_id with fileid=None')
2051
file_id = osutils.safe_file_id(file_id)
2023
symbol_versioning.warn(symbol_versioning.zero_twelve
2024
% 'WorkingTree.set_root_id with fileid=None',
2029
file_id = osutils.safe_file_id(file_id)
2052
2030
self._set_root_id(file_id)
2054
2032
def _set_root_id(self, file_id):
2089
2067
raise NotImplementedError(self.unlock)
2091
def update(self, change_reporter=None, possible_transports=None):
2069
def update(self, change_reporter=None):
2092
2070
"""Update a working tree along its branch.
2094
2072
This will update the branch if its bound too, which means we have
2305
2283
current_inv = None
2306
2284
inv_finished = True
2307
2285
while not inv_finished or not disk_finished:
2309
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2310
cur_disk_dir_content) = current_disk
2312
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2313
cur_disk_dir_content) = ((None, None), None)
2314
2286
if not disk_finished:
2315
2287
# strip out .bzr dirs
2316
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2317
len(cur_disk_dir_content) > 0):
2318
# osutils.walkdirs can be made nicer -
2288
if current_disk[0][1][top_strip_len:] == '':
2289
# osutils.walkdirs can be made nicer -
2319
2290
# yield the path-from-prefix rather than the pathjoined
2321
bzrdir_loc = bisect_left(cur_disk_dir_content,
2323
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2292
bzrdir_loc = bisect_left(current_disk[1], ('.bzr', '.bzr'))
2293
if current_disk[1][bzrdir_loc][0] == '.bzr':
2324
2294
# we dont yield the contents of, or, .bzr itself.
2325
del cur_disk_dir_content[bzrdir_loc]
2295
del current_disk[1][bzrdir_loc]
2326
2296
if inv_finished:
2327
2297
# everything is unknown
2330
2300
# everything is missing
2333
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2303
direction = cmp(current_inv[0][0], current_disk[0][0])
2334
2304
if direction > 0:
2335
2305
# disk is before inventory - unknown
2336
2306
dirblock = [(relpath, basename, kind, stat, None, None) for
2337
relpath, basename, kind, stat, top_path in
2338
cur_disk_dir_content]
2339
yield (cur_disk_dir_relpath, None), dirblock
2307
relpath, basename, kind, stat, top_path in current_disk[1]]
2308
yield (current_disk[0][0], None), dirblock
2341
2310
current_disk = disk_iterator.next()
2342
2311
except StopIteration:
2344
2313
elif direction < 0:
2345
2314
# inventory is before disk - missing.
2346
2315
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2347
for relpath, basename, dkind, stat, fileid, kind in
2316
for relpath, basename, dkind, stat, fileid, kind in
2348
2317
current_inv[1]]
2349
2318
yield (current_inv[0][0], current_inv[0][1]), dirblock
2356
2325
# merge the inventory and disk data together
2358
2327
for relpath, subiterator in itertools.groupby(sorted(
2359
current_inv[1] + cur_disk_dir_content,
2360
key=operator.itemgetter(0)), operator.itemgetter(1)):
2328
current_inv[1] + current_disk[1], key=operator.itemgetter(0)), operator.itemgetter(1)):
2361
2329
path_elements = list(subiterator)
2362
2330
if len(path_elements) == 2:
2363
2331
inv_row, disk_row = path_elements
2417
2385
# FIXME: stash the node in pending
2418
2386
entry = inv[top_id]
2419
if entry.kind == 'directory':
2420
for name, child in entry.sorted_children():
2421
dirblock.append((relroot + name, name, child.kind, None,
2422
child.file_id, child.kind
2387
for name, child in entry.sorted_children():
2388
dirblock.append((relroot + name, name, child.kind, None,
2389
child.file_id, child.kind
2424
2391
yield (currentdir[0], entry.file_id), dirblock
2425
2392
# push the user specified dirs from dirblock
2426
2393
for dir in reversed(dirblock):
2459
2426
self.set_conflicts(un_resolved)
2460
2427
return un_resolved, resolved
2464
tree_basis = self.basis_tree()
2465
tree_basis.lock_read()
2467
repo_basis = self.branch.repository.revision_tree(
2468
self.last_revision())
2469
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2470
raise errors.BzrCheckError(
2471
"Mismatched basis inventory content.")
2476
2429
def _validate(self):
2477
2430
"""Validate internal structures.
2488
def _get_rules_searcher(self, default_searcher):
2489
"""See Tree._get_rules_searcher."""
2490
if self._rules_searcher is None:
2491
self._rules_searcher = super(WorkingTree,
2492
self)._get_rules_searcher(default_searcher)
2493
return self._rules_searcher
2496
2441
class WorkingTree2(WorkingTree):
2497
2442
"""This is the Format 2 working tree.
2557
2502
def _last_revision(self):
2558
2503
"""See Mutable.last_revision."""
2560
return self._transport.get_bytes('last-revision')
2505
return osutils.safe_revision_id(
2506
self._control_files.get('last-revision').read())
2561
2507
except errors.NoSuchFile:
2562
2508
return _mod_revision.NULL_REVISION
2565
2511
"""See WorkingTree._change_last_revision."""
2566
2512
if revision_id is None or revision_id == NULL_REVISION:
2568
self._transport.delete('last-revision')
2514
self._control_files._transport.delete('last-revision')
2569
2515
except errors.NoSuchFile:
2573
self._transport.put_bytes('last-revision', revision_id,
2574
mode=self._control_files._file_mode)
2519
self._control_files.put_bytes('last-revision', revision_id)
2577
2522
@needs_tree_write_lock
2620
2565
return path[:-len(suffix)]
2568
@deprecated_function(zero_eight)
2569
def is_control_file(filename):
2570
"""See WorkingTree.is_control_filename(filename)."""
2571
## FIXME: better check
2572
filename = normpath(filename)
2573
while filename != '':
2574
head, tail = os.path.split(filename)
2575
## mutter('check %r for control file' % ((head, tail),))
2578
if filename == head:
2623
2584
class WorkingTreeFormat(object):
2624
2585
"""An encapsulation of the initialization and open routines for a format.
2658
2619
except errors.NoSuchFile:
2659
2620
raise errors.NoWorkingTree(base=transport.base)
2660
2621
except KeyError:
2661
raise errors.UnknownFormatError(format=format_string,
2662
kind="working tree")
2622
raise errors.UnknownFormatError(format=format_string)
2664
2624
def __eq__(self, other):
2665
2625
return self.__class__ is other.__class__
2714
2675
"""See WorkingTreeFormat.get_format_description()."""
2715
2676
return "Working tree format 2"
2717
def _stub_initialize_on_transport(self, transport, file_mode):
2718
"""Workaround: create control files for a remote working tree.
2678
def stub_initialize_remote(self, control_files):
2679
"""As a special workaround create critical control files for a remote working tree
2720
2681
This ensures that it can later be updated and dealt with locally,
2721
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2682
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2722
2683
no working tree. (See bug #43064).
2724
2685
sio = StringIO()
2725
2686
inv = Inventory()
2726
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2687
xml5.serializer_v5.write_inventory(inv, sio)
2728
transport.put_file('inventory', sio, file_mode)
2729
transport.put_bytes('pending-merges', '', file_mode)
2731
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2732
accelerator_tree=None, hardlink=False):
2689
control_files.put('inventory', sio)
2691
control_files.put_bytes('pending-merges', '')
2694
def initialize(self, a_bzrdir, revision_id=None):
2733
2695
"""See WorkingTreeFormat.initialize()."""
2734
2696
if not isinstance(a_bzrdir.transport, LocalTransport):
2735
2697
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2736
if from_branch is not None:
2737
branch = from_branch
2739
branch = a_bzrdir.open_branch()
2698
branch = a_bzrdir.open_branch()
2740
2699
if revision_id is None:
2741
2700
revision_id = _mod_revision.ensure_null(branch.last_revision())
2702
revision_id = osutils.safe_revision_id(revision_id)
2742
2703
branch.lock_write()
2744
2705
branch.generate_revision_history(revision_id)
2753
2714
_bzrdir=a_bzrdir)
2754
2715
basis_tree = branch.repository.revision_tree(revision_id)
2755
2716
if basis_tree.inventory.root is not None:
2756
wt.set_root_id(basis_tree.get_root_id())
2717
wt.set_root_id(basis_tree.inventory.root.file_id)
2757
2718
# set the parent list and cache the basis tree.
2758
2719
if _mod_revision.is_null(revision_id):
2759
2720
parent_trees = []
2821
2782
return LockableFiles(transport, self._lock_file_name,
2822
2783
self._lock_class)
2824
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2825
accelerator_tree=None, hardlink=False):
2785
def initialize(self, a_bzrdir, revision_id=None):
2826
2786
"""See WorkingTreeFormat.initialize().
2828
:param revision_id: if supplied, create a working tree at a different
2829
revision than the branch is at.
2830
:param accelerator_tree: A tree which can be used for retrieving file
2831
contents more quickly than the revision tree, i.e. a workingtree.
2832
The revision tree will be used for cases where accelerator_tree's
2833
content is different.
2834
:param hardlink: If true, hard-link files from accelerator_tree,
2788
revision_id allows creating a working tree at a different
2789
revision than the branch is at.
2837
2791
if not isinstance(a_bzrdir.transport, LocalTransport):
2838
2792
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2840
2794
control_files = self._open_control_files(a_bzrdir)
2841
2795
control_files.create_lock()
2842
2796
control_files.lock_write()
2843
transport.put_bytes('format', self.get_format_string(),
2844
mode=control_files._file_mode)
2845
if from_branch is not None:
2846
branch = from_branch
2848
branch = a_bzrdir.open_branch()
2797
control_files.put_utf8('format', self.get_format_string())
2798
branch = a_bzrdir.open_branch()
2849
2799
if revision_id is None:
2850
2800
revision_id = _mod_revision.ensure_null(branch.last_revision())
2802
revision_id = osutils.safe_revision_id(revision_id)
2851
2803
# WorkingTree3 can handle an inventory which has a unique root id.
2852
2804
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2853
2805
# those trees. And because there isn't a format bump inbetween, we
2866
2818
basis_tree = branch.repository.revision_tree(revision_id)
2867
2819
# only set an explicit root id if there is one to set.
2868
2820
if basis_tree.inventory.root is not None:
2869
wt.set_root_id(basis_tree.get_root_id())
2821
wt.set_root_id(basis_tree.inventory.root.file_id)
2870
2822
if revision_id == NULL_REVISION:
2871
2823
wt.set_parent_trees([])