1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
17
"""WorkingTree object and friends.
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
23
new revision based on the workingtree and its inventory.
25
At the moment every WorkingTree has its own branch. Remote
26
WorkingTrees aren't supported.
28
To get a WorkingTree, call bzrdir.open_workingtree() or
29
WorkingTree.open(dir).
32
# TODO: Give the workingtree sole responsibility for the working inventory;
33
# remove the variable and references to it from the branch. This may require
34
# updating the commit code so as to update the inventory within the working
35
# copy, and making sure there's only one WorkingTree for any directory on disk.
36
# At the moment they may alias the inventory and have old copies of it in
37
# memory. (Now done? -- mbp 20060309)
39
from cStringIO import StringIO
43
from bzrlib.lazy_import import lazy_import
44
lazy_import(globals(), """
45
from bisect import bisect_left
59
conflicts as _mod_conflicts,
67
revision as _mod_revision,
80
from bzrlib.transport import get_transport
82
from bzrlib.workingtree_4 import WorkingTreeFormat4
85
from bzrlib import symbol_versioning
86
from bzrlib.decorators import needs_read_lock, needs_write_lock
87
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
88
from bzrlib.lockable_files import LockableFiles, TransportLock
89
from bzrlib.lockdir import LockDir
90
import bzrlib.mutabletree
91
from bzrlib.mutabletree import needs_tree_write_lock
92
from bzrlib import osutils
93
from bzrlib.osutils import (
105
from bzrlib.trace import mutter, note
106
from bzrlib.transport.local import LocalTransport
107
from bzrlib.progress import DummyProgress, ProgressPhase
108
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
109
from bzrlib.rio import RioReader, rio_file, Stanza
110
from bzrlib.symbol_versioning import (deprecated_passed,
113
DEPRECATED_PARAMETER,
120
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
121
CONFLICT_HEADER_1 = "BZR conflict list format 1"
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()
144
class TreeEntry(object):
145
"""An entry that implements the minimum interface used by commands.
147
This needs further inspection, it may be better to have
148
InventoryEntries without ids - though that seems wrong. For now,
149
this is a parallel hierarchy to InventoryEntry, and needs to become
150
one of several things: decorates to that hierarchy, children of, or
152
Another note is that these objects are currently only used when there is
153
no InventoryEntry available - i.e. for unversioned objects.
154
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
157
def __eq__(self, other):
158
# yes, this us ugly, TODO: best practice __eq__ style.
159
return (isinstance(other, TreeEntry)
160
and other.__class__ == self.__class__)
162
def kind_character(self):
166
class TreeDirectory(TreeEntry):
167
"""See TreeEntry. This is a directory in a working tree."""
169
def __eq__(self, other):
170
return (isinstance(other, TreeDirectory)
171
and other.__class__ == self.__class__)
173
def kind_character(self):
177
class TreeFile(TreeEntry):
178
"""See TreeEntry. This is a regular file in a working tree."""
180
def __eq__(self, other):
181
return (isinstance(other, TreeFile)
182
and other.__class__ == self.__class__)
184
def kind_character(self):
188
class TreeLink(TreeEntry):
189
"""See TreeEntry. This is a symlink in a working tree."""
191
def __eq__(self, other):
192
return (isinstance(other, TreeLink)
193
and other.__class__ == self.__class__)
195
def kind_character(self):
199
class WorkingTree(bzrlib.mutabletree.MutableTree):
200
"""Working copy tree.
202
The inventory is held in the `Branch` working-inventory, and the
203
files are in a directory on disk.
205
It is possible for a `WorkingTree` to have a filename which is
206
not listed in the Inventory and vice versa.
209
def __init__(self, basedir='.',
210
branch=DEPRECATED_PARAMETER,
216
"""Construct a WorkingTree instance. This is not a public API.
218
:param branch: A branch to override probing for the branch.
220
self._format = _format
221
self.bzrdir = _bzrdir
223
raise errors.BzrError("Please use bzrdir.open_workingtree or "
224
"WorkingTree.open() to obtain a WorkingTree.")
225
assert isinstance(basedir, basestring), \
226
"base directory %r is not a string" % basedir
227
basedir = safe_unicode(basedir)
228
mutter("opening working tree %r", basedir)
229
if deprecated_passed(branch):
230
self._branch = branch
232
self._branch = self.bzrdir.open_branch()
233
self.basedir = realpath(basedir)
234
# if branch is at our basedir and is a format 6 or less
235
if isinstance(self._format, WorkingTreeFormat2):
236
# share control object
237
self._control_files = self.branch.control_files
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" \
243
self._control_files = _control_files
244
# update the whole cache up front and write to disk if anything changed;
245
# in the future we might want to do this more selectively
246
# two possible ways offer themselves : in self._unlock, write the cache
247
# if needed, or, when the cache sees a change, append it to the hash
248
# cache file, and have the parser take the most recent entry for a
250
wt_trans = self.bzrdir.get_workingtree_transport(None)
251
cache_filename = wt_trans.local_abspath('stat-cache')
252
self._hashcache = hashcache.HashCache(basedir, cache_filename,
253
self._control_files._file_mode)
256
# is this scan needed ? it makes things kinda slow.
263
if _inventory is None:
264
# This will be acquired on lock_read() or lock_write()
265
self._inventory_is_modified = False
266
self._inventory = None
268
# the caller of __init__ has provided an inventory,
269
# we assume they know what they are doing - as its only
270
# the Format factory and creation methods that are
271
# permitted to do this.
272
self._set_inventory(_inventory, dirty=False)
273
self._detect_case_handling()
275
def _detect_case_handling(self):
276
wt_trans = self.bzrdir.get_workingtree_transport(None)
278
wt_trans.stat("FoRMaT")
279
except errors.NoSuchFile:
280
self.case_sensitive = True
282
self.case_sensitive = False
284
self._setup_directory_is_tree_reference()
287
fget=lambda self: self._branch,
288
doc="""The branch this WorkingTree is connected to.
290
This cannot be set - it is reflective of the actual disk structure
291
the working tree has been constructed from.
294
def break_lock(self):
295
"""Break a lock if one is present from another instance.
297
Uses the ui factory to ask for confirmation if the lock may be from
300
This will probe the repository for its lock as well.
302
self._control_files.break_lock()
303
self.branch.break_lock()
305
def requires_rich_root(self):
306
return self._format.requires_rich_root
308
def supports_tree_reference(self):
311
def _set_inventory(self, inv, dirty):
312
"""Set the internal cached inventory.
314
:param inv: The inventory to set.
315
:param dirty: A boolean indicating whether the inventory is the same
316
logical inventory as whats on disk. If True the inventory is not
317
the same and should be written to disk or data will be lost, if
318
False then the inventory is the same as that on disk and any
319
serialisation would be unneeded overhead.
321
assert inv.root is not None
322
self._inventory = inv
323
self._inventory_is_modified = dirty
326
def open(path=None, _unsupported=False):
327
"""Open an existing working tree at path.
331
path = os.path.getcwdu()
332
control = bzrdir.BzrDir.open(path, _unsupported)
333
return control.open_workingtree(_unsupported)
336
def open_containing(path=None):
337
"""Open an existing working tree which has its root about path.
339
This probes for a working tree at path and searches upwards from there.
341
Basically we keep looking up until we find the control directory or
342
run into /. If there isn't one, raises NotBranchError.
343
TODO: give this a new exception.
344
If there is one, it is returned, along with the unused portion of path.
346
:return: The WorkingTree that contains 'path', and the rest of path
349
path = osutils.getcwd()
350
control, relpath = bzrdir.BzrDir.open_containing(path)
352
return control.open_workingtree(), relpath
355
def open_downlevel(path=None):
356
"""Open an unsupported working tree.
358
Only intended for advanced situations like upgrading part of a bzrdir.
360
return WorkingTree.open(path, _unsupported=True)
363
def find_trees(location):
364
def list_current(transport):
365
return [d for d in transport.list_dir('') if d != '.bzr']
366
def evaluate(bzrdir):
368
tree = bzrdir.open_workingtree()
369
except errors.NoWorkingTree:
373
transport = get_transport(location)
374
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
375
list_current=list_current)
376
return [t for t in iterator if t is not None]
378
# should be deprecated - this is slow and in any case treating them as a
379
# container is (we now know) bad style -- mbp 20070302
380
## @deprecated_method(zero_fifteen)
382
"""Iterate through file_ids for this tree.
384
file_ids are in a WorkingTree if they are in the working inventory
385
and the working file exists.
387
inv = self._inventory
388
for path, ie in inv.iter_entries():
389
if osutils.lexists(self.abspath(path)):
392
def all_file_ids(self):
393
"""See Tree.iter_all_file_ids"""
394
return set(self.inventory)
397
return "<%s of %s>" % (self.__class__.__name__,
398
getattr(self, 'basedir', None))
400
def abspath(self, filename):
401
return pathjoin(self.basedir, filename)
403
def basis_tree(self):
404
"""Return RevisionTree for the current last revision.
406
If the left most parent is a ghost then the returned tree will be an
407
empty tree - one obtained by calling repository.revision_tree(None).
410
revision_id = self.get_parent_ids()[0]
412
# no parents, return an empty revision tree.
413
# in the future this should return the tree for
414
# 'empty:' - the implicit root empty tree.
415
return self.branch.repository.revision_tree(None)
417
return self.revision_tree(revision_id)
418
except errors.NoSuchRevision:
420
# No cached copy available, retrieve from the repository.
421
# FIXME? RBC 20060403 should we cache the inventory locally
424
return self.branch.repository.revision_tree(revision_id)
425
except errors.RevisionNotPresent:
426
# the basis tree *may* be a ghost or a low level error may have
427
# occured. If the revision is present, its a problem, if its not
429
if self.branch.repository.has_revision(revision_id):
431
# the basis tree is a ghost so return an empty tree.
432
return self.branch.repository.revision_tree(None)
435
self._flush_ignore_list_cache()
438
@deprecated_method(zero_eight)
439
def create(branch, directory):
440
"""Create a workingtree for branch at directory.
442
If existing_directory already exists it must have a .bzr directory.
443
If it does not exist, it will be created.
445
This returns a new WorkingTree object for the new checkout.
447
TODO FIXME RBC 20060124 when we have checkout formats in place this
448
should accept an optional revisionid to checkout [and reject this if
449
checking out into the same dir as a pre-checkout-aware branch format.]
451
XXX: When BzrDir is present, these should be created through that
454
warnings.warn('delete WorkingTree.create', stacklevel=3)
455
transport = get_transport(directory)
456
if branch.bzrdir.root_transport.base == transport.base:
458
return branch.bzrdir.create_workingtree()
459
# different directory,
460
# create a branch reference
461
# and now a working tree.
462
raise NotImplementedError
465
@deprecated_method(zero_eight)
466
def create_standalone(directory):
467
"""Create a checkout and a branch and a repo at directory.
469
Directory must exist and be empty.
471
please use BzrDir.create_standalone_workingtree
473
return bzrdir.BzrDir.create_standalone_workingtree(directory)
475
def relpath(self, path):
476
"""Return the local path portion from a given path.
478
The path may be absolute or relative. If its a relative path it is
479
interpreted relative to the python current working directory.
481
return osutils.relpath(self.basedir, path)
483
def has_filename(self, filename):
484
return osutils.lexists(self.abspath(filename))
486
def get_file(self, file_id, path=None):
488
path = self.id2path(file_id)
489
return self.get_file_byname(path)
491
def get_file_text(self, file_id):
492
return self.get_file(file_id).read()
494
def get_file_byname(self, filename):
495
return file(self.abspath(filename), 'rb')
498
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
499
"""See Tree.annotate_iter
501
This implementation will use the basis tree implementation if possible.
502
Lines not in the basis are attributed to CURRENT_REVISION
504
If there are pending merges, lines added by those merges will be
505
incorrectly attributed to CURRENT_REVISION (but after committing, the
506
attribution will be correct).
508
basis = self.basis_tree()
511
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
512
require_versioned=True).next()
513
changed_content, kind = changes[2], changes[6]
514
if not changed_content:
515
return basis.annotate_iter(file_id)
519
if kind[0] != 'file':
522
old_lines = list(basis.annotate_iter(file_id))
524
for tree in self.branch.repository.revision_trees(
525
self.get_parent_ids()[1:]):
526
if file_id not in tree:
528
old.append(list(tree.annotate_iter(file_id)))
529
return annotate.reannotate(old, self.get_file(file_id).readlines(),
534
def _get_ancestors(self, default_revision):
535
ancestors = set([default_revision])
536
for parent_id in self.get_parent_ids():
537
ancestors.update(self.branch.repository.get_ancestry(
538
parent_id, topo_sorted=False))
541
def get_parent_ids(self):
542
"""See Tree.get_parent_ids.
544
This implementation reads the pending merges list and last_revision
545
value and uses that to decide what the parents list should be.
547
last_rev = _mod_revision.ensure_null(self._last_revision())
548
if _mod_revision.NULL_REVISION == last_rev:
553
merges_file = self._control_files.get('pending-merges')
554
except errors.NoSuchFile:
557
for l in merges_file.readlines():
558
revision_id = l.rstrip('\n')
559
parents.append(revision_id)
563
def get_root_id(self):
564
"""Return the id of this trees root"""
565
return self._inventory.root.file_id
567
def _get_store_filename(self, file_id):
568
## XXX: badly named; this is not in the store at all
569
return self.abspath(self.id2path(file_id))
572
def clone(self, to_bzrdir, revision_id=None):
573
"""Duplicate this working tree into to_bzr, including all state.
575
Specifically modified files are kept as modified, but
576
ignored and unknown files are discarded.
578
If you want to make a new line of development, see bzrdir.sprout()
581
If not None, the cloned tree will have its last revision set to
582
revision, and and difference between the source trees last revision
583
and this one merged in.
585
# assumes the target bzr dir format is compatible.
586
result = self._format.initialize(to_bzrdir)
587
self.copy_content_into(result, revision_id)
591
def copy_content_into(self, tree, revision_id=None):
592
"""Copy the current content and user files of this tree into tree."""
593
tree.set_root_id(self.get_root_id())
594
if revision_id is None:
595
merge.transform_tree(tree, self)
597
# TODO now merge from tree.last_revision to revision (to preserve
598
# user local changes)
599
merge.transform_tree(tree, self)
600
tree.set_parent_ids([revision_id])
602
def id2abspath(self, file_id):
603
return self.abspath(self.id2path(file_id))
605
def has_id(self, file_id):
606
# files that have been deleted are excluded
608
if not inv.has_id(file_id):
610
path = inv.id2path(file_id)
611
return osutils.lexists(self.abspath(path))
613
def has_or_had_id(self, file_id):
614
if file_id == self.inventory.root.file_id:
616
return self.inventory.has_id(file_id)
618
__contains__ = has_id
620
def get_file_size(self, file_id):
622
return os.path.getsize(self.id2abspath(file_id))
624
if e.errno != errno.ENOENT:
630
def get_file_sha1(self, file_id, path=None, stat_value=None):
632
path = self._inventory.id2path(file_id)
633
return self._hashcache.get_sha1(path, stat_value)
635
def get_file_mtime(self, file_id, path=None):
637
path = self.inventory.id2path(file_id)
638
return os.lstat(self.abspath(path)).st_mtime
640
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
641
file_id = self.path2id(path)
642
return self._inventory[file_id].executable
644
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
645
mode = stat_result.st_mode
646
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
648
if not supports_executable():
649
def is_executable(self, file_id, path=None):
650
return self._inventory[file_id].executable
652
_is_executable_from_path_and_stat = \
653
_is_executable_from_path_and_stat_from_basis
655
def is_executable(self, file_id, path=None):
657
path = self.id2path(file_id)
658
mode = os.lstat(self.abspath(path)).st_mode
659
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
661
_is_executable_from_path_and_stat = \
662
_is_executable_from_path_and_stat_from_stat
664
@needs_tree_write_lock
665
def _add(self, files, ids, kinds):
666
"""See MutableTree._add."""
667
# TODO: Re-adding a file that is removed in the working copy
668
# should probably put it back with the previous ID.
669
# the read and write working inventory should not occur in this
670
# function - they should be part of lock_write and unlock.
672
for f, file_id, kind in zip(files, ids, kinds):
673
assert kind is not None
675
inv.add_path(f, kind=kind)
677
inv.add_path(f, kind=kind, file_id=file_id)
678
self._inventory_is_modified = True
680
@needs_tree_write_lock
681
def _gather_kinds(self, files, kinds):
682
"""See MutableTree._gather_kinds."""
683
for pos, f in enumerate(files):
684
if kinds[pos] is None:
685
fullpath = normpath(self.abspath(f))
687
kinds[pos] = file_kind(fullpath)
689
if e.errno == errno.ENOENT:
690
raise errors.NoSuchFile(fullpath)
693
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
694
"""Add revision_id as a parent.
696
This is equivalent to retrieving the current list of parent ids
697
and setting the list to its value plus revision_id.
699
:param revision_id: The revision id to add to the parent list. It may
700
be a ghost revision as long as its not the first parent to be added,
701
or the allow_leftmost_as_ghost parameter is set True.
702
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
704
parents = self.get_parent_ids() + [revision_id]
705
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
706
or allow_leftmost_as_ghost)
708
@needs_tree_write_lock
709
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
710
"""Add revision_id, tree tuple as a parent.
712
This is equivalent to retrieving the current list of parent trees
713
and setting the list to its value plus parent_tuple. See also
714
add_parent_tree_id - if you only have a parent id available it will be
715
simpler to use that api. If you have the parent already available, using
716
this api is preferred.
718
:param parent_tuple: The (revision id, tree) to add to the parent list.
719
If the revision_id is a ghost, pass None for the tree.
720
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
722
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
723
if len(parent_ids) > 1:
724
# the leftmost may have already been a ghost, preserve that if it
726
allow_leftmost_as_ghost = True
727
self.set_parent_ids(parent_ids,
728
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
730
@needs_tree_write_lock
731
def add_pending_merge(self, *revision_ids):
732
# TODO: Perhaps should check at this point that the
733
# history of the revision is actually present?
734
parents = self.get_parent_ids()
736
for rev_id in revision_ids:
737
if rev_id in parents:
739
parents.append(rev_id)
742
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
744
def path_content_summary(self, path, _lstat=os.lstat,
745
_mapper=osutils.file_kind_from_stat_mode):
746
"""See Tree.path_content_summary."""
747
abspath = self.abspath(path)
749
stat_result = _lstat(abspath)
751
if getattr(e, 'errno', None) == errno.ENOENT:
753
return ('missing', None, None, None)
754
# propagate other errors
756
kind = _mapper(stat_result.st_mode)
758
size = stat_result.st_size
759
# try for a stat cache lookup
760
executable = self._is_executable_from_path_and_stat(path, stat_result)
761
return (kind, size, executable, self._sha_from_stat(
763
elif kind == 'directory':
764
# perhaps it looks like a plain directory, but it's really a
766
if self._directory_is_tree_reference(path):
767
kind = 'tree-reference'
768
return kind, None, None, None
769
elif kind == 'symlink':
770
return ('symlink', None, None, os.readlink(abspath))
772
return (kind, None, None, None)
774
@deprecated_method(zero_eleven)
776
def pending_merges(self):
777
"""Return a list of pending merges.
779
These are revisions that have been merged into the working
780
directory but not yet committed.
782
As of 0.11 this is deprecated. Please see WorkingTree.get_parent_ids()
783
instead - which is available on all tree objects.
785
return self.get_parent_ids()[1:]
787
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
788
"""Common ghost checking functionality from set_parent_*.
790
This checks that the left hand-parent exists if there are any
793
if len(revision_ids) > 0:
794
leftmost_id = revision_ids[0]
795
if (not allow_leftmost_as_ghost and not
796
self.branch.repository.has_revision(leftmost_id)):
797
raise errors.GhostRevisionUnusableHere(leftmost_id)
799
def _set_merges_from_parent_ids(self, parent_ids):
800
merges = parent_ids[1:]
801
self._control_files.put_bytes('pending-merges', '\n'.join(merges))
803
@needs_tree_write_lock
804
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
805
"""Set the parent ids to revision_ids.
807
See also set_parent_trees. This api will try to retrieve the tree data
808
for each element of revision_ids from the trees repository. If you have
809
tree data already available, it is more efficient to use
810
set_parent_trees rather than set_parent_ids. set_parent_ids is however
811
an easier API to use.
813
:param revision_ids: The revision_ids to set as the parent ids of this
814
working tree. Any of these may be ghosts.
816
self._check_parents_for_ghosts(revision_ids,
817
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
818
for revision_id in revision_ids:
819
_mod_revision.check_not_reserved_id(revision_id)
821
if len(revision_ids) > 0:
822
self.set_last_revision(revision_ids[0])
824
self.set_last_revision(_mod_revision.NULL_REVISION)
826
self._set_merges_from_parent_ids(revision_ids)
828
@needs_tree_write_lock
829
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
830
"""See MutableTree.set_parent_trees."""
831
parent_ids = [rev for (rev, tree) in parents_list]
832
for revision_id in parent_ids:
833
_mod_revision.check_not_reserved_id(revision_id)
835
self._check_parents_for_ghosts(parent_ids,
836
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
838
if len(parent_ids) == 0:
839
leftmost_parent_id = _mod_revision.NULL_REVISION
840
leftmost_parent_tree = None
842
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
844
if self._change_last_revision(leftmost_parent_id):
845
if leftmost_parent_tree is None:
846
# If we don't have a tree, fall back to reading the
847
# parent tree from the repository.
848
self._cache_basis_inventory(leftmost_parent_id)
850
inv = leftmost_parent_tree.inventory
851
xml = self._create_basis_xml_from_inventory(
852
leftmost_parent_id, inv)
853
self._write_basis_inventory(xml)
854
self._set_merges_from_parent_ids(parent_ids)
856
@needs_tree_write_lock
857
def set_pending_merges(self, rev_list):
858
parents = self.get_parent_ids()
859
leftmost = parents[:1]
860
new_parents = leftmost + rev_list
861
self.set_parent_ids(new_parents)
863
@needs_tree_write_lock
864
def set_merge_modified(self, modified_hashes):
866
for file_id, hash in modified_hashes.iteritems():
867
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
868
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
870
def _sha_from_stat(self, path, stat_result):
871
"""Get a sha digest from the tree's stat cache.
873
The default implementation assumes no stat cache is present.
875
:param path: The path.
876
:param stat_result: The stat result being looked up.
880
def _put_rio(self, filename, stanzas, header):
881
self._must_be_locked()
882
my_file = rio_file(stanzas, header)
883
self._control_files.put(filename, my_file)
885
@needs_write_lock # because merge pulls data into the branch.
886
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
888
"""Merge from a branch into this working tree.
890
:param branch: The branch to merge from.
891
:param to_revision: If non-None, the merge will merge to to_revision,
892
but not beyond it. to_revision does not need to be in the history
893
of the branch when it is supplied. If None, to_revision defaults to
894
branch.last_revision().
896
from bzrlib.merge import Merger, Merge3Merger
897
pb = bzrlib.ui.ui_factory.nested_progress_bar()
899
merger = Merger(self.branch, this_tree=self, pb=pb)
900
merger.pp = ProgressPhase("Merge phase", 5, pb)
901
merger.pp.next_phase()
902
# check that there are no
904
merger.check_basis(check_clean=True, require_commits=False)
905
if to_revision is None:
906
to_revision = _mod_revision.ensure_null(branch.last_revision())
907
merger.other_rev_id = to_revision
908
if _mod_revision.is_null(merger.other_rev_id):
909
raise errors.NoCommits(branch)
910
self.branch.fetch(branch, last_revision=merger.other_rev_id)
911
merger.other_basis = merger.other_rev_id
912
merger.other_tree = self.branch.repository.revision_tree(
914
merger.other_branch = branch
915
merger.pp.next_phase()
916
if from_revision is None:
919
merger.set_base_revision(from_revision, branch)
920
if merger.base_rev_id == merger.other_rev_id:
921
raise errors.PointlessMerge
922
merger.backup_files = False
923
if merge_type is None:
924
merger.merge_type = Merge3Merger
926
merger.merge_type = merge_type
927
merger.set_interesting_files(None)
928
merger.show_base = False
929
merger.reprocess = False
930
conflicts = merger.do_merge()
937
def merge_modified(self):
938
"""Return a dictionary of files modified by a merge.
940
The list is initialized by WorkingTree.set_merge_modified, which is
941
typically called after we make some automatic updates to the tree
944
This returns a map of file_id->sha1, containing only files which are
945
still in the working inventory and have that text hash.
948
hashfile = self._control_files.get('merge-hashes')
949
except errors.NoSuchFile:
953
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
954
raise errors.MergeModifiedFormatError()
955
except StopIteration:
956
raise errors.MergeModifiedFormatError()
957
for s in RioReader(hashfile):
958
# RioReader reads in Unicode, so convert file_ids back to utf8
959
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
960
if file_id not in self.inventory:
962
text_hash = s.get("hash")
963
if text_hash == self.get_file_sha1(file_id):
964
merge_hashes[file_id] = text_hash
968
def mkdir(self, path, file_id=None):
969
"""See MutableTree.mkdir()."""
971
file_id = generate_ids.gen_file_id(os.path.basename(path))
972
os.mkdir(self.abspath(path))
973
self.add(path, file_id, 'directory')
976
def get_symlink_target(self, file_id):
977
return os.readlink(self.id2abspath(file_id))
980
def subsume(self, other_tree):
981
def add_children(inventory, entry):
982
for child_entry in entry.children.values():
983
inventory._byid[child_entry.file_id] = child_entry
984
if child_entry.kind == 'directory':
985
add_children(inventory, child_entry)
986
if other_tree.get_root_id() == self.get_root_id():
987
raise errors.BadSubsumeSource(self, other_tree,
988
'Trees have the same root')
990
other_tree_path = self.relpath(other_tree.basedir)
991
except errors.PathNotChild:
992
raise errors.BadSubsumeSource(self, other_tree,
993
'Tree is not contained by the other')
994
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
995
if new_root_parent is None:
996
raise errors.BadSubsumeSource(self, other_tree,
997
'Parent directory is not versioned.')
998
# We need to ensure that the result of a fetch will have a
999
# versionedfile for the other_tree root, and only fetching into
1000
# RepositoryKnit2 guarantees that.
1001
if not self.branch.repository.supports_rich_root():
1002
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
1003
other_tree.lock_tree_write()
1005
new_parents = other_tree.get_parent_ids()
1006
other_root = other_tree.inventory.root
1007
other_root.parent_id = new_root_parent
1008
other_root.name = osutils.basename(other_tree_path)
1009
self.inventory.add(other_root)
1010
add_children(self.inventory, other_root)
1011
self._write_inventory(self.inventory)
1012
# normally we don't want to fetch whole repositories, but i think
1013
# here we really do want to consolidate the whole thing.
1014
for parent_id in other_tree.get_parent_ids():
1015
self.branch.fetch(other_tree.branch, parent_id)
1016
self.add_parent_tree_id(parent_id)
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
1047
@needs_tree_write_lock
1048
def extract(self, file_id, format=None):
1049
"""Extract a subtree from this tree.
1051
A new branch will be created, relative to the path for this tree.
1055
segments = osutils.splitpath(path)
1056
transport = self.branch.bzrdir.root_transport
1057
for name in segments:
1058
transport = transport.clone(name)
1059
transport.ensure_base()
1062
sub_path = self.id2path(file_id)
1063
branch_transport = mkdirs(sub_path)
1065
format = self.bzrdir.cloning_metadir()
1066
branch_transport.ensure_base()
1067
branch_bzrdir = format.initialize_on_transport(branch_transport)
1069
repo = branch_bzrdir.find_repository()
1070
except errors.NoRepositoryPresent:
1071
repo = branch_bzrdir.create_repository()
1072
if not repo.supports_rich_root():
1073
raise errors.RootNotRich()
1074
new_branch = branch_bzrdir.create_branch()
1075
new_branch.pull(self.branch)
1076
for parent_id in self.get_parent_ids():
1077
new_branch.fetch(self.branch, parent_id)
1078
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1079
if tree_transport.base != branch_transport.base:
1080
tree_bzrdir = format.initialize_on_transport(tree_transport)
1081
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1083
tree_bzrdir = branch_bzrdir
1084
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1085
wt.set_parent_ids(self.get_parent_ids())
1086
my_inv = self.inventory
1087
child_inv = Inventory(root_id=None)
1088
new_root = my_inv[file_id]
1089
my_inv.remove_recursive_id(file_id)
1090
new_root.parent_id = None
1091
child_inv.add(new_root)
1092
self._write_inventory(my_inv)
1093
wt._write_inventory(child_inv)
1096
def _serialize(self, inventory, out_file):
1097
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1100
def _deserialize(selt, in_file):
1101
return xml5.serializer_v5.read_inventory(in_file)
1104
"""Write the in memory inventory to disk."""
1105
# TODO: Maybe this should only write on dirty ?
1106
if self._control_files._lock_mode != 'w':
1107
raise errors.NotWriteLocked(self)
1109
self._serialize(self._inventory, sio)
1111
self._control_files.put('inventory', sio)
1112
self._inventory_is_modified = False
1114
def _kind(self, relpath):
1115
return osutils.file_kind(self.abspath(relpath))
1117
def list_files(self, include_root=False):
1118
"""Recursively list all files as (path, class, kind, id, entry).
1120
Lists, but does not descend into unversioned directories.
1122
This does not include files that have been deleted in this
1125
Skips the control directory.
1127
# list_files is an iterator, so @needs_read_lock doesn't work properly
1128
# with it. So callers should be careful to always read_lock the tree.
1129
if not self.is_locked():
1130
raise errors.ObjectNotLocked(self)
1132
inv = self.inventory
1133
if include_root is True:
1134
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1135
# Convert these into local objects to save lookup times
1136
pathjoin = osutils.pathjoin
1137
file_kind = self._kind
1139
# transport.base ends in a slash, we want the piece
1140
# between the last two slashes
1141
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
1143
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1145
# directory file_id, relative path, absolute path, reverse sorted children
1146
children = os.listdir(self.basedir)
1148
# jam 20060527 The kernel sized tree seems equivalent whether we
1149
# use a deque and popleft to keep them sorted, or if we use a plain
1150
# list and just reverse() them.
1151
children = collections.deque(children)
1152
stack = [(inv.root.file_id, u'', self.basedir, children)]
1154
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1157
f = children.popleft()
1158
## TODO: If we find a subdirectory with its own .bzr
1159
## directory, then that is a separate tree and we
1160
## should exclude it.
1162
# the bzrdir for this tree
1163
if transport_base_dir == f:
1166
# we know that from_dir_relpath and from_dir_abspath never end in a slash
1167
# and 'f' doesn't begin with one, we can do a string op, rather
1168
# than the checks of pathjoin(), all relative paths will have an extra slash
1170
fp = from_dir_relpath + '/' + f
1173
fap = from_dir_abspath + '/' + f
1175
f_ie = inv.get_child(from_dir_id, f)
1178
elif self.is_ignored(fp[1:]):
1181
# we may not have found this file, because of a unicode issue
1182
f_norm, can_access = osutils.normalized_filename(f)
1183
if f == f_norm or not can_access:
1184
# No change, so treat this file normally
1187
# this file can be accessed by a normalized path
1188
# check again if it is versioned
1189
# these lines are repeated here for performance
1191
fp = from_dir_relpath + '/' + f
1192
fap = from_dir_abspath + '/' + f
1193
f_ie = inv.get_child(from_dir_id, f)
1196
elif self.is_ignored(fp[1:]):
1203
# make a last minute entry
1205
yield fp[1:], c, fk, f_ie.file_id, f_ie
1208
yield fp[1:], c, fk, None, fk_entries[fk]()
1210
yield fp[1:], c, fk, None, TreeEntry()
1213
if fk != 'directory':
1216
# But do this child first
1217
new_children = os.listdir(fap)
1219
new_children = collections.deque(new_children)
1220
stack.append((f_ie.file_id, fp, fap, new_children))
1221
# Break out of inner loop,
1222
# so that we start outer loop with child
1225
# if we finished all children, pop it off the stack
1228
@needs_tree_write_lock
1229
def move(self, from_paths, to_dir=None, after=False, **kwargs):
1232
to_dir must exist in the inventory.
1234
If to_dir exists and is a directory, the files are moved into
1235
it, keeping their old names.
1237
Note that to_dir is only the last component of the new name;
1238
this doesn't change the directory.
1240
For each entry in from_paths the move mode will be determined
1243
The first mode moves the file in the filesystem and updates the
1244
inventory. The second mode only updates the inventory without
1245
touching the file on the filesystem. This is the new mode introduced
1248
move uses the second mode if 'after == True' and the target is not
1249
versioned but present in the working tree.
1251
move uses the second mode if 'after == False' and the source is
1252
versioned but no longer in the working tree, and the target is not
1253
versioned but present in the working tree.
1255
move uses the first mode if 'after == False' and the source is
1256
versioned and present in the working tree, and the target is not
1257
versioned and not present in the working tree.
1259
Everything else results in an error.
1261
This returns a list of (from_path, to_path) pairs for each
1262
entry that is moved.
1267
# check for deprecated use of signature
1269
to_dir = kwargs.get('to_name', None)
1271
raise TypeError('You must supply a target directory')
1273
symbol_versioning.warn('The parameter to_name was deprecated'
1274
' in version 0.13. Use to_dir instead',
1277
# check destination directory
1278
assert not isinstance(from_paths, basestring)
1279
inv = self.inventory
1280
to_abs = self.abspath(to_dir)
1281
if not isdir(to_abs):
1282
raise errors.BzrMoveFailedError('',to_dir,
1283
errors.NotADirectory(to_abs))
1284
if not self.has_filename(to_dir):
1285
raise errors.BzrMoveFailedError('',to_dir,
1286
errors.NotInWorkingDirectory(to_dir))
1287
to_dir_id = inv.path2id(to_dir)
1288
if to_dir_id is None:
1289
raise errors.BzrMoveFailedError('',to_dir,
1290
errors.NotVersionedError(path=str(to_dir)))
1292
to_dir_ie = inv[to_dir_id]
1293
if to_dir_ie.kind != 'directory':
1294
raise errors.BzrMoveFailedError('',to_dir,
1295
errors.NotADirectory(to_abs))
1297
# create rename entries and tuples
1298
for from_rel in from_paths:
1299
from_tail = splitpath(from_rel)[-1]
1300
from_id = inv.path2id(from_rel)
1302
raise errors.BzrMoveFailedError(from_rel,to_dir,
1303
errors.NotVersionedError(path=str(from_rel)))
1305
from_entry = inv[from_id]
1306
from_parent_id = from_entry.parent_id
1307
to_rel = pathjoin(to_dir, from_tail)
1308
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1310
from_tail=from_tail,
1311
from_parent_id=from_parent_id,
1312
to_rel=to_rel, to_tail=from_tail,
1313
to_parent_id=to_dir_id)
1314
rename_entries.append(rename_entry)
1315
rename_tuples.append((from_rel, to_rel))
1317
# determine which move mode to use. checks also for movability
1318
rename_entries = self._determine_mv_mode(rename_entries, after)
1320
original_modified = self._inventory_is_modified
1323
self._inventory_is_modified = True
1324
self._move(rename_entries)
1326
# restore the inventory on error
1327
self._inventory_is_modified = original_modified
1329
self._write_inventory(inv)
1330
return rename_tuples
1332
def _determine_mv_mode(self, rename_entries, after=False):
1333
"""Determines for each from-to pair if both inventory and working tree
1334
or only the inventory has to be changed.
1336
Also does basic plausability tests.
1338
inv = self.inventory
1340
for rename_entry in rename_entries:
1341
# store to local variables for easier reference
1342
from_rel = rename_entry.from_rel
1343
from_id = rename_entry.from_id
1344
to_rel = rename_entry.to_rel
1345
to_id = inv.path2id(to_rel)
1346
only_change_inv = False
1348
# check the inventory for source and destination
1350
raise errors.BzrMoveFailedError(from_rel,to_rel,
1351
errors.NotVersionedError(path=str(from_rel)))
1352
if to_id is not None:
1353
raise errors.BzrMoveFailedError(from_rel,to_rel,
1354
errors.AlreadyVersionedError(path=str(to_rel)))
1356
# try to determine the mode for rename (only change inv or change
1357
# inv and file system)
1359
if not self.has_filename(to_rel):
1360
raise errors.BzrMoveFailedError(from_id,to_rel,
1361
errors.NoSuchFile(path=str(to_rel),
1362
extra="New file has not been created yet"))
1363
only_change_inv = True
1364
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1365
only_change_inv = True
1366
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1367
only_change_inv = False
1368
elif (sys.platform == 'win32'
1369
and from_rel.lower() == to_rel.lower()
1370
and self.has_filename(from_rel)):
1371
only_change_inv = False
1373
# something is wrong, so lets determine what exactly
1374
if not self.has_filename(from_rel) and \
1375
not self.has_filename(to_rel):
1376
raise errors.BzrRenameFailedError(from_rel,to_rel,
1377
errors.PathsDoNotExist(paths=(str(from_rel),
1380
raise errors.RenameFailedFilesExist(from_rel, to_rel)
1381
rename_entry.only_change_inv = only_change_inv
1382
return rename_entries
1384
def _move(self, rename_entries):
1385
"""Moves a list of files.
1387
Depending on the value of the flag 'only_change_inv', the
1388
file will be moved on the file system or not.
1390
inv = self.inventory
1393
for entry in rename_entries:
1395
self._move_entry(entry)
1397
self._rollback_move(moved)
1401
def _rollback_move(self, moved):
1402
"""Try to rollback a previous move in case of an filesystem error."""
1403
inv = self.inventory
1406
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1407
entry.to_tail, entry.to_parent_id, entry.from_rel,
1408
entry.from_tail, entry.from_parent_id,
1409
entry.only_change_inv))
1410
except errors.BzrMoveFailedError, e:
1411
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
1412
" The working tree is in an inconsistent state."
1413
" Please consider doing a 'bzr revert'."
1414
" Error message is: %s" % e)
1416
def _move_entry(self, entry):
1417
inv = self.inventory
1418
from_rel_abs = self.abspath(entry.from_rel)
1419
to_rel_abs = self.abspath(entry.to_rel)
1420
if from_rel_abs == to_rel_abs:
1421
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
1422
"Source and target are identical.")
1424
if not entry.only_change_inv:
1426
osutils.rename(from_rel_abs, to_rel_abs)
1428
raise errors.BzrMoveFailedError(entry.from_rel,
1430
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
1432
@needs_tree_write_lock
1433
def rename_one(self, from_rel, to_rel, after=False):
1436
This can change the directory or the filename or both.
1438
rename_one has several 'modes' to work. First, it can rename a physical
1439
file and change the file_id. That is the normal mode. Second, it can
1440
only change the file_id without touching any physical file. This is
1441
the new mode introduced in version 0.15.
1443
rename_one uses the second mode if 'after == True' and 'to_rel' is not
1444
versioned but present in the working tree.
1446
rename_one uses the second mode if 'after == False' and 'from_rel' is
1447
versioned but no longer in the working tree, and 'to_rel' is not
1448
versioned but present in the working tree.
1450
rename_one uses the first mode if 'after == False' and 'from_rel' is
1451
versioned and present in the working tree, and 'to_rel' is not
1452
versioned and not present in the working tree.
1454
Everything else results in an error.
1456
inv = self.inventory
1459
# create rename entries and tuples
1460
from_tail = splitpath(from_rel)[-1]
1461
from_id = inv.path2id(from_rel)
1463
raise errors.BzrRenameFailedError(from_rel,to_rel,
1464
errors.NotVersionedError(path=str(from_rel)))
1465
from_entry = inv[from_id]
1466
from_parent_id = from_entry.parent_id
1467
to_dir, to_tail = os.path.split(to_rel)
1468
to_dir_id = inv.path2id(to_dir)
1469
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1471
from_tail=from_tail,
1472
from_parent_id=from_parent_id,
1473
to_rel=to_rel, to_tail=to_tail,
1474
to_parent_id=to_dir_id)
1475
rename_entries.append(rename_entry)
1477
# determine which move mode to use. checks also for movability
1478
rename_entries = self._determine_mv_mode(rename_entries, after)
1480
# check if the target changed directory and if the target directory is
1482
if to_dir_id is None:
1483
raise errors.BzrMoveFailedError(from_rel,to_rel,
1484
errors.NotVersionedError(path=str(to_dir)))
1486
# all checks done. now we can continue with our actual work
1487
mutter('rename_one:\n'
1492
' to_dir_id {%s}\n',
1493
from_id, from_rel, to_rel, to_dir, to_dir_id)
1495
self._move(rename_entries)
1496
self._write_inventory(inv)
1498
class _RenameEntry(object):
1499
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
1500
to_rel, to_tail, to_parent_id, only_change_inv=False):
1501
self.from_rel = from_rel
1502
self.from_id = from_id
1503
self.from_tail = from_tail
1504
self.from_parent_id = from_parent_id
1505
self.to_rel = to_rel
1506
self.to_tail = to_tail
1507
self.to_parent_id = to_parent_id
1508
self.only_change_inv = only_change_inv
1512
"""Return all unknown files.
1514
These are files in the working directory that are not versioned or
1515
control files or ignored.
1517
# force the extras method to be fully executed before returning, to
1518
# prevent race conditions with the lock
1520
[subp for subp in self.extras() if not self.is_ignored(subp)])
1522
@needs_tree_write_lock
1523
def unversion(self, file_ids):
1524
"""Remove the file ids in file_ids from the current versioned set.
1526
When a file_id is unversioned, all of its children are automatically
1529
:param file_ids: The file ids to stop versioning.
1530
:raises: NoSuchId if any fileid is not currently versioned.
1532
for file_id in file_ids:
1533
if self._inventory.has_id(file_id):
1534
self._inventory.remove_recursive_id(file_id)
1536
raise errors.NoSuchId(self, file_id)
1538
# in the future this should just set a dirty bit to wait for the
1539
# final unlock. However, until all methods of workingtree start
1540
# with the current in -memory inventory rather than triggering
1541
# a read, it is more complex - we need to teach read_inventory
1542
# to know when to read, and when to not read first... and possibly
1543
# to save first when the in memory one may be corrupted.
1544
# so for now, we just only write it if it is indeed dirty.
1546
self._write_inventory(self._inventory)
1548
@deprecated_method(zero_eight)
1549
def iter_conflicts(self):
1550
"""List all files in the tree that have text or content conflicts.
1551
DEPRECATED. Use conflicts instead."""
1552
return self._iter_conflicts()
1554
def _iter_conflicts(self):
1556
for info in self.list_files():
1558
stem = get_conflicted_stem(path)
1561
if stem not in conflicted:
1562
conflicted.add(stem)
1566
def pull(self, source, overwrite=False, stop_revision=None,
1567
change_reporter=None, possible_transports=None):
1568
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1571
pp = ProgressPhase("Pull phase", 2, top_pb)
1573
old_revision_info = self.branch.last_revision_info()
1574
basis_tree = self.basis_tree()
1575
count = self.branch.pull(source, overwrite, stop_revision,
1576
possible_transports=possible_transports)
1577
new_revision_info = self.branch.last_revision_info()
1578
if new_revision_info != old_revision_info:
1580
repository = self.branch.repository
1581
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1582
basis_tree.lock_read()
1584
new_basis_tree = self.branch.basis_tree()
1591
change_reporter=change_reporter)
1592
if (basis_tree.inventory.root is None and
1593
new_basis_tree.inventory.root is not None):
1594
self.set_root_id(new_basis_tree.get_root_id())
1598
# TODO - dedup parents list with things merged by pull ?
1599
# reuse the revisiontree we merged against to set the new
1601
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1602
# we have to pull the merge trees out again, because
1603
# merge_inner has set the ids. - this corner is not yet
1604
# layered well enough to prevent double handling.
1605
# XXX TODO: Fix the double handling: telling the tree about
1606
# the already known parent data is wasteful.
1607
merges = self.get_parent_ids()[1:]
1608
parent_trees.extend([
1609
(parent, repository.revision_tree(parent)) for
1611
self.set_parent_trees(parent_trees)
1618
def put_file_bytes_non_atomic(self, file_id, bytes):
1619
"""See MutableTree.put_file_bytes_non_atomic."""
1620
stream = file(self.id2abspath(file_id), 'wb')
1625
# TODO: update the hashcache here ?
1628
"""Yield all unversioned files in this WorkingTree.
1630
If there are any unversioned directories then only the directory is
1631
returned, not all its children. But if there are unversioned files
1632
under a versioned subdirectory, they are returned.
1634
Currently returned depth-first, sorted by name within directories.
1635
This is the same order used by 'osutils.walkdirs'.
1637
## TODO: Work from given directory downwards
1638
for path, dir_entry in self.inventory.directories():
1639
# mutter("search for unknowns in %r", path)
1640
dirabs = self.abspath(path)
1641
if not isdir(dirabs):
1642
# e.g. directory deleted
1646
for subf in os.listdir(dirabs):
1649
if subf not in dir_entry.children:
1650
subf_norm, can_access = osutils.normalized_filename(subf)
1651
if subf_norm != subf and can_access:
1652
if subf_norm not in dir_entry.children:
1653
fl.append(subf_norm)
1659
subp = pathjoin(path, subf)
1662
def ignored_files(self):
1663
"""Yield list of PATH, IGNORE_PATTERN"""
1664
for subp in self.extras():
1665
pat = self.is_ignored(subp)
1669
def get_ignore_list(self):
1670
"""Return list of ignore patterns.
1672
Cached in the Tree object after the first call.
1674
ignoreset = getattr(self, '_ignoreset', None)
1675
if ignoreset is not None:
1678
ignore_globs = set()
1679
ignore_globs.update(ignores.get_runtime_ignores())
1680
ignore_globs.update(ignores.get_user_ignores())
1681
if self.has_filename(bzrlib.IGNORE_FILENAME):
1682
f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
1684
ignore_globs.update(ignores.parse_ignore_file(f))
1687
self._ignoreset = ignore_globs
1690
def _flush_ignore_list_cache(self):
1691
"""Resets the cached ignore list to force a cache rebuild."""
1692
self._ignoreset = None
1693
self._ignoreglobster = None
1695
def is_ignored(self, filename):
1696
r"""Check whether the filename matches an ignore pattern.
1698
Patterns containing '/' or '\' need to match the whole path;
1699
others match against only the last component.
1701
If the file is ignored, returns the pattern which caused it to
1702
be ignored, otherwise None. So this can simply be used as a
1703
boolean if desired."""
1704
if getattr(self, '_ignoreglobster', None) is None:
1705
self._ignoreglobster = globbing.Globster(self.get_ignore_list())
1706
return self._ignoreglobster.match(filename)
1708
def kind(self, file_id):
1709
return file_kind(self.id2abspath(file_id))
1711
def stored_kind(self, file_id):
1712
"""See Tree.stored_kind"""
1713
return self.inventory[file_id].kind
1715
def _comparison_data(self, entry, path):
1716
abspath = self.abspath(path)
1718
stat_value = os.lstat(abspath)
1720
if getattr(e, 'errno', None) == errno.ENOENT:
1727
mode = stat_value.st_mode
1728
kind = osutils.file_kind_from_stat_mode(mode)
1729
if not supports_executable():
1730
executable = entry is not None and entry.executable
1732
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1733
return kind, executable, stat_value
1735
def _file_size(self, entry, stat_value):
1736
return stat_value.st_size
1738
def last_revision(self):
1739
"""Return the last revision of the branch for this tree.
1741
This format tree does not support a separate marker for last-revision
1742
compared to the branch.
1744
See MutableTree.last_revision
1746
return self._last_revision()
1749
def _last_revision(self):
1750
"""helper for get_parent_ids."""
1751
return _mod_revision.ensure_null(self.branch.last_revision())
1753
def is_locked(self):
1754
return self._control_files.is_locked()
1756
def _must_be_locked(self):
1757
if not self.is_locked():
1758
raise errors.ObjectNotLocked(self)
1760
def lock_read(self):
1761
"""See Branch.lock_read, and WorkingTree.unlock."""
1762
if not self.is_locked():
1764
self.branch.lock_read()
1766
return self._control_files.lock_read()
1768
self.branch.unlock()
1771
def lock_tree_write(self):
1772
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1773
if not self.is_locked():
1775
self.branch.lock_read()
1777
return self._control_files.lock_write()
1779
self.branch.unlock()
1782
def lock_write(self):
1783
"""See MutableTree.lock_write, and WorkingTree.unlock."""
1784
if not self.is_locked():
1786
self.branch.lock_write()
1788
return self._control_files.lock_write()
1790
self.branch.unlock()
1793
def get_physical_lock_status(self):
1794
return self._control_files.get_physical_lock_status()
1796
def _basis_inventory_name(self):
1797
return 'basis-inventory-cache'
1799
def _reset_data(self):
1800
"""Reset transient data that cannot be revalidated."""
1801
self._inventory_is_modified = False
1802
result = self._deserialize(self._control_files.get('inventory'))
1803
self._set_inventory(result, dirty=False)
1805
@needs_tree_write_lock
1806
def set_last_revision(self, new_revision):
1807
"""Change the last revision in the working tree."""
1808
if self._change_last_revision(new_revision):
1809
self._cache_basis_inventory(new_revision)
1811
def _change_last_revision(self, new_revision):
1812
"""Template method part of set_last_revision to perform the change.
1814
This is used to allow WorkingTree3 instances to not affect branch
1815
when their last revision is set.
1817
if _mod_revision.is_null(new_revision):
1818
self.branch.set_revision_history([])
1821
self.branch.generate_revision_history(new_revision)
1822
except errors.NoSuchRevision:
1823
# not present in the repo - dont try to set it deeper than the tip
1824
self.branch.set_revision_history([new_revision])
1827
def _write_basis_inventory(self, xml):
1828
"""Write the basis inventory XML to the basis-inventory file"""
1829
assert isinstance(xml, str), 'serialised xml must be bytestring.'
1830
path = self._basis_inventory_name()
1832
self._control_files.put(path, sio)
1834
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1835
"""Create the text that will be saved in basis-inventory"""
1836
inventory.revision_id = revision_id
1837
return xml7.serializer_v7.write_inventory_to_string(inventory)
1839
def _cache_basis_inventory(self, new_revision):
1840
"""Cache new_revision as the basis inventory."""
1841
# TODO: this should allow the ready-to-use inventory to be passed in,
1842
# as commit already has that ready-to-use [while the format is the
1845
# this double handles the inventory - unpack and repack -
1846
# but is easier to understand. We can/should put a conditional
1847
# in here based on whether the inventory is in the latest format
1848
# - perhaps we should repack all inventories on a repository
1850
# the fast path is to copy the raw xml from the repository. If the
1851
# xml contains 'revision_id="', then we assume the right
1852
# revision_id is set. We must check for this full string, because a
1853
# root node id can legitimately look like 'revision_id' but cannot
1855
xml = self.branch.repository.get_inventory_xml(new_revision)
1856
firstline = xml.split('\n', 1)[0]
1857
if (not 'revision_id="' in firstline or
1858
'format="7"' not in firstline):
1859
inv = self.branch.repository.deserialise_inventory(
1861
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1862
self._write_basis_inventory(xml)
1863
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1866
def read_basis_inventory(self):
1867
"""Read the cached basis inventory."""
1868
path = self._basis_inventory_name()
1869
return self._control_files.get(path).read()
1872
def read_working_inventory(self):
1873
"""Read the working inventory.
1875
:raises errors.InventoryModified: read_working_inventory will fail
1876
when the current in memory inventory has been modified.
1878
# conceptually this should be an implementation detail of the tree.
1879
# XXX: Deprecate this.
1880
# ElementTree does its own conversion from UTF-8, so open in
1882
if self._inventory_is_modified:
1883
raise errors.InventoryModified(self)
1884
result = self._deserialize(self._control_files.get('inventory'))
1885
self._set_inventory(result, dirty=False)
1888
@needs_tree_write_lock
1889
def remove(self, files, verbose=False, to_file=None, keep_files=True,
1891
"""Remove nominated files from the working inventory.
1893
:files: File paths relative to the basedir.
1894
:keep_files: If true, the files will also be kept.
1895
:force: Delete files and directories, even if they are changed and
1896
even if the directories are not empty.
1898
if isinstance(files, basestring):
1904
unknown_nested_files=set()
1906
def recurse_directory_to_add_files(directory):
1907
# Recurse directory and add all files
1908
# so we can check if they have changed.
1909
for parent_info, file_infos in\
1910
osutils.walkdirs(self.abspath(directory),
1912
for relpath, basename, kind, lstat, abspath in file_infos:
1913
# Is it versioned or ignored?
1914
if self.path2id(relpath) or self.is_ignored(relpath):
1915
# Add nested content for deletion.
1916
new_files.add(relpath)
1918
# Files which are not versioned and not ignored
1919
# should be treated as unknown.
1920
unknown_nested_files.add((relpath, None, kind))
1922
for filename in files:
1923
# Get file name into canonical form.
1924
abspath = self.abspath(filename)
1925
filename = self.relpath(abspath)
1926
if len(filename) > 0:
1927
new_files.add(filename)
1928
if osutils.isdir(abspath):
1929
recurse_directory_to_add_files(filename)
1931
files = list(new_files)
1934
return # nothing to do
1936
# Sort needed to first handle directory content before the directory
1937
files.sort(reverse=True)
1939
# Bail out if we are going to delete files we shouldn't
1940
if not keep_files and not force:
1941
has_changed_files = len(unknown_nested_files) > 0
1942
if not has_changed_files:
1943
for (file_id, path, content_change, versioned, parent_id, name,
1944
kind, executable) in self.iter_changes(self.basis_tree(),
1945
include_unchanged=True, require_versioned=False,
1946
want_unversioned=True, specific_files=files):
1947
if versioned == (False, False):
1948
# The record is unknown ...
1949
if not self.is_ignored(path[1]):
1950
# ... but not ignored
1951
has_changed_files = True
1953
elif content_change and (kind[1] != None):
1954
# Versioned and changed, but not deleted
1955
has_changed_files = True
1958
if has_changed_files:
1959
# Make delta show ALL applicable changes in error message.
1960
tree_delta = self.changes_from(self.basis_tree(),
1961
require_versioned=False, want_unversioned=True,
1962
specific_files=files)
1963
for unknown_file in unknown_nested_files:
1964
if unknown_file not in tree_delta.unversioned:
1965
tree_delta.unversioned.extend((unknown_file,))
1966
raise errors.BzrRemoveChangedFilesError(tree_delta)
1968
# Build inv_delta and delete files where applicaple,
1969
# do this before any modifications to inventory.
1971
fid = self.path2id(f)
1974
message = "%s is not versioned." % (f,)
1977
# having removed it, it must be either ignored or unknown
1978
if self.is_ignored(f):
1982
textui.show_status(new_status, self.kind(fid), f,
1985
inv_delta.append((f, None, fid, None))
1986
message = "removed %s" % (f,)
1989
abs_path = self.abspath(f)
1990
if osutils.lexists(abs_path):
1991
if (osutils.isdir(abs_path) and
1992
len(os.listdir(abs_path)) > 0):
1994
osutils.rmtree(abs_path)
1996
message = "%s is not an empty directory "\
1997
"and won't be deleted." % (f,)
1999
osutils.delete_any(abs_path)
2000
message = "deleted %s" % (f,)
2001
elif message is not None:
2002
# Only care if we haven't done anything yet.
2003
message = "%s does not exist." % (f,)
2005
# Print only one message (if any) per file.
2006
if message is not None:
2008
self.apply_inventory_delta(inv_delta)
2010
@needs_tree_write_lock
2011
def revert(self, filenames=None, old_tree=None, backups=True,
2012
pb=DummyProgress(), report_changes=False):
2013
from bzrlib.conflicts import resolve
2016
symbol_versioning.warn('Using [] to revert all files is deprecated'
2017
' as of bzr 0.91. Please use None (the default) instead.',
2018
DeprecationWarning, stacklevel=2)
2019
if old_tree is None:
2020
basis_tree = self.basis_tree()
2021
basis_tree.lock_read()
2022
old_tree = basis_tree
2026
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
2028
if filenames is None and len(self.get_parent_ids()) > 1:
2030
last_revision = self.last_revision()
2031
if last_revision != NULL_REVISION:
2032
if basis_tree is None:
2033
basis_tree = self.basis_tree()
2034
basis_tree.lock_read()
2035
parent_trees.append((last_revision, basis_tree))
2036
self.set_parent_trees(parent_trees)
2039
resolve(self, filenames, ignore_misses=True, recursive=True)
2041
if basis_tree is not None:
2045
def revision_tree(self, revision_id):
2046
"""See Tree.revision_tree.
2048
WorkingTree can supply revision_trees for the basis revision only
2049
because there is only one cached inventory in the bzr directory.
2051
if revision_id == self.last_revision():
2053
xml = self.read_basis_inventory()
2054
except errors.NoSuchFile:
2058
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2059
# dont use the repository revision_tree api because we want
2060
# to supply the inventory.
2061
if inv.revision_id == revision_id:
2062
return revisiontree.RevisionTree(self.branch.repository,
2064
except errors.BadInventoryFormat:
2066
# raise if there was no inventory, or if we read the wrong inventory.
2067
raise errors.NoSuchRevisionInTree(self, revision_id)
2069
# XXX: This method should be deprecated in favour of taking in a proper
2070
# new Inventory object.
2071
@needs_tree_write_lock
2072
def set_inventory(self, new_inventory_list):
2073
from bzrlib.inventory import (Inventory,
2078
inv = Inventory(self.get_root_id())
2079
for path, file_id, parent, kind in new_inventory_list:
2080
name = os.path.basename(path)
2083
# fixme, there should be a factory function inv,add_??
2084
if kind == 'directory':
2085
inv.add(InventoryDirectory(file_id, name, parent))
2086
elif kind == 'file':
2087
inv.add(InventoryFile(file_id, name, parent))
2088
elif kind == 'symlink':
2089
inv.add(InventoryLink(file_id, name, parent))
2091
raise errors.BzrError("unknown kind %r" % kind)
2092
self._write_inventory(inv)
2094
@needs_tree_write_lock
2095
def set_root_id(self, file_id):
2096
"""Set the root id for this tree."""
2099
symbol_versioning.warn(symbol_versioning.zero_twelve
2100
% 'WorkingTree.set_root_id with fileid=None',
2105
file_id = osutils.safe_file_id(file_id)
2106
self._set_root_id(file_id)
2108
def _set_root_id(self, file_id):
2109
"""Set the root id for this tree, in a format specific manner.
2111
:param file_id: The file id to assign to the root. It must not be
2112
present in the current inventory or an error will occur. It must
2113
not be None, but rather a valid file id.
2115
inv = self._inventory
2116
orig_root_id = inv.root.file_id
2117
# TODO: it might be nice to exit early if there was nothing
2118
# to do, saving us from trigger a sync on unlock.
2119
self._inventory_is_modified = True
2120
# we preserve the root inventory entry object, but
2121
# unlinkit from the byid index
2122
del inv._byid[inv.root.file_id]
2123
inv.root.file_id = file_id
2124
# and link it into the index with the new changed id.
2125
inv._byid[inv.root.file_id] = inv.root
2126
# and finally update all children to reference the new id.
2127
# XXX: this should be safe to just look at the root.children
2128
# list, not the WHOLE INVENTORY.
2131
if entry.parent_id == orig_root_id:
2132
entry.parent_id = inv.root.file_id
2135
"""See Branch.unlock.
2137
WorkingTree locking just uses the Branch locking facilities.
2138
This is current because all working trees have an embedded branch
2139
within them. IF in the future, we were to make branch data shareable
2140
between multiple working trees, i.e. via shared storage, then we
2141
would probably want to lock both the local tree, and the branch.
2143
raise NotImplementedError(self.unlock)
2145
def update(self, change_reporter=None, possible_transports=None):
2146
"""Update a working tree along its branch.
2148
This will update the branch if its bound too, which means we have
2149
multiple trees involved:
2151
- The new basis tree of the master.
2152
- The old basis tree of the branch.
2153
- The old basis tree of the working tree.
2154
- The current working tree state.
2156
Pathologically, all three may be different, and non-ancestors of each
2157
other. Conceptually we want to:
2159
- Preserve the wt.basis->wt.state changes
2160
- Transform the wt.basis to the new master basis.
2161
- Apply a merge of the old branch basis to get any 'local' changes from
2163
- Restore the wt.basis->wt.state changes.
2165
There isn't a single operation at the moment to do that, so we:
2166
- Merge current state -> basis tree of the master w.r.t. the old tree
2168
- Do a 'normal' merge of the old branch basis if it is relevant.
2170
if self.branch.get_bound_location() is not None:
2172
update_branch = True
2174
self.lock_tree_write()
2175
update_branch = False
2178
old_tip = self.branch.update(possible_transports)
2181
return self._update_tree(old_tip, change_reporter)
2185
@needs_tree_write_lock
2186
def _update_tree(self, old_tip=None, change_reporter=None):
2187
"""Update a tree to the master branch.
2189
:param old_tip: if supplied, the previous tip revision the branch,
2190
before it was changed to the master branch's tip.
2192
# here if old_tip is not None, it is the old tip of the branch before
2193
# it was updated from the master branch. This should become a pending
2194
# merge in the working tree to preserve the user existing work. we
2195
# cant set that until we update the working trees last revision to be
2196
# one from the new branch, because it will just get absorbed by the
2197
# parent de-duplication logic.
2199
# We MUST save it even if an error occurs, because otherwise the users
2200
# local work is unreferenced and will appear to have been lost.
2204
last_rev = self.get_parent_ids()[0]
2206
last_rev = _mod_revision.NULL_REVISION
2207
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2208
# merge tree state up to new branch tip.
2209
basis = self.basis_tree()
2212
to_tree = self.branch.basis_tree()
2213
if basis.inventory.root is None:
2214
self.set_root_id(to_tree.get_root_id())
2216
result += merge.merge_inner(
2221
change_reporter=change_reporter)
2224
# TODO - dedup parents list with things merged by pull ?
2225
# reuse the tree we've updated to to set the basis:
2226
parent_trees = [(self.branch.last_revision(), to_tree)]
2227
merges = self.get_parent_ids()[1:]
2228
# Ideally we ask the tree for the trees here, that way the working
2229
# tree can decide whether to give us teh entire tree or give us a
2230
# lazy initialised tree. dirstate for instance will have the trees
2231
# in ram already, whereas a last-revision + basis-inventory tree
2232
# will not, but also does not need them when setting parents.
2233
for parent in merges:
2234
parent_trees.append(
2235
(parent, self.branch.repository.revision_tree(parent)))
2236
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2237
parent_trees.append(
2238
(old_tip, self.branch.repository.revision_tree(old_tip)))
2239
self.set_parent_trees(parent_trees)
2240
last_rev = parent_trees[0][0]
2242
# the working tree had the same last-revision as the master
2243
# branch did. We may still have pivot local work from the local
2244
# branch into old_tip:
2245
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2246
self.add_parent_tree_id(old_tip)
2247
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2248
and old_tip != last_rev):
2249
# our last revision was not the prior branch last revision
2250
# and we have converted that last revision to a pending merge.
2251
# base is somewhere between the branch tip now
2252
# and the now pending merge
2254
# Since we just modified the working tree and inventory, flush out
2255
# the current state, before we modify it again.
2256
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2257
# requires it only because TreeTransform directly munges the
2258
# inventory and calls tree._write_inventory(). Ultimately we
2259
# should be able to remove this extra flush.
2261
graph = self.branch.repository.get_graph()
2262
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2264
base_tree = self.branch.repository.revision_tree(base_rev_id)
2265
other_tree = self.branch.repository.revision_tree(old_tip)
2266
result += merge.merge_inner(
2271
change_reporter=change_reporter)
2274
def _write_hashcache_if_dirty(self):
2275
"""Write out the hashcache if it is dirty."""
2276
if self._hashcache.needs_write:
2278
self._hashcache.write()
2280
if e.errno not in (errno.EPERM, errno.EACCES):
2282
# TODO: jam 20061219 Should this be a warning? A single line
2283
# warning might be sufficient to let the user know what
2285
mutter('Could not write hashcache for %s\nError: %s',
2286
self._hashcache.cache_file_name(), e)
2288
@needs_tree_write_lock
2289
def _write_inventory(self, inv):
2290
"""Write inventory as the current inventory."""
2291
self._set_inventory(inv, dirty=True)
2294
def set_conflicts(self, arg):
2295
raise errors.UnsupportedOperation(self.set_conflicts, self)
2297
def add_conflicts(self, arg):
2298
raise errors.UnsupportedOperation(self.add_conflicts, self)
2301
def conflicts(self):
2302
conflicts = _mod_conflicts.ConflictList()
2303
for conflicted in self._iter_conflicts():
2306
if file_kind(self.abspath(conflicted)) != "file":
2308
except errors.NoSuchFile:
2311
for suffix in ('.THIS', '.OTHER'):
2313
kind = file_kind(self.abspath(conflicted+suffix))
2316
except errors.NoSuchFile:
2320
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
2321
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
2323
file_id=self.path2id(conflicted)))
2326
def walkdirs(self, prefix=""):
2327
"""Walk the directories of this tree.
2329
returns a generator which yields items in the form:
2330
((curren_directory_path, fileid),
2331
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
2334
This API returns a generator, which is only valid during the current
2335
tree transaction - within a single lock_read or lock_write duration.
2337
If the tree is not locked, it may cause an error to be raised,
2338
depending on the tree implementation.
2340
disk_top = self.abspath(prefix)
2341
if disk_top.endswith('/'):
2342
disk_top = disk_top[:-1]
2343
top_strip_len = len(disk_top) + 1
2344
inventory_iterator = self._walkdirs(prefix)
2345
disk_iterator = osutils.walkdirs(disk_top, prefix)
2347
current_disk = disk_iterator.next()
2348
disk_finished = False
2350
if not (e.errno == errno.ENOENT or
2351
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
2354
disk_finished = True
2356
current_inv = inventory_iterator.next()
2357
inv_finished = False
2358
except StopIteration:
2361
while not inv_finished or not disk_finished:
2363
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2364
cur_disk_dir_content) = current_disk
2366
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2367
cur_disk_dir_content) = ((None, None), None)
2368
if not disk_finished:
2369
# strip out .bzr dirs
2370
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2371
len(cur_disk_dir_content) > 0):
2372
# osutils.walkdirs can be made nicer -
2373
# yield the path-from-prefix rather than the pathjoined
2375
bzrdir_loc = bisect_left(cur_disk_dir_content,
2377
if cur_disk_dir_content[bzrdir_loc][0] == '.bzr':
2378
# we dont yield the contents of, or, .bzr itself.
2379
del cur_disk_dir_content[bzrdir_loc]
2381
# everything is unknown
2384
# everything is missing
2387
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2389
# disk is before inventory - unknown
2390
dirblock = [(relpath, basename, kind, stat, None, None) for
2391
relpath, basename, kind, stat, top_path in
2392
cur_disk_dir_content]
2393
yield (cur_disk_dir_relpath, None), dirblock
2395
current_disk = disk_iterator.next()
2396
except StopIteration:
2397
disk_finished = True
2399
# inventory is before disk - missing.
2400
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2401
for relpath, basename, dkind, stat, fileid, kind in
2403
yield (current_inv[0][0], current_inv[0][1]), dirblock
2405
current_inv = inventory_iterator.next()
2406
except StopIteration:
2409
# versioned present directory
2410
# merge the inventory and disk data together
2412
for relpath, subiterator in itertools.groupby(sorted(
2413
current_inv[1] + cur_disk_dir_content,
2414
key=operator.itemgetter(0)), operator.itemgetter(1)):
2415
path_elements = list(subiterator)
2416
if len(path_elements) == 2:
2417
inv_row, disk_row = path_elements
2418
# versioned, present file
2419
dirblock.append((inv_row[0],
2420
inv_row[1], disk_row[2],
2421
disk_row[3], inv_row[4],
2423
elif len(path_elements[0]) == 5:
2425
dirblock.append((path_elements[0][0],
2426
path_elements[0][1], path_elements[0][2],
2427
path_elements[0][3], None, None))
2428
elif len(path_elements[0]) == 6:
2429
# versioned, absent file.
2430
dirblock.append((path_elements[0][0],
2431
path_elements[0][1], 'unknown', None,
2432
path_elements[0][4], path_elements[0][5]))
2434
raise NotImplementedError('unreachable code')
2435
yield current_inv[0], dirblock
2437
current_inv = inventory_iterator.next()
2438
except StopIteration:
2441
current_disk = disk_iterator.next()
2442
except StopIteration:
2443
disk_finished = True
2445
def _walkdirs(self, prefix=""):
2446
"""Walk the directories of this tree.
2448
:prefix: is used as the directrory to start with.
2449
returns a generator which yields items in the form:
2450
((curren_directory_path, fileid),
2451
[(file1_path, file1_name, file1_kind, None, file1_id,
2454
_directory = 'directory'
2455
# get the root in the inventory
2456
inv = self.inventory
2457
top_id = inv.path2id(prefix)
2461
pending = [(prefix, '', _directory, None, top_id, None)]
2464
currentdir = pending.pop()
2465
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2466
top_id = currentdir[4]
2468
relroot = currentdir[0] + '/'
2471
# FIXME: stash the node in pending
2473
for name, child in entry.sorted_children():
2474
dirblock.append((relroot + name, name, child.kind, None,
2475
child.file_id, child.kind
2477
yield (currentdir[0], entry.file_id), dirblock
2478
# push the user specified dirs from dirblock
2479
for dir in reversed(dirblock):
2480
if dir[2] == _directory:
2483
@needs_tree_write_lock
2484
def auto_resolve(self):
2485
"""Automatically resolve text conflicts according to contents.
2487
Only text conflicts are auto_resolvable. Files with no conflict markers
2488
are considered 'resolved', because bzr always puts conflict markers
2489
into files that have text conflicts. The corresponding .THIS .BASE and
2490
.OTHER files are deleted, as per 'resolve'.
2491
:return: a tuple of ConflictLists: (un_resolved, resolved).
2493
un_resolved = _mod_conflicts.ConflictList()
2494
resolved = _mod_conflicts.ConflictList()
2495
conflict_re = re.compile('^(<{7}|={7}|>{7})')
2496
for conflict in self.conflicts():
2497
if (conflict.typestring != 'text conflict' or
2498
self.kind(conflict.file_id) != 'file'):
2499
un_resolved.append(conflict)
2501
my_file = open(self.id2abspath(conflict.file_id), 'rb')
2503
for line in my_file:
2504
if conflict_re.search(line):
2505
un_resolved.append(conflict)
2508
resolved.append(conflict)
2511
resolved.remove_files(self)
2512
self.set_conflicts(un_resolved)
2513
return un_resolved, resolved
2515
def _validate(self):
2516
"""Validate internal structures.
2518
This is meant mostly for the test suite. To give it a chance to detect
2519
corruption after actions have occurred. The default implementation is a
2522
:return: None. An exception should be raised if there is an error.
2527
class WorkingTree2(WorkingTree):
2528
"""This is the Format 2 working tree.
2530
This was the first weave based working tree.
2531
- uses os locks for locking.
2532
- uses the branch last-revision.
2535
def __init__(self, *args, **kwargs):
2536
super(WorkingTree2, self).__init__(*args, **kwargs)
2537
# WorkingTree2 has more of a constraint that self._inventory must
2538
# exist. Because this is an older format, we don't mind the overhead
2539
# caused by the extra computation here.
2541
# Newer WorkingTree's should only have self._inventory set when they
2543
if self._inventory is None:
2544
self.read_working_inventory()
2546
def lock_tree_write(self):
2547
"""See WorkingTree.lock_tree_write().
2549
In Format2 WorkingTrees we have a single lock for the branch and tree
2550
so lock_tree_write() degrades to lock_write().
2552
self.branch.lock_write()
2554
return self._control_files.lock_write()
2556
self.branch.unlock()
2560
# do non-implementation specific cleanup
2563
# we share control files:
2564
if self._control_files._lock_count == 3:
2565
# _inventory_is_modified is always False during a read lock.
2566
if self._inventory_is_modified:
2568
self._write_hashcache_if_dirty()
2570
# reverse order of locking.
2572
return self._control_files.unlock()
2574
self.branch.unlock()
2577
class WorkingTree3(WorkingTree):
2578
"""This is the Format 3 working tree.
2580
This differs from the base WorkingTree by:
2581
- having its own file lock
2582
- having its own last-revision property.
2584
This is new in bzr 0.8
2588
def _last_revision(self):
2589
"""See Mutable.last_revision."""
2591
return self._control_files.get('last-revision').read()
2592
except errors.NoSuchFile:
2593
return _mod_revision.NULL_REVISION
2595
def _change_last_revision(self, revision_id):
2596
"""See WorkingTree._change_last_revision."""
2597
if revision_id is None or revision_id == NULL_REVISION:
2599
self._control_files._transport.delete('last-revision')
2600
except errors.NoSuchFile:
2604
self._control_files.put_bytes('last-revision', revision_id)
2607
@needs_tree_write_lock
2608
def set_conflicts(self, conflicts):
2609
self._put_rio('conflicts', conflicts.to_stanzas(),
2612
@needs_tree_write_lock
2613
def add_conflicts(self, new_conflicts):
2614
conflict_set = set(self.conflicts())
2615
conflict_set.update(set(list(new_conflicts)))
2616
self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2617
key=_mod_conflicts.Conflict.sort_key)))
2620
def conflicts(self):
2622
confile = self._control_files.get('conflicts')
2623
except errors.NoSuchFile:
2624
return _mod_conflicts.ConflictList()
2626
if confile.next() != CONFLICT_HEADER_1 + '\n':
2627
raise errors.ConflictFormatError()
2628
except StopIteration:
2629
raise errors.ConflictFormatError()
2630
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2633
# do non-implementation specific cleanup
2635
if self._control_files._lock_count == 1:
2636
# _inventory_is_modified is always False during a read lock.
2637
if self._inventory_is_modified:
2639
self._write_hashcache_if_dirty()
2640
# reverse order of locking.
2642
return self._control_files.unlock()
2644
self.branch.unlock()
2647
def get_conflicted_stem(path):
2648
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2649
if path.endswith(suffix):
2650
return path[:-len(suffix)]
2653
@deprecated_function(zero_eight)
2654
def is_control_file(filename):
2655
"""See WorkingTree.is_control_filename(filename)."""
2656
## FIXME: better check
2657
filename = normpath(filename)
2658
while filename != '':
2659
head, tail = os.path.split(filename)
2660
## mutter('check %r for control file' % ((head, tail),))
2663
if filename == head:
2669
class WorkingTreeFormat(object):
2670
"""An encapsulation of the initialization and open routines for a format.
2672
Formats provide three things:
2673
* An initialization routine,
2677
Formats are placed in an dict by their format string for reference
2678
during workingtree opening. Its not required that these be instances, they
2679
can be classes themselves with class methods - it simply depends on
2680
whether state is needed for a given format or not.
2682
Once a format is deprecated, just deprecate the initialize and open
2683
methods on the format class. Do not deprecate the object, as the
2684
object will be created every time regardless.
2687
_default_format = None
2688
"""The default format used for new trees."""
2691
"""The known formats."""
2693
requires_rich_root = False
2695
upgrade_recommended = False
2698
def find_format(klass, a_bzrdir):
2699
"""Return the format for the working tree object in a_bzrdir."""
2701
transport = a_bzrdir.get_workingtree_transport(None)
2702
format_string = transport.get("format").read()
2703
return klass._formats[format_string]
2704
except errors.NoSuchFile:
2705
raise errors.NoWorkingTree(base=transport.base)
2707
raise errors.UnknownFormatError(format=format_string,
2708
kind="working tree")
2710
def __eq__(self, other):
2711
return self.__class__ is other.__class__
2713
def __ne__(self, other):
2714
return not (self == other)
2717
def get_default_format(klass):
2718
"""Return the current default format."""
2719
return klass._default_format
2721
def get_format_string(self):
2722
"""Return the ASCII format string that identifies this format."""
2723
raise NotImplementedError(self.get_format_string)
2725
def get_format_description(self):
2726
"""Return the short description for this format."""
2727
raise NotImplementedError(self.get_format_description)
2729
def is_supported(self):
2730
"""Is this format supported?
2732
Supported formats can be initialized and opened.
2733
Unsupported formats may not support initialization or committing or
2734
some other features depending on the reason for not being supported.
2739
def register_format(klass, format):
2740
klass._formats[format.get_format_string()] = format
2743
def set_default_format(klass, format):
2744
klass._default_format = format
2747
def unregister_format(klass, format):
2748
assert klass._formats[format.get_format_string()] is format
2749
del klass._formats[format.get_format_string()]
2752
class WorkingTreeFormat2(WorkingTreeFormat):
2753
"""The second working tree format.
2755
This format modified the hash cache from the format 1 hash cache.
2758
upgrade_recommended = True
2760
def get_format_description(self):
2761
"""See WorkingTreeFormat.get_format_description()."""
2762
return "Working tree format 2"
2764
def stub_initialize_remote(self, control_files):
2765
"""As a special workaround create critical control files for a remote working tree
2767
This ensures that it can later be updated and dealt with locally,
2768
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2769
no working tree. (See bug #43064).
2773
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2775
control_files.put('inventory', sio)
2777
control_files.put_bytes('pending-merges', '')
2780
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2781
accelerator_tree=None, hardlink=False):
2782
"""See WorkingTreeFormat.initialize()."""
2783
if not isinstance(a_bzrdir.transport, LocalTransport):
2784
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2785
if from_branch is not None:
2786
branch = from_branch
2788
branch = a_bzrdir.open_branch()
2789
if revision_id is None:
2790
revision_id = _mod_revision.ensure_null(branch.last_revision())
2793
branch.generate_revision_history(revision_id)
2797
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2803
basis_tree = branch.repository.revision_tree(revision_id)
2804
if basis_tree.inventory.root is not None:
2805
wt.set_root_id(basis_tree.get_root_id())
2806
# set the parent list and cache the basis tree.
2807
if _mod_revision.is_null(revision_id):
2810
parent_trees = [(revision_id, basis_tree)]
2811
wt.set_parent_trees(parent_trees)
2812
transform.build_tree(basis_tree, wt)
2816
super(WorkingTreeFormat2, self).__init__()
2817
self._matchingbzrdir = bzrdir.BzrDirFormat6()
2819
def open(self, a_bzrdir, _found=False):
2820
"""Return the WorkingTree object for a_bzrdir
2822
_found is a private parameter, do not use it. It is used to indicate
2823
if format probing has already been done.
2826
# we are being called directly and must probe.
2827
raise NotImplementedError
2828
if not isinstance(a_bzrdir.transport, LocalTransport):
2829
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2830
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2836
class WorkingTreeFormat3(WorkingTreeFormat):
2837
"""The second working tree format updated to record a format marker.
2840
- exists within a metadir controlling .bzr
2841
- includes an explicit version marker for the workingtree control
2842
files, separate from the BzrDir format
2843
- modifies the hash cache format
2845
- uses a LockDir to guard access for writes.
2848
upgrade_recommended = True
2850
def get_format_string(self):
2851
"""See WorkingTreeFormat.get_format_string()."""
2852
return "Bazaar-NG Working Tree format 3"
2854
def get_format_description(self):
2855
"""See WorkingTreeFormat.get_format_description()."""
2856
return "Working tree format 3"
2858
_lock_file_name = 'lock'
2859
_lock_class = LockDir
2861
_tree_class = WorkingTree3
2863
def __get_matchingbzrdir(self):
2864
return bzrdir.BzrDirMetaFormat1()
2866
_matchingbzrdir = property(__get_matchingbzrdir)
2868
def _open_control_files(self, a_bzrdir):
2869
transport = a_bzrdir.get_workingtree_transport(None)
2870
return LockableFiles(transport, self._lock_file_name,
2873
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2874
accelerator_tree=None, hardlink=False):
2875
"""See WorkingTreeFormat.initialize().
2877
:param revision_id: if supplied, create a working tree at a different
2878
revision than the branch is at.
2879
:param accelerator_tree: A tree which can be used for retrieving file
2880
contents more quickly than the revision tree, i.e. a workingtree.
2881
The revision tree will be used for cases where accelerator_tree's
2882
content is different.
2883
:param hardlink: If true, hard-link files from accelerator_tree,
2886
if not isinstance(a_bzrdir.transport, LocalTransport):
2887
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2888
transport = a_bzrdir.get_workingtree_transport(self)
2889
control_files = self._open_control_files(a_bzrdir)
2890
control_files.create_lock()
2891
control_files.lock_write()
2892
control_files.put_utf8('format', self.get_format_string())
2893
if from_branch is not None:
2894
branch = from_branch
2896
branch = a_bzrdir.open_branch()
2897
if revision_id is None:
2898
revision_id = _mod_revision.ensure_null(branch.last_revision())
2899
# WorkingTree3 can handle an inventory which has a unique root id.
2900
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2901
# those trees. And because there isn't a format bump inbetween, we
2902
# are maintaining compatibility with older clients.
2903
# inv = Inventory(root_id=gen_root_id())
2904
inv = self._initial_inventory()
2905
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
2911
_control_files=control_files)
2912
wt.lock_tree_write()
2914
basis_tree = branch.repository.revision_tree(revision_id)
2915
# only set an explicit root id if there is one to set.
2916
if basis_tree.inventory.root is not None:
2917
wt.set_root_id(basis_tree.get_root_id())
2918
if revision_id == NULL_REVISION:
2919
wt.set_parent_trees([])
2921
wt.set_parent_trees([(revision_id, basis_tree)])
2922
transform.build_tree(basis_tree, wt)
2924
# Unlock in this order so that the unlock-triggers-flush in
2925
# WorkingTree is given a chance to fire.
2926
control_files.unlock()
2930
def _initial_inventory(self):
2934
super(WorkingTreeFormat3, self).__init__()
2936
def open(self, a_bzrdir, _found=False):
2937
"""Return the WorkingTree object for a_bzrdir
2939
_found is a private parameter, do not use it. It is used to indicate
2940
if format probing has already been done.
2943
# we are being called directly and must probe.
2944
raise NotImplementedError
2945
if not isinstance(a_bzrdir.transport, LocalTransport):
2946
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2947
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
2950
def _open(self, a_bzrdir, control_files):
2951
"""Open the tree itself.
2953
:param a_bzrdir: the dir for the tree.
2954
:param control_files: the control files for the tree.
2956
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
2960
_control_files=control_files)
2963
return self.get_format_string()
2966
__default_format = WorkingTreeFormat4()
2967
WorkingTreeFormat.register_format(__default_format)
2968
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2969
WorkingTreeFormat.set_default_format(__default_format)
2970
# formats which have no format string are not discoverable
2971
# and not independently creatable, so are not registered.
2972
_legacy_formats = [WorkingTreeFormat2(),