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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
80
80
import bzrlib.branch
81
81
from bzrlib.transport import get_transport
83
from bzrlib.workingtree_4 import WorkingTreeFormat4
83
from bzrlib.workingtree_4 import (
86
90
from bzrlib import symbol_versioning
87
91
from bzrlib.decorators import needs_read_lock, needs_write_lock
88
92
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
89
from bzrlib.lockable_files import LockableFiles, TransportLock
93
from bzrlib.lockable_files import LockableFiles
90
94
from bzrlib.lockdir import LockDir
91
95
import bzrlib.mutabletree
92
96
from bzrlib.mutabletree import needs_tree_write_lock
97
from bzrlib import osutils
93
98
from bzrlib.osutils import (
123
126
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()
144
129
class TreeEntry(object):
145
130
"""An entry that implements the minimum interface used by commands.
147
This needs further inspection, it may be better to have
132
This needs further inspection, it may be better to have
148
133
InventoryEntries without ids - though that seems wrong. For now,
149
134
this is a parallel hierarchy to InventoryEntry, and needs to become
150
135
one of several things: decorates to that hierarchy, children of, or
237
224
self._control_files = self.branch.control_files
239
226
# assume all other formats have their own control files.
240
assert isinstance(_control_files, LockableFiles), \
241
"_control_files must be a LockableFiles, not %r" \
243
227
self._control_files = _control_files
228
self._transport = self._control_files._transport
244
229
# update the whole cache up front and write to disk if anything changed;
245
230
# in the future we might want to do this more selectively
246
231
# two possible ways offer themselves : in self._unlock, write the cache
270
256
# the Format factory and creation methods that are
271
257
# permitted to do this.
272
258
self._set_inventory(_inventory, dirty=False)
259
self._detect_case_handling()
260
self._rules_searcher = None
261
self.views = self._make_views()
263
def _detect_case_handling(self):
264
wt_trans = self.bzrdir.get_workingtree_transport(None)
266
wt_trans.stat("FoRMaT")
267
except errors.NoSuchFile:
268
self.case_sensitive = True
270
self.case_sensitive = False
272
self._setup_directory_is_tree_reference()
274
274
branch = property(
275
275
fget=lambda self: self._branch,
348
353
return WorkingTree.open(path, _unsupported=True)
356
def find_trees(location):
357
def list_current(transport):
358
return [d for d in transport.list_dir('') if d != '.bzr']
359
def evaluate(bzrdir):
361
tree = bzrdir.open_workingtree()
362
except errors.NoWorkingTree:
366
transport = get_transport(location)
367
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
368
list_current=list_current)
369
return [t for t in iterator if t is not None]
350
371
# should be deprecated - this is slow and in any case treating them as a
351
372
# container is (we now know) bad style -- mbp 20070302
352
373
## @deprecated_method(zero_fifteen)
390
417
# at this point ?
392
419
return self.branch.repository.revision_tree(revision_id)
393
except errors.RevisionNotPresent:
420
except (errors.RevisionNotPresent, errors.NoSuchRevision):
394
421
# the basis tree *may* be a ghost or a low level error may have
395
# occured. If the revision is present, its a problem, if its not
422
# occurred. If the revision is present, its a problem, if its not
397
424
if self.branch.repository.has_revision(revision_id):
399
426
# the basis tree is a ghost so return an empty tree.
400
return self.branch.repository.revision_tree(None)
427
return self.branch.repository.revision_tree(
428
_mod_revision.NULL_REVISION)
402
430
def _cleanup(self):
403
431
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)
443
433
def relpath(self, path):
444
434
"""Return the local path portion from a given path.
446
The path may be absolute or relative. If its a relative path it is
436
The path may be absolute or relative. If its a relative path it is
447
437
interpreted relative to the python current working directory.
449
439
return osutils.relpath(self.basedir, path)
451
441
def has_filename(self, filename):
452
442
return osutils.lexists(self.abspath(filename))
454
def get_file(self, file_id):
455
file_id = osutils.safe_file_id(file_id)
456
return self.get_file_byname(self.id2path(file_id))
458
def get_file_text(self, file_id):
459
file_id = osutils.safe_file_id(file_id)
460
return self.get_file(file_id).read()
462
def get_file_byname(self, filename):
463
return file(self.abspath(filename), 'rb')
444
def get_file(self, file_id, path=None, filtered=True):
445
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
447
def get_file_with_stat(self, file_id, path=None, filtered=True,
449
"""See MutableTree.get_file_with_stat."""
451
path = self.id2path(file_id)
452
file_obj = self.get_file_byname(path, filtered=False)
453
stat_value = _fstat(file_obj.fileno())
454
if self.supports_content_filtering() and filtered:
455
filters = self._content_filter_stack(path)
456
file_obj = filtered_input_file(file_obj, filters)
457
return (file_obj, stat_value)
459
def get_file_text(self, file_id, path=None, filtered=True):
460
return self.get_file(file_id, path=path, filtered=filtered).read()
462
def get_file_byname(self, filename, filtered=True):
463
path = self.abspath(filename)
465
if self.supports_content_filtering() and filtered:
466
filters = self._content_filter_stack(filename)
467
return filtered_input_file(f, filters)
471
def get_file_lines(self, file_id, path=None, filtered=True):
472
"""See Tree.get_file_lines()"""
473
file = self.get_file(file_id, path, filtered=filtered)
475
return file.readlines()
466
480
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
473
487
incorrectly attributed to CURRENT_REVISION (but after committing, the
474
488
attribution will be correct).
476
file_id = osutils.safe_file_id(file_id)
477
490
basis = self.basis_tree()
478
491
basis.lock_read()
480
changes = self._iter_changes(basis, True, [self.id2path(file_id)],
493
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
481
494
require_versioned=True).next()
482
495
changed_content, kind = changes[2], changes[6]
483
496
if not changed_content:
532
545
def get_root_id(self):
533
546
"""Return the id of this trees root"""
534
547
return self._inventory.root.file_id
536
549
def _get_store_filename(self, file_id):
537
550
## XXX: badly named; this is not in the store at all
538
file_id = osutils.safe_file_id(file_id)
539
551
return self.abspath(self.id2path(file_id))
542
554
def clone(self, to_bzrdir, revision_id=None):
543
555
"""Duplicate this working tree into to_bzr, including all state.
545
557
Specifically modified files are kept as modified, but
546
558
ignored and unknown files are discarded.
548
560
If you want to make a new line of development, see bzrdir.sprout()
551
If not None, the cloned tree will have its last revision set to
552
revision, and and difference between the source trees last revision
563
If not None, the cloned tree will have its last revision set to
564
revision, and difference between the source trees last revision
553
565
and this one merged in.
555
567
# assumes the target bzr dir format is compatible.
556
result = self._format.initialize(to_bzrdir)
568
result = to_bzrdir.create_workingtree()
557
569
self.copy_content_into(result, revision_id)
591
600
__contains__ = has_id
593
602
def get_file_size(self, file_id):
594
file_id = osutils.safe_file_id(file_id)
595
return os.path.getsize(self.id2abspath(file_id))
603
"""See Tree.get_file_size"""
605
return os.path.getsize(self.id2abspath(file_id))
607
if e.errno != errno.ENOENT:
598
613
def get_file_sha1(self, file_id, path=None, stat_value=None):
599
file_id = osutils.safe_file_id(file_id)
601
615
path = self._inventory.id2path(file_id)
602
616
return self._hashcache.get_sha1(path, stat_value)
604
618
def get_file_mtime(self, file_id, path=None):
605
file_id = osutils.safe_file_id(file_id)
607
620
path = self.inventory.id2path(file_id)
608
621
return os.lstat(self.abspath(path)).st_mtime
623
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
624
file_id = self.path2id(path)
625
return self._inventory[file_id].executable
627
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
628
mode = stat_result.st_mode
629
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
610
631
if not supports_executable():
611
632
def is_executable(self, file_id, path=None):
612
file_id = osutils.safe_file_id(file_id)
613
633
return self._inventory[file_id].executable
635
_is_executable_from_path_and_stat = \
636
_is_executable_from_path_and_stat_from_basis
615
638
def is_executable(self, file_id, path=None):
617
file_id = osutils.safe_file_id(file_id)
618
640
path = self.id2path(file_id)
619
641
mode = os.lstat(self.abspath(path)).st_mode
620
642
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
644
_is_executable_from_path_and_stat = \
645
_is_executable_from_path_and_stat_from_stat
622
647
@needs_tree_write_lock
623
648
def _add(self, files, ids, kinds):
624
649
"""See MutableTree._add."""
625
650
# TODO: Re-adding a file that is removed in the working copy
626
651
# should probably put it back with the previous ID.
627
# the read and write working inventory should not occur in this
652
# the read and write working inventory should not occur in this
628
653
# function - they should be part of lock_write and unlock.
629
654
inv = self.inventory
630
655
for f, file_id, kind in zip(files, ids, kinds):
631
assert kind is not None
632
656
if file_id is None:
633
657
inv.add_path(f, kind=kind)
635
file_id = osutils.safe_file_id(file_id)
636
659
inv.add_path(f, kind=kind, file_id=file_id)
637
660
self._inventory_is_modified = True
701
724
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
703
@deprecated_method(zero_eleven)
705
def pending_merges(self):
706
"""Return a list of pending merges.
708
These are revisions that have been merged into the working
709
directory but not yet committed.
711
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
712
instead - which is available on all tree objects.
714
return self.get_parent_ids()[1:]
726
def path_content_summary(self, path, _lstat=os.lstat,
727
_mapper=osutils.file_kind_from_stat_mode):
728
"""See Tree.path_content_summary."""
729
abspath = self.abspath(path)
731
stat_result = _lstat(abspath)
733
if getattr(e, 'errno', None) == errno.ENOENT:
735
return ('missing', None, None, None)
736
# propagate other errors
738
kind = _mapper(stat_result.st_mode)
740
size = stat_result.st_size
741
# try for a stat cache lookup
742
executable = self._is_executable_from_path_and_stat(path, stat_result)
743
return (kind, size, executable, self._sha_from_stat(
745
elif kind == 'directory':
746
# perhaps it looks like a plain directory, but it's really a
748
if self._directory_is_tree_reference(path):
749
kind = 'tree-reference'
750
return kind, None, None, None
751
elif kind == 'symlink':
752
target = osutils.readlink(abspath)
753
return ('symlink', None, None, target)
755
return (kind, None, None, None)
716
757
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
717
758
"""Common ghost checking functionality from set_parent_*.
728
769
def _set_merges_from_parent_ids(self, parent_ids):
729
770
merges = parent_ids[1:]
730
self._control_files.put_bytes('pending-merges', '\n'.join(merges))
771
self._transport.put_bytes('pending-merges', '\n'.join(merges),
772
mode=self.bzrdir._get_file_mode())
774
def _filter_parent_ids_by_ancestry(self, revision_ids):
775
"""Check that all merged revisions are proper 'heads'.
777
This will always return the first revision_id, and any merged revisions
780
if len(revision_ids) == 0:
782
graph = self.branch.repository.get_graph()
783
heads = graph.heads(revision_ids)
784
new_revision_ids = revision_ids[:1]
785
for revision_id in revision_ids[1:]:
786
if revision_id in heads and revision_id not in new_revision_ids:
787
new_revision_ids.append(revision_id)
788
if new_revision_ids != revision_ids:
789
trace.mutter('requested to set revision_ids = %s,'
790
' but filtered to %s', revision_ids, new_revision_ids)
791
return new_revision_ids
732
793
@needs_tree_write_lock
733
794
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
734
795
"""Set the parent ids to revision_ids.
736
797
See also set_parent_trees. This api will try to retrieve the tree data
737
798
for each element of revision_ids from the trees repository. If you have
738
799
tree data already available, it is more efficient to use
742
803
:param revision_ids: The revision_ids to set as the parent ids of this
743
804
working tree. Any of these may be ghosts.
745
revision_ids = [osutils.safe_revision_id(r) for r in revision_ids]
746
806
self._check_parents_for_ghosts(revision_ids,
747
807
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
748
808
for revision_id in revision_ids:
749
809
_mod_revision.check_not_reserved_id(revision_id)
811
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
751
813
if len(revision_ids) > 0:
752
814
self.set_last_revision(revision_ids[0])
758
820
@needs_tree_write_lock
759
821
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
760
822
"""See MutableTree.set_parent_trees."""
761
parent_ids = [osutils.safe_revision_id(rev) for (rev, tree) in parents_list]
823
parent_ids = [rev for (rev, tree) in parents_list]
762
824
for revision_id in parent_ids:
763
825
_mod_revision.check_not_reserved_id(revision_id)
765
827
self._check_parents_for_ghosts(parent_ids,
766
828
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
830
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
768
832
if len(parent_ids) == 0:
769
833
leftmost_parent_id = _mod_revision.NULL_REVISION
770
834
leftmost_parent_tree = None
797
861
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
798
862
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
864
def _sha_from_stat(self, path, stat_result):
865
"""Get a sha digest from the tree's stat cache.
867
The default implementation assumes no stat cache is present.
869
:param path: The path.
870
:param stat_result: The stat result being looked up.
800
874
def _put_rio(self, filename, stanzas, header):
801
875
self._must_be_locked()
802
876
my_file = rio_file(stanzas, header)
803
self._control_files.put(filename, my_file)
877
self._transport.put_file(filename, my_file,
878
mode=self.bzrdir._get_file_mode())
805
880
@needs_write_lock # because merge pulls data into the branch.
806
881
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
867
940
still in the working inventory and have that text hash.
870
hashfile = self._control_files.get('merge-hashes')
943
hashfile = self._transport.get('merge-hashes')
871
944
except errors.NoSuchFile:
875
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
949
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
950
raise errors.MergeModifiedFormatError()
951
except StopIteration:
876
952
raise errors.MergeModifiedFormatError()
877
except StopIteration:
878
raise errors.MergeModifiedFormatError()
879
for s in RioReader(hashfile):
880
# RioReader reads in Unicode, so convert file_ids back to utf8
881
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
882
if file_id not in self.inventory:
884
text_hash = s.get("hash")
885
if text_hash == self.get_file_sha1(file_id):
886
merge_hashes[file_id] = text_hash
953
for s in RioReader(hashfile):
954
# RioReader reads in Unicode, so convert file_ids back to utf8
955
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
956
if file_id not in self.inventory:
958
text_hash = s.get("hash")
959
if text_hash == self.get_file_sha1(file_id):
960
merge_hashes[file_id] = text_hash
889
965
@needs_write_lock
890
966
def mkdir(self, path, file_id=None):
941
1018
other_tree.unlock()
942
1019
other_tree.bzrdir.retire_bzrdir()
1021
def _setup_directory_is_tree_reference(self):
1022
if self._branch.repository._format.supports_tree_reference:
1023
self._directory_is_tree_reference = \
1024
self._directory_may_be_tree_reference
1026
self._directory_is_tree_reference = \
1027
self._directory_is_never_tree_reference
1029
def _directory_is_never_tree_reference(self, relpath):
1032
def _directory_may_be_tree_reference(self, relpath):
1033
# as a special case, if a directory contains control files then
1034
# it's a tree reference, except that the root of the tree is not
1035
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1036
# TODO: We could ask all the control formats whether they
1037
# recognize this directory, but at the moment there's no cheap api
1038
# to do that. Since we probably can only nest bzr checkouts and
1039
# they always use this name it's ok for now. -- mbp 20060306
1041
# FIXME: There is an unhandled case here of a subdirectory
1042
# containing .bzr but not a branch; that will probably blow up
1043
# when you try to commit it. It might happen if there is a
1044
# checkout in a subdirectory. This can be avoided by not adding
944
1047
@needs_tree_write_lock
945
1048
def extract(self, file_id, format=None):
946
1049
"""Extract a subtree from this tree.
948
1051
A new branch will be created, relative to the path for this tree.
955
1058
transport = transport.clone(name)
956
1059
transport.ensure_base()
957
1060
return transport
959
1062
sub_path = self.id2path(file_id)
960
1063
branch_transport = mkdirs(sub_path)
961
1064
if format is None:
962
format = bzrdir.format_registry.make_bzrdir('dirstate-with-subtree')
1065
format = self.bzrdir.cloning_metadir()
963
1066
branch_transport.ensure_base()
964
1067
branch_bzrdir = format.initialize_on_transport(branch_transport)
966
1069
repo = branch_bzrdir.find_repository()
967
1070
except errors.NoRepositoryPresent:
968
1071
repo = branch_bzrdir.create_repository()
969
assert repo.supports_rich_root()
971
if not repo.supports_rich_root():
972
raise errors.RootNotRich()
1072
if not repo.supports_rich_root():
1073
raise errors.RootNotRich()
973
1074
new_branch = branch_bzrdir.create_branch()
974
1075
new_branch.pull(self.branch)
975
1076
for parent_id in self.get_parent_ids():
1425
1532
:raises: NoSuchId if any fileid is not currently versioned.
1427
1534
for file_id in file_ids:
1428
file_id = osutils.safe_file_id(file_id)
1535
if file_id not in self._inventory:
1536
raise errors.NoSuchId(self, file_id)
1537
for file_id in file_ids:
1429
1538
if self._inventory.has_id(file_id):
1430
1539
self._inventory.remove_recursive_id(file_id)
1432
raise errors.NoSuchId(self, file_id)
1433
1540
if len(file_ids):
1434
# in the future this should just set a dirty bit to wait for the
1541
# in the future this should just set a dirty bit to wait for the
1435
1542
# final unlock. However, until all methods of workingtree start
1436
# with the current in -memory inventory rather than triggering
1543
# with the current in -memory inventory rather than triggering
1437
1544
# a read, it is more complex - we need to teach read_inventory
1438
1545
# to know when to read, and when to not read first... and possibly
1439
1546
# to save first when the in memory one may be corrupted.
1440
1547
# so for now, we just only write it if it is indeed dirty.
1441
1548
# - RBC 20060907
1442
1549
self._write_inventory(self._inventory)
1444
@deprecated_method(zero_eight)
1445
def iter_conflicts(self):
1446
"""List all files in the tree that have text or content conflicts.
1447
DEPRECATED. Use conflicts instead."""
1448
return self._iter_conflicts()
1450
1551
def _iter_conflicts(self):
1451
1552
conflicted = set()
1468
1569
pp.next_phase()
1469
1570
old_revision_info = self.branch.last_revision_info()
1470
1571
basis_tree = self.basis_tree()
1471
count = self.branch.pull(source, overwrite, stop_revision)
1572
count = self.branch.pull(source, overwrite, stop_revision,
1573
possible_transports=possible_transports,
1472
1575
new_revision_info = self.branch.last_revision_info()
1473
1576
if new_revision_info != old_revision_info:
1474
1577
pp.next_phase()
1494
1597
# reuse the revisiontree we merged against to set the new
1496
1599
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1497
# we have to pull the merge trees out again, because
1498
# merge_inner has set the ids. - this corner is not yet
1600
# we have to pull the merge trees out again, because
1601
# merge_inner has set the ids. - this corner is not yet
1499
1602
# layered well enough to prevent double handling.
1500
1603
# XXX TODO: Fix the double handling: telling the tree about
1501
1604
# the already known parent data is wasteful.
1542
1644
for subf in os.listdir(dirabs):
1645
if self.bzrdir.is_control_filename(subf):
1545
1647
if subf not in dir_entry.children:
1546
subf_norm, can_access = osutils.normalized_filename(subf)
1650
can_access) = osutils.normalized_filename(subf)
1651
except UnicodeDecodeError:
1652
path_os_enc = path.encode(osutils._fs_enc)
1653
relpath = path_os_enc + '/' + subf
1654
raise errors.BadFilenameEncoding(relpath,
1547
1656
if subf_norm != subf and can_access:
1548
1657
if subf_norm not in dir_entry.children:
1549
1658
fl.append(subf_norm)
1551
1660
fl.append(subf)
1554
1663
for subf in fl:
1555
1664
subp = pathjoin(path, subf)
1691
1804
def _reset_data(self):
1692
1805
"""Reset transient data that cannot be revalidated."""
1693
1806
self._inventory_is_modified = False
1694
result = self._deserialize(self._control_files.get('inventory'))
1807
result = self._deserialize(self._transport.get('inventory'))
1695
1808
self._set_inventory(result, dirty=False)
1697
1810
@needs_tree_write_lock
1698
1811
def set_last_revision(self, new_revision):
1699
1812
"""Change the last revision in the working tree."""
1700
new_revision = osutils.safe_revision_id(new_revision)
1701
1813
if self._change_last_revision(new_revision):
1702
1814
self._cache_basis_inventory(new_revision)
1704
1816
def _change_last_revision(self, new_revision):
1705
1817
"""Template method part of set_last_revision to perform the change.
1707
1819
This is used to allow WorkingTree3 instances to not affect branch
1708
1820
when their last revision is set.
1720
1832
def _write_basis_inventory(self, xml):
1721
1833
"""Write the basis inventory XML to the basis-inventory file"""
1722
assert isinstance(xml, str), 'serialised xml must be bytestring.'
1723
1834
path = self._basis_inventory_name()
1724
1835
sio = StringIO(xml)
1725
self._control_files.put(path, sio)
1836
self._transport.put_file(path, sio,
1837
mode=self.bzrdir._get_file_mode())
1727
1839
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1728
1840
"""Create the text that will be saved in basis-inventory"""
1729
# TODO: jam 20070209 This should be redundant, as the revision_id
1730
# as all callers should have already converted the revision_id to
1732
inventory.revision_id = osutils.safe_revision_id(revision_id)
1841
inventory.revision_id = revision_id
1733
1842
return xml7.serializer_v7.write_inventory_to_string(inventory)
1735
1844
def _cache_basis_inventory(self, new_revision):
1738
1847
# as commit already has that ready-to-use [while the format is the
1739
1848
# same, that is].
1741
# this double handles the inventory - unpack and repack -
1850
# this double handles the inventory - unpack and repack -
1742
1851
# but is easier to understand. We can/should put a conditional
1743
1852
# in here based on whether the inventory is in the latest format
1744
1853
# - perhaps we should repack all inventories on a repository
1746
1855
# the fast path is to copy the raw xml from the repository. If the
1747
# xml contains 'revision_id="', then we assume the right
1856
# xml contains 'revision_id="', then we assume the right
1748
1857
# revision_id is set. We must check for this full string, because a
1749
1858
# root node id can legitimately look like 'revision_id' but cannot
1750
1859
# contain a '"'.
1751
1860
xml = self.branch.repository.get_inventory_xml(new_revision)
1752
1861
firstline = xml.split('\n', 1)[0]
1753
if (not 'revision_id="' in firstline or
1862
if (not 'revision_id="' in firstline or
1754
1863
'format="7"' not in firstline):
1755
1864
inv = self.branch.repository.deserialise_inventory(
1756
1865
new_revision, xml)
1762
1871
def read_basis_inventory(self):
1763
1872
"""Read the cached basis inventory."""
1764
1873
path = self._basis_inventory_name()
1765
return self._control_files.get(path).read()
1874
return self._transport.get_bytes(path)
1767
1876
@needs_read_lock
1768
1877
def read_working_inventory(self):
1769
1878
"""Read the working inventory.
1771
1880
:raises errors.InventoryModified: read_working_inventory will fail
1772
1881
when the current in memory inventory has been modified.
1774
# conceptually this should be an implementation detail of the tree.
1883
# conceptually this should be an implementation detail of the tree.
1775
1884
# XXX: Deprecate this.
1776
1885
# ElementTree does its own conversion from UTF-8, so open in
1778
1887
if self._inventory_is_modified:
1779
1888
raise errors.InventoryModified(self)
1780
result = self._deserialize(self._control_files.get('inventory'))
1889
result = self._deserialize(self._transport.get('inventory'))
1781
1890
self._set_inventory(result, dirty=False)
1791
1900
:force: Delete files and directories, even if they are changed and
1792
1901
even if the directories are not empty.
1794
## TODO: Normalize names
1796
1903
if isinstance(files, basestring):
1797
1904
files = [files]
1801
1908
new_files=set()
1802
unknown_files_in_directory=set()
1909
unknown_nested_files=set()
1804
1911
def recurse_directory_to_add_files(directory):
1805
# recurse directory and add all files
1912
# Recurse directory and add all files
1806
1913
# so we can check if they have changed.
1807
1914
for parent_info, file_infos in\
1808
osutils.walkdirs(self.abspath(directory),
1810
for relpath, basename, kind, lstat, abspath in file_infos:
1812
if self.path2id(relpath): #is it versioned?
1813
new_files.add(relpath)
1815
unknown_files_in_directory.add(
1816
(relpath, None, kind))
1915
self.walkdirs(directory):
1916
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1917
# Is it versioned or ignored?
1918
if self.path2id(relpath) or self.is_ignored(relpath):
1919
# Add nested content for deletion.
1920
new_files.add(relpath)
1922
# Files which are not versioned and not ignored
1923
# should be treated as unknown.
1924
unknown_nested_files.add((relpath, None, kind))
1818
1926
for filename in files:
1819
1927
# Get file name into canonical form.
1821
1929
filename = self.relpath(abspath)
1822
1930
if len(filename) > 0:
1823
1931
new_files.add(filename)
1824
if osutils.isdir(abspath):
1825
recurse_directory_to_add_files(filename)
1826
files = [f for f in new_files]
1932
recurse_directory_to_add_files(filename)
1934
files = list(new_files)
1828
1936
if len(files) == 0:
1829
1937
return # nothing to do
1831
1939
# Sort needed to first handle directory content before the directory
1832
1940
files.sort(reverse=True)
1942
# Bail out if we are going to delete files we shouldn't
1833
1943
if not keep_files and not force:
1834
has_changed_files = len(unknown_files_in_directory) > 0
1944
has_changed_files = len(unknown_nested_files) > 0
1835
1945
if not has_changed_files:
1836
1946
for (file_id, path, content_change, versioned, parent_id, name,
1837
kind, executable) in self._iter_changes(self.basis_tree(),
1947
kind, executable) in self.iter_changes(self.basis_tree(),
1838
1948
include_unchanged=True, require_versioned=False,
1839
1949
want_unversioned=True, specific_files=files):
1840
# check if it's unknown OR changed but not deleted:
1841
if (versioned == (False, False)
1842
or (content_change and kind[1] != None)):
1950
if versioned == (False, False):
1951
# The record is unknown ...
1952
if not self.is_ignored(path[1]):
1953
# ... but not ignored
1954
has_changed_files = True
1956
elif content_change and (kind[1] is not None):
1957
# Versioned and changed, but not deleted
1843
1958
has_changed_files = True
1846
1961
if has_changed_files:
1847
# make delta to show ALL applicable changes in error message.
1962
# Make delta show ALL applicable changes in error message.
1848
1963
tree_delta = self.changes_from(self.basis_tree(),
1964
require_versioned=False, want_unversioned=True,
1849
1965
specific_files=files)
1850
for unknown_file in unknown_files_in_directory:
1851
tree_delta.unversioned.extend((unknown_file,))
1966
for unknown_file in unknown_nested_files:
1967
if unknown_file not in tree_delta.unversioned:
1968
tree_delta.unversioned.extend((unknown_file,))
1852
1969
raise errors.BzrRemoveChangedFilesError(tree_delta)
1854
# do this before any modifications
1971
# Build inv_delta and delete files where applicable,
1972
# do this before any modifications to inventory.
1855
1973
for f in files:
1856
1974
fid = self.path2id(f)
1859
message="%s is not versioned." % (f,)
1977
message = "%s is not versioned." % (f,)
1862
1980
# having removed it, it must be either ignored or unknown
1866
1984
new_status = '?'
1867
1985
textui.show_status(new_status, self.kind(fid), f,
1868
1986
to_file=to_file)
1870
1988
inv_delta.append((f, None, fid, None))
1871
message="removed %s" % (f,)
1989
message = "removed %s" % (f,)
1873
1991
if not keep_files:
1874
1992
abs_path = self.abspath(f)
1875
1993
if osutils.lexists(abs_path):
1876
1994
if (osutils.isdir(abs_path) and
1877
1995
len(os.listdir(abs_path)) > 0):
1878
message="%s is not empty directory "\
1879
"and won't be deleted." % (f,)
1997
osutils.rmtree(abs_path)
1999
message = "%s is not an empty directory "\
2000
"and won't be deleted." % (f,)
1881
2002
osutils.delete_any(abs_path)
1882
message="deleted %s" % (f,)
2003
message = "deleted %s" % (f,)
1883
2004
elif message is not None:
1884
# only care if we haven't done anything yet.
1885
message="%s does not exist." % (f,)
2005
# Only care if we haven't done anything yet.
2006
message = "%s does not exist." % (f,)
1887
# print only one message (if any) per file.
2008
# Print only one message (if any) per file.
1888
2009
if message is not None:
1890
2011
self.apply_inventory_delta(inv_delta)
1892
2013
@needs_tree_write_lock
1893
def revert(self, filenames, old_tree=None, backups=True,
2014
def revert(self, filenames=None, old_tree=None, backups=True,
1894
2015
pb=DummyProgress(), report_changes=False):
1895
2016
from bzrlib.conflicts import resolve
2019
symbol_versioning.warn('Using [] to revert all files is deprecated'
2020
' as of bzr 0.91. Please use None (the default) instead.',
2021
DeprecationWarning, stacklevel=2)
1896
2022
if old_tree is None:
1897
old_tree = self.basis_tree()
1898
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1900
if not len(filenames):
1901
self.set_parent_ids(self.get_parent_ids()[:1])
2023
basis_tree = self.basis_tree()
2024
basis_tree.lock_read()
2025
old_tree = basis_tree
1904
resolve(self, filenames, ignore_misses=True)
2029
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
2031
if filenames is None and len(self.get_parent_ids()) > 1:
2033
last_revision = self.last_revision()
2034
if last_revision != NULL_REVISION:
2035
if basis_tree is None:
2036
basis_tree = self.basis_tree()
2037
basis_tree.lock_read()
2038
parent_trees.append((last_revision, basis_tree))
2039
self.set_parent_trees(parent_trees)
2042
resolve(self, filenames, ignore_misses=True, recursive=True)
2044
if basis_tree is not None:
1905
2046
return conflicts
1907
2048
def revision_tree(self, revision_id):
1956
2097
@needs_tree_write_lock
1957
2098
def set_root_id(self, file_id):
1958
2099
"""Set the root id for this tree."""
1960
2101
if file_id is None:
1961
symbol_versioning.warn(symbol_versioning.zero_twelve
1962
% 'WorkingTree.set_root_id with fileid=None',
1967
file_id = osutils.safe_file_id(file_id)
2103
'WorkingTree.set_root_id with fileid=None')
2104
file_id = osutils.safe_file_id(file_id)
1968
2105
self._set_root_id(file_id)
1970
2107
def _set_root_id(self, file_id):
1971
2108
"""Set the root id for this tree, in a format specific manner.
1973
:param file_id: The file id to assign to the root. It must not be
2110
:param file_id: The file id to assign to the root. It must not be
1974
2111
present in the current inventory or an error will occur. It must
1975
2112
not be None, but rather a valid file id.
1996
2133
def unlock(self):
1997
2134
"""See Branch.unlock.
1999
2136
WorkingTree locking just uses the Branch locking facilities.
2000
2137
This is current because all working trees have an embedded branch
2001
2138
within them. IF in the future, we were to make branch data shareable
2002
between multiple working trees, i.e. via shared storage, then we
2139
between multiple working trees, i.e. via shared storage, then we
2003
2140
would probably want to lock both the local tree, and the branch.
2005
2142
raise NotImplementedError(self.unlock)
2007
def update(self, change_reporter=None):
2144
def update(self, change_reporter=None, possible_transports=None):
2008
2145
"""Update a working tree along its branch.
2010
2147
This will update the branch if its bound too, which means we have
2088
2225
parent_trees = [(self.branch.last_revision(), to_tree)]
2089
2226
merges = self.get_parent_ids()[1:]
2090
2227
# Ideally we ask the tree for the trees here, that way the working
2091
# tree can decide whether to give us teh entire tree or give us a
2228
# tree can decide whether to give us the entire tree or give us a
2092
2229
# lazy initialised tree. dirstate for instance will have the trees
2093
2230
# in ram already, whereas a last-revision + basis-inventory tree
2094
2231
# will not, but also does not need them when setting parents.
2221
2358
current_inv = None
2222
2359
inv_finished = True
2223
2360
while not inv_finished or not disk_finished:
2362
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2363
cur_disk_dir_content) = current_disk
2365
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2366
cur_disk_dir_content) = ((None, None), None)
2224
2367
if not disk_finished:
2225
2368
# strip out .bzr dirs
2226
if current_disk[0][1][top_strip_len:] == '':
2227
# osutils.walkdirs can be made nicer -
2369
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2370
len(cur_disk_dir_content) > 0):
2371
# osutils.walkdirs can be made nicer -
2228
2372
# yield the path-from-prefix rather than the pathjoined
2230
bzrdir_loc = bisect_left(current_disk[1], ('.bzr', '.bzr'))
2231
if current_disk[1][bzrdir_loc][0] == '.bzr':
2374
bzrdir_loc = bisect_left(cur_disk_dir_content,
2376
if (bzrdir_loc < len(cur_disk_dir_content)
2377
and self.bzrdir.is_control_filename(
2378
cur_disk_dir_content[bzrdir_loc][0])):
2232
2379
# we dont yield the contents of, or, .bzr itself.
2233
del current_disk[1][bzrdir_loc]
2380
del cur_disk_dir_content[bzrdir_loc]
2234
2381
if inv_finished:
2235
2382
# everything is unknown
2238
2385
# everything is missing
2241
direction = cmp(current_inv[0][0], current_disk[0][0])
2388
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2242
2389
if direction > 0:
2243
2390
# disk is before inventory - unknown
2244
2391
dirblock = [(relpath, basename, kind, stat, None, None) for
2245
relpath, basename, kind, stat, top_path in current_disk[1]]
2246
yield (current_disk[0][0], None), dirblock
2392
relpath, basename, kind, stat, top_path in
2393
cur_disk_dir_content]
2394
yield (cur_disk_dir_relpath, None), dirblock
2248
2396
current_disk = disk_iterator.next()
2249
2397
except StopIteration:
2251
2399
elif direction < 0:
2252
2400
# inventory is before disk - missing.
2253
2401
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2254
for relpath, basename, dkind, stat, fileid, kind in
2402
for relpath, basename, dkind, stat, fileid, kind in
2255
2403
current_inv[1]]
2256
2404
yield (current_inv[0][0], current_inv[0][1]), dirblock
2263
2411
# merge the inventory and disk data together
2265
2413
for relpath, subiterator in itertools.groupby(sorted(
2266
current_inv[1] + current_disk[1], key=operator.itemgetter(0)), operator.itemgetter(1)):
2414
current_inv[1] + cur_disk_dir_content,
2415
key=operator.itemgetter(0)), operator.itemgetter(1)):
2267
2416
path_elements = list(subiterator)
2268
2417
if len(path_elements) == 2:
2269
2418
inv_row, disk_row = path_elements
2323
2472
# FIXME: stash the node in pending
2324
2473
entry = inv[top_id]
2325
for name, child in entry.sorted_children():
2326
dirblock.append((relroot + name, name, child.kind, None,
2327
child.file_id, child.kind
2474
if entry.kind == 'directory':
2475
for name, child in entry.sorted_children():
2476
dirblock.append((relroot + name, name, child.kind, None,
2477
child.file_id, child.kind
2329
2479
yield (currentdir[0], entry.file_id), dirblock
2330
2480
# push the user specified dirs from dirblock
2331
2481
for dir in reversed(dirblock):
2543
def _get_rules_searcher(self, default_searcher):
2544
"""See Tree._get_rules_searcher."""
2545
if self._rules_searcher is None:
2546
self._rules_searcher = super(WorkingTree,
2547
self)._get_rules_searcher(default_searcher)
2548
return self._rules_searcher
2550
def get_shelf_manager(self):
2551
"""Return the ShelfManager for this WorkingTree."""
2552
from bzrlib.shelf import ShelfManager
2553
return ShelfManager(self, self._transport)
2379
2556
class WorkingTree2(WorkingTree):
2380
2557
"""This is the Format 2 working tree.
2382
This was the first weave based working tree.
2559
This was the first weave based working tree.
2383
2560
- uses os locks for locking.
2384
2561
- uses the branch last-revision.
2440
2617
def _last_revision(self):
2441
2618
"""See Mutable.last_revision."""
2443
return osutils.safe_revision_id(
2444
self._control_files.get('last-revision').read())
2620
return self._transport.get_bytes('last-revision')
2445
2621
except errors.NoSuchFile:
2622
return _mod_revision.NULL_REVISION
2448
2624
def _change_last_revision(self, revision_id):
2449
2625
"""See WorkingTree._change_last_revision."""
2450
2626
if revision_id is None or revision_id == NULL_REVISION:
2452
self._control_files._transport.delete('last-revision')
2628
self._transport.delete('last-revision')
2453
2629
except errors.NoSuchFile:
2457
self._control_files.put_bytes('last-revision', revision_id)
2633
self._transport.put_bytes('last-revision', revision_id,
2634
mode=self.bzrdir._get_file_mode())
2460
2637
@needs_tree_write_lock
2461
2638
def set_conflicts(self, conflicts):
2462
self._put_rio('conflicts', conflicts.to_stanzas(),
2639
self._put_rio('conflicts', conflicts.to_stanzas(),
2463
2640
CONFLICT_HEADER_1)
2465
2642
@needs_tree_write_lock
2472
2649
@needs_read_lock
2473
2650
def conflicts(self):
2475
confile = self._control_files.get('conflicts')
2652
confile = self._transport.get('conflicts')
2476
2653
except errors.NoSuchFile:
2477
2654
return _mod_conflicts.ConflictList()
2479
if confile.next() != CONFLICT_HEADER_1 + '\n':
2657
if confile.next() != CONFLICT_HEADER_1 + '\n':
2658
raise errors.ConflictFormatError()
2659
except StopIteration:
2480
2660
raise errors.ConflictFormatError()
2481
except StopIteration:
2482
raise errors.ConflictFormatError()
2483
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2661
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2485
2665
def unlock(self):
2486
2666
# do non-implementation specific cleanup
2503
2683
return path[:-len(suffix)]
2506
@deprecated_function(zero_eight)
2507
def is_control_file(filename):
2508
"""See WorkingTree.is_control_filename(filename)."""
2509
## FIXME: better check
2510
filename = normpath(filename)
2511
while filename != '':
2512
head, tail = os.path.split(filename)
2513
## mutter('check %r for control file' % ((head, tail),))
2516
if filename == head:
2522
2686
class WorkingTreeFormat(object):
2523
2687
"""An encapsulation of the initialization and open routines for a format.
2527
2691
* a format string,
2528
2692
* an open routine.
2530
Formats are placed in an dict by their format string for reference
2694
Formats are placed in an dict by their format string for reference
2531
2695
during workingtree opening. Its not required that these be instances, they
2532
can be classes themselves with class methods - it simply depends on
2696
can be classes themselves with class methods - it simply depends on
2533
2697
whether state is needed for a given format or not.
2535
2699
Once a format is deprecated, just deprecate the initialize and open
2536
methods on the format class. Do not deprecate the object, as the
2700
methods on the format class. Do not deprecate the object, as the
2537
2701
object will be created every time regardless.
2582
2747
"""Is this format supported?
2584
2749
Supported formats can be initialized and opened.
2585
Unsupported formats may not support initialization or committing or
2750
Unsupported formats may not support initialization or committing or
2586
2751
some other features depending on the reason for not being supported.
2755
def supports_content_filtering(self):
2756
"""True if this format supports content filtering."""
2759
def supports_views(self):
2760
"""True if this format supports stored views."""
2591
2764
def register_format(klass, format):
2592
2765
klass._formats[format.get_format_string()] = format
2613
2785
"""See WorkingTreeFormat.get_format_description()."""
2614
2786
return "Working tree format 2"
2616
def stub_initialize_remote(self, control_files):
2617
"""As a special workaround create critical control files for a remote working tree
2788
def _stub_initialize_on_transport(self, transport, file_mode):
2789
"""Workaround: create control files for a remote working tree.
2619
2791
This ensures that it can later be updated and dealt with locally,
2620
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2792
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2621
2793
no working tree. (See bug #43064).
2623
2795
sio = StringIO()
2624
2796
inv = Inventory()
2625
xml5.serializer_v5.write_inventory(inv, sio)
2797
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2627
control_files.put('inventory', sio)
2629
control_files.put_bytes('pending-merges', '')
2632
def initialize(self, a_bzrdir, revision_id=None):
2799
transport.put_file('inventory', sio, file_mode)
2800
transport.put_bytes('pending-merges', '', file_mode)
2802
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2803
accelerator_tree=None, hardlink=False):
2633
2804
"""See WorkingTreeFormat.initialize()."""
2634
2805
if not isinstance(a_bzrdir.transport, LocalTransport):
2635
2806
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2636
branch = a_bzrdir.open_branch()
2807
if from_branch is not None:
2808
branch = from_branch
2810
branch = a_bzrdir.open_branch()
2637
2811
if revision_id is None:
2638
2812
revision_id = _mod_revision.ensure_null(branch.last_revision())
2640
revision_id = osutils.safe_revision_id(revision_id)
2641
2813
branch.lock_write()
2643
2815
branch.generate_revision_history(revision_id)
2718
2890
def _open_control_files(self, a_bzrdir):
2719
2891
transport = a_bzrdir.get_workingtree_transport(None)
2720
return LockableFiles(transport, self._lock_file_name,
2892
return LockableFiles(transport, self._lock_file_name,
2721
2893
self._lock_class)
2723
def initialize(self, a_bzrdir, revision_id=None):
2895
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2896
accelerator_tree=None, hardlink=False):
2724
2897
"""See WorkingTreeFormat.initialize().
2726
revision_id allows creating a working tree at a different
2727
revision than the branch is at.
2899
:param revision_id: if supplied, create a working tree at a different
2900
revision than the branch is at.
2901
:param accelerator_tree: A tree which can be used for retrieving file
2902
contents more quickly than the revision tree, i.e. a workingtree.
2903
The revision tree will be used for cases where accelerator_tree's
2904
content is different.
2905
:param hardlink: If true, hard-link files from accelerator_tree,
2729
2908
if not isinstance(a_bzrdir.transport, LocalTransport):
2730
2909
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2732
2911
control_files = self._open_control_files(a_bzrdir)
2733
2912
control_files.create_lock()
2734
2913
control_files.lock_write()
2735
control_files.put_utf8('format', self.get_format_string())
2736
branch = a_bzrdir.open_branch()
2914
transport.put_bytes('format', self.get_format_string(),
2915
mode=a_bzrdir._get_file_mode())
2916
if from_branch is not None:
2917
branch = from_branch
2919
branch = a_bzrdir.open_branch()
2737
2920
if revision_id is None:
2738
2921
revision_id = _mod_revision.ensure_null(branch.last_revision())
2740
revision_id = osutils.safe_revision_id(revision_id)
2741
2922
# WorkingTree3 can handle an inventory which has a unique root id.
2742
2923
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2743
2924
# those trees. And because there isn't a format bump inbetween, we