1
# Copyright (C) 2005-2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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).
33
from cStringIO import StringIO
37
from bzrlib.lazy_import import lazy_import
38
lazy_import(globals(), """
39
from bisect import bisect_left
51
conflicts as _mod_conflicts,
60
revision as _mod_revision,
70
from bzrlib.workingtree_4 import (
77
from bzrlib import symbol_versioning
78
from bzrlib.decorators import needs_read_lock, needs_write_lock
79
from bzrlib.lock import LogicalLockResult
80
from bzrlib.lockable_files import LockableFiles
81
from bzrlib.lockdir import LockDir
82
import bzrlib.mutabletree
83
from bzrlib.mutabletree import needs_tree_write_lock
84
from bzrlib import osutils
85
from bzrlib.osutils import (
95
from bzrlib.filters import filtered_input_file
96
from bzrlib.trace import mutter, note
97
from bzrlib.transport.local import LocalTransport
98
from bzrlib.revision import CURRENT_REVISION
99
from bzrlib.rio import RioReader, rio_file, Stanza
100
from bzrlib.symbol_versioning import (
102
DEPRECATED_PARAMETER,
106
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
107
# TODO: Modifying the conflict objects or their type is currently nearly
108
# impossible as there is no clear relationship between the working tree format
109
# and the conflict list file format.
110
CONFLICT_HEADER_1 = "BZR conflict list format 1"
112
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
115
class TreeEntry(object):
116
"""An entry that implements the minimum interface used by commands.
118
This needs further inspection, it may be better to have
119
InventoryEntries without ids - though that seems wrong. For now,
120
this is a parallel hierarchy to InventoryEntry, and needs to become
121
one of several things: decorates to that hierarchy, children of, or
123
Another note is that these objects are currently only used when there is
124
no InventoryEntry available - i.e. for unversioned objects.
125
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
128
def __eq__(self, other):
129
# yes, this us ugly, TODO: best practice __eq__ style.
130
return (isinstance(other, TreeEntry)
131
and other.__class__ == self.__class__)
133
def kind_character(self):
137
class TreeDirectory(TreeEntry):
138
"""See TreeEntry. This is a directory in a working tree."""
140
def __eq__(self, other):
141
return (isinstance(other, TreeDirectory)
142
and other.__class__ == self.__class__)
144
def kind_character(self):
148
class TreeFile(TreeEntry):
149
"""See TreeEntry. This is a regular file in a working tree."""
151
def __eq__(self, other):
152
return (isinstance(other, TreeFile)
153
and other.__class__ == self.__class__)
155
def kind_character(self):
159
class TreeLink(TreeEntry):
160
"""See TreeEntry. This is a symlink in a working tree."""
162
def __eq__(self, other):
163
return (isinstance(other, TreeLink)
164
and other.__class__ == self.__class__)
166
def kind_character(self):
170
class WorkingTree(bzrlib.mutabletree.MutableTree,
171
bzrdir.ControlComponent):
172
"""Working copy tree.
174
The inventory is held in the `Branch` working-inventory, and the
175
files are in a directory on disk.
177
It is possible for a `WorkingTree` to have a filename which is
178
not listed in the Inventory and vice versa.
180
:ivar basedir: The root of the tree on disk. This is a unicode path object
181
(as opposed to a URL).
184
# override this to set the strategy for storing views
185
def _make_views(self):
186
return views.DisabledViews(self)
188
def __init__(self, basedir='.',
189
branch=DEPRECATED_PARAMETER,
195
"""Construct a WorkingTree instance. This is not a public API.
197
:param branch: A branch to override probing for the branch.
199
self._format = _format
200
self.bzrdir = _bzrdir
202
raise errors.BzrError("Please use bzrdir.open_workingtree or "
203
"WorkingTree.open() to obtain a WorkingTree.")
204
basedir = safe_unicode(basedir)
205
mutter("opening working tree %r", basedir)
206
if deprecated_passed(branch):
207
self._branch = branch
209
self._branch = self.bzrdir.open_branch()
210
self.basedir = realpath(basedir)
211
# if branch is at our basedir and is a format 6 or less
212
if isinstance(self._format, WorkingTreeFormat2):
213
# share control object
214
self._control_files = self.branch.control_files
216
# assume all other formats have their own control files.
217
self._control_files = _control_files
218
self._transport = self._control_files._transport
219
# update the whole cache up front and write to disk if anything changed;
220
# in the future we might want to do this more selectively
221
# two possible ways offer themselves : in self._unlock, write the cache
222
# if needed, or, when the cache sees a change, append it to the hash
223
# cache file, and have the parser take the most recent entry for a
225
wt_trans = self.bzrdir.get_workingtree_transport(None)
226
cache_filename = wt_trans.local_abspath('stat-cache')
227
self._hashcache = hashcache.HashCache(basedir, cache_filename,
228
self.bzrdir._get_file_mode(),
229
self._content_filter_stack_provider())
232
# is this scan needed ? it makes things kinda slow.
239
if _inventory is None:
240
# This will be acquired on lock_read() or lock_write()
241
self._inventory_is_modified = False
242
self._inventory = None
244
# the caller of __init__ has provided an inventory,
245
# we assume they know what they are doing - as its only
246
# the Format factory and creation methods that are
247
# permitted to do this.
248
self._set_inventory(_inventory, dirty=False)
249
self._detect_case_handling()
250
self._rules_searcher = None
251
self.views = self._make_views()
254
def user_transport(self):
255
return self.bzrdir.user_transport
258
def control_transport(self):
259
return self._transport
261
def _detect_case_handling(self):
262
wt_trans = self.bzrdir.get_workingtree_transport(None)
264
wt_trans.stat("FoRMaT")
265
except errors.NoSuchFile:
266
self.case_sensitive = True
268
self.case_sensitive = False
270
self._setup_directory_is_tree_reference()
273
fget=lambda self: self._branch,
274
doc="""The branch this WorkingTree is connected to.
276
This cannot be set - it is reflective of the actual disk structure
277
the working tree has been constructed from.
280
def break_lock(self):
281
"""Break a lock if one is present from another instance.
283
Uses the ui factory to ask for confirmation if the lock may be from
286
This will probe the repository for its lock as well.
288
self._control_files.break_lock()
289
self.branch.break_lock()
291
def _get_check_refs(self):
292
"""Return the references needed to perform a check of this tree.
294
The default implementation returns no refs, and is only suitable for
295
trees that have no local caching and can commit on ghosts at any time.
297
:seealso: bzrlib.check for details about check_refs.
301
def requires_rich_root(self):
302
return self._format.requires_rich_root
304
def supports_tree_reference(self):
307
def supports_content_filtering(self):
308
return self._format.supports_content_filtering()
310
def supports_views(self):
311
return self.views.supports_views()
313
def _set_inventory(self, inv, dirty):
314
"""Set the internal cached inventory.
316
:param inv: The inventory to set.
317
:param dirty: A boolean indicating whether the inventory is the same
318
logical inventory as whats on disk. If True the inventory is not
319
the same and should be written to disk or data will be lost, if
320
False then the inventory is the same as that on disk and any
321
serialisation would be unneeded overhead.
323
self._inventory = inv
324
self._inventory_is_modified = dirty
327
def open(path=None, _unsupported=False):
328
"""Open an existing working tree at path.
332
path = osutils.getcwd()
333
control = bzrdir.BzrDir.open(path, _unsupported)
334
return control.open_workingtree(_unsupported)
337
def open_containing(path=None):
338
"""Open an existing working tree which has its root about path.
340
This probes for a working tree at path and searches upwards from there.
342
Basically we keep looking up until we find the control directory or
343
run into /. If there isn't one, raises NotBranchError.
344
TODO: give this a new exception.
345
If there is one, it is returned, along with the unused portion of path.
347
:return: The WorkingTree that contains 'path', and the rest of path
350
path = osutils.getcwd()
351
control, relpath = bzrdir.BzrDir.open_containing(path)
352
return control.open_workingtree(), relpath
355
def open_containing_paths(file_list, default_directory='.',
356
canonicalize=True, apply_view=True):
357
"""Open the WorkingTree that contains a set of paths.
359
Fail if the paths given are not all in a single tree.
361
This is used for the many command-line interfaces that take a list of
362
any number of files and that require they all be in the same tree.
364
# recommended replacement for builtins.internal_tree_files
365
if file_list is None or len(file_list) == 0:
366
tree = WorkingTree.open_containing(default_directory)[0]
367
if tree.supports_views() and apply_view:
368
view_files = tree.views.lookup_view()
370
file_list = view_files
371
view_str = views.view_display_str(view_files)
372
note("Ignoring files outside view. View is %s" % view_str)
373
return tree, file_list
374
tree = WorkingTree.open_containing(file_list[0])[0]
375
return tree, tree.safe_relpath_files(file_list, canonicalize,
376
apply_view=apply_view)
378
def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
379
"""Convert file_list into a list of relpaths in tree.
381
:param self: A tree to operate on.
382
:param file_list: A list of user provided paths or None.
383
:param apply_view: if True and a view is set, apply it or check that
384
specified files are within it
385
:return: A list of relative paths.
386
:raises errors.PathNotChild: When a provided path is in a different self
389
if file_list is None:
391
if self.supports_views() and apply_view:
392
view_files = self.views.lookup_view()
396
# self.relpath exists as a "thunk" to osutils, but canonical_relpath
397
# doesn't - fix that up here before we enter the loop.
399
fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
402
for filename in file_list:
403
relpath = fixer(osutils.dereference_path(filename))
404
if view_files and not osutils.is_inside_any(view_files, relpath):
405
raise errors.FileOutsideView(filename, view_files)
406
new_list.append(relpath)
410
def open_downlevel(path=None):
411
"""Open an unsupported working tree.
413
Only intended for advanced situations like upgrading part of a bzrdir.
415
return WorkingTree.open(path, _unsupported=True)
418
def find_trees(location):
419
def list_current(transport):
420
return [d for d in transport.list_dir('') if d != '.bzr']
421
def evaluate(bzrdir):
423
tree = bzrdir.open_workingtree()
424
except errors.NoWorkingTree:
428
t = transport.get_transport(location)
429
iterator = bzrdir.BzrDir.find_bzrdirs(t, evaluate=evaluate,
430
list_current=list_current)
431
return [tr for tr in iterator if tr is not None]
433
# should be deprecated - this is slow and in any case treating them as a
434
# container is (we now know) bad style -- mbp 20070302
435
## @deprecated_method(zero_fifteen)
437
"""Iterate through file_ids for this tree.
439
file_ids are in a WorkingTree if they are in the working inventory
440
and the working file exists.
442
inv = self._inventory
443
for path, ie in inv.iter_entries():
444
if osutils.lexists(self.abspath(path)):
447
def all_file_ids(self):
448
"""See Tree.iter_all_file_ids"""
449
return set(self.inventory)
452
return "<%s of %s>" % (self.__class__.__name__,
453
getattr(self, 'basedir', None))
455
def abspath(self, filename):
456
return pathjoin(self.basedir, filename)
458
def basis_tree(self):
459
"""Return RevisionTree for the current last revision.
461
If the left most parent is a ghost then the returned tree will be an
462
empty tree - one obtained by calling
463
repository.revision_tree(NULL_REVISION).
466
revision_id = self.get_parent_ids()[0]
468
# no parents, return an empty revision tree.
469
# in the future this should return the tree for
470
# 'empty:' - the implicit root empty tree.
471
return self.branch.repository.revision_tree(
472
_mod_revision.NULL_REVISION)
474
return self.revision_tree(revision_id)
475
except errors.NoSuchRevision:
477
# No cached copy available, retrieve from the repository.
478
# FIXME? RBC 20060403 should we cache the inventory locally
481
return self.branch.repository.revision_tree(revision_id)
482
except (errors.RevisionNotPresent, errors.NoSuchRevision):
483
# the basis tree *may* be a ghost or a low level error may have
484
# occurred. If the revision is present, its a problem, if its not
486
if self.branch.repository.has_revision(revision_id):
488
# the basis tree is a ghost so return an empty tree.
489
return self.branch.repository.revision_tree(
490
_mod_revision.NULL_REVISION)
493
self._flush_ignore_list_cache()
495
def relpath(self, path):
496
"""Return the local path portion from a given path.
498
The path may be absolute or relative. If its a relative path it is
499
interpreted relative to the python current working directory.
501
return osutils.relpath(self.basedir, path)
503
def has_filename(self, filename):
504
return osutils.lexists(self.abspath(filename))
506
def get_file(self, file_id, path=None, filtered=True):
507
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
509
def get_file_with_stat(self, file_id, path=None, filtered=True,
511
"""See Tree.get_file_with_stat."""
513
path = self.id2path(file_id)
514
file_obj = self.get_file_byname(path, filtered=False)
515
stat_value = _fstat(file_obj.fileno())
516
if filtered and self.supports_content_filtering():
517
filters = self._content_filter_stack(path)
518
file_obj = filtered_input_file(file_obj, filters)
519
return (file_obj, stat_value)
521
def get_file_text(self, file_id, path=None, filtered=True):
522
my_file = self.get_file(file_id, path=path, filtered=filtered)
524
return my_file.read()
528
def get_file_byname(self, filename, filtered=True):
529
path = self.abspath(filename)
531
if filtered and self.supports_content_filtering():
532
filters = self._content_filter_stack(filename)
533
return filtered_input_file(f, filters)
537
def get_file_lines(self, file_id, path=None, filtered=True):
538
"""See Tree.get_file_lines()"""
539
file = self.get_file(file_id, path, filtered=filtered)
541
return file.readlines()
546
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
547
"""See Tree.annotate_iter
549
This implementation will use the basis tree implementation if possible.
550
Lines not in the basis are attributed to CURRENT_REVISION
552
If there are pending merges, lines added by those merges will be
553
incorrectly attributed to CURRENT_REVISION (but after committing, the
554
attribution will be correct).
556
maybe_file_parent_keys = []
557
for parent_id in self.get_parent_ids():
559
parent_tree = self.revision_tree(parent_id)
560
except errors.NoSuchRevisionInTree:
561
parent_tree = self.branch.repository.revision_tree(parent_id)
562
parent_tree.lock_read()
564
if file_id not in parent_tree:
566
ie = parent_tree.inventory[file_id]
567
if ie.kind != 'file':
568
# Note: this is slightly unnecessary, because symlinks and
569
# directories have a "text" which is the empty text, and we
570
# know that won't mess up annotations. But it seems cleaner
572
parent_text_key = (file_id, ie.revision)
573
if parent_text_key not in maybe_file_parent_keys:
574
maybe_file_parent_keys.append(parent_text_key)
577
graph = _mod_graph.Graph(self.branch.repository.texts)
578
heads = graph.heads(maybe_file_parent_keys)
579
file_parent_keys = []
580
for key in maybe_file_parent_keys:
582
file_parent_keys.append(key)
584
# Now we have the parents of this content
585
annotator = self.branch.repository.texts.get_annotator()
586
text = self.get_file_text(file_id)
587
this_key =(file_id, default_revision)
588
annotator.add_special_text(this_key, file_parent_keys, text)
589
annotations = [(key[-1], line)
590
for key, line in annotator.annotate_flat(this_key)]
593
def _get_ancestors(self, default_revision):
594
ancestors = set([default_revision])
595
for parent_id in self.get_parent_ids():
596
ancestors.update(self.branch.repository.get_ancestry(
597
parent_id, topo_sorted=False))
600
def get_parent_ids(self):
601
"""See Tree.get_parent_ids.
603
This implementation reads the pending merges list and last_revision
604
value and uses that to decide what the parents list should be.
606
last_rev = _mod_revision.ensure_null(self._last_revision())
607
if _mod_revision.NULL_REVISION == last_rev:
612
merges_bytes = self._transport.get_bytes('pending-merges')
613
except errors.NoSuchFile:
616
for l in osutils.split_lines(merges_bytes):
617
revision_id = l.rstrip('\n')
618
parents.append(revision_id)
622
def get_root_id(self):
623
"""Return the id of this trees root"""
624
return self._inventory.root.file_id
626
def _get_store_filename(self, file_id):
627
## XXX: badly named; this is not in the store at all
628
return self.abspath(self.id2path(file_id))
631
def clone(self, to_bzrdir, revision_id=None):
632
"""Duplicate this working tree into to_bzr, including all state.
634
Specifically modified files are kept as modified, but
635
ignored and unknown files are discarded.
637
If you want to make a new line of development, see bzrdir.sprout()
640
If not None, the cloned tree will have its last revision set to
641
revision, and difference between the source trees last revision
642
and this one merged in.
644
# assumes the target bzr dir format is compatible.
645
result = to_bzrdir.create_workingtree()
646
self.copy_content_into(result, revision_id)
650
def copy_content_into(self, tree, revision_id=None):
651
"""Copy the current content and user files of this tree into tree."""
652
tree.set_root_id(self.get_root_id())
653
if revision_id is None:
654
merge.transform_tree(tree, self)
656
# TODO now merge from tree.last_revision to revision (to preserve
657
# user local changes)
658
merge.transform_tree(tree, self)
659
tree.set_parent_ids([revision_id])
661
def id2abspath(self, file_id):
662
return self.abspath(self.id2path(file_id))
664
def has_id(self, file_id):
665
# files that have been deleted are excluded
667
if not inv.has_id(file_id):
669
path = inv.id2path(file_id)
670
return osutils.lexists(self.abspath(path))
672
def has_or_had_id(self, file_id):
673
if file_id == self.inventory.root.file_id:
675
return self.inventory.has_id(file_id)
677
__contains__ = has_id
679
def get_file_size(self, file_id):
680
"""See Tree.get_file_size"""
681
# XXX: this returns the on-disk size; it should probably return the
684
return os.path.getsize(self.id2abspath(file_id))
686
if e.errno != errno.ENOENT:
692
def get_file_sha1(self, file_id, path=None, stat_value=None):
694
path = self._inventory.id2path(file_id)
695
return self._hashcache.get_sha1(path, stat_value)
697
def get_file_mtime(self, file_id, path=None):
699
path = self.inventory.id2path(file_id)
700
return os.lstat(self.abspath(path)).st_mtime
702
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
703
file_id = self.path2id(path)
705
# For unversioned files on win32, we just assume they are not
708
return self._inventory[file_id].executable
710
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
711
mode = stat_result.st_mode
712
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
714
if not supports_executable():
715
def is_executable(self, file_id, path=None):
716
return self._inventory[file_id].executable
718
_is_executable_from_path_and_stat = \
719
_is_executable_from_path_and_stat_from_basis
721
def is_executable(self, file_id, path=None):
723
path = self.id2path(file_id)
724
mode = os.lstat(self.abspath(path)).st_mode
725
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
727
_is_executable_from_path_and_stat = \
728
_is_executable_from_path_and_stat_from_stat
730
@needs_tree_write_lock
731
def _add(self, files, ids, kinds):
732
"""See MutableTree._add."""
733
# TODO: Re-adding a file that is removed in the working copy
734
# should probably put it back with the previous ID.
735
# the read and write working inventory should not occur in this
736
# function - they should be part of lock_write and unlock.
738
for f, file_id, kind in zip(files, ids, kinds):
740
inv.add_path(f, kind=kind)
742
inv.add_path(f, kind=kind, file_id=file_id)
743
self._inventory_is_modified = True
745
@needs_tree_write_lock
746
def _gather_kinds(self, files, kinds):
747
"""See MutableTree._gather_kinds."""
748
for pos, f in enumerate(files):
749
if kinds[pos] is None:
750
fullpath = normpath(self.abspath(f))
752
kinds[pos] = file_kind(fullpath)
754
if e.errno == errno.ENOENT:
755
raise errors.NoSuchFile(fullpath)
758
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
759
"""Add revision_id as a parent.
761
This is equivalent to retrieving the current list of parent ids
762
and setting the list to its value plus revision_id.
764
:param revision_id: The revision id to add to the parent list. It may
765
be a ghost revision as long as its not the first parent to be added,
766
or the allow_leftmost_as_ghost parameter is set True.
767
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
769
parents = self.get_parent_ids() + [revision_id]
770
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
771
or allow_leftmost_as_ghost)
773
@needs_tree_write_lock
774
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
775
"""Add revision_id, tree tuple as a parent.
777
This is equivalent to retrieving the current list of parent trees
778
and setting the list to its value plus parent_tuple. See also
779
add_parent_tree_id - if you only have a parent id available it will be
780
simpler to use that api. If you have the parent already available, using
781
this api is preferred.
783
:param parent_tuple: The (revision id, tree) to add to the parent list.
784
If the revision_id is a ghost, pass None for the tree.
785
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
787
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
788
if len(parent_ids) > 1:
789
# the leftmost may have already been a ghost, preserve that if it
791
allow_leftmost_as_ghost = True
792
self.set_parent_ids(parent_ids,
793
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
795
@needs_tree_write_lock
796
def add_pending_merge(self, *revision_ids):
797
# TODO: Perhaps should check at this point that the
798
# history of the revision is actually present?
799
parents = self.get_parent_ids()
801
for rev_id in revision_ids:
802
if rev_id in parents:
804
parents.append(rev_id)
807
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
809
def path_content_summary(self, path, _lstat=os.lstat,
810
_mapper=osutils.file_kind_from_stat_mode):
811
"""See Tree.path_content_summary."""
812
abspath = self.abspath(path)
814
stat_result = _lstat(abspath)
816
if getattr(e, 'errno', None) == errno.ENOENT:
818
return ('missing', None, None, None)
819
# propagate other errors
821
kind = _mapper(stat_result.st_mode)
823
return self._file_content_summary(path, stat_result)
824
elif kind == 'directory':
825
# perhaps it looks like a plain directory, but it's really a
827
if self._directory_is_tree_reference(path):
828
kind = 'tree-reference'
829
return kind, None, None, None
830
elif kind == 'symlink':
831
target = osutils.readlink(abspath)
832
return ('symlink', None, None, target)
834
return (kind, None, None, None)
836
def _file_content_summary(self, path, stat_result):
837
size = stat_result.st_size
838
executable = self._is_executable_from_path_and_stat(path, stat_result)
839
# try for a stat cache lookup
840
return ('file', size, executable, self._sha_from_stat(
843
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
844
"""Common ghost checking functionality from set_parent_*.
846
This checks that the left hand-parent exists if there are any
849
if len(revision_ids) > 0:
850
leftmost_id = revision_ids[0]
851
if (not allow_leftmost_as_ghost and not
852
self.branch.repository.has_revision(leftmost_id)):
853
raise errors.GhostRevisionUnusableHere(leftmost_id)
855
def _set_merges_from_parent_ids(self, parent_ids):
856
merges = parent_ids[1:]
857
self._transport.put_bytes('pending-merges', '\n'.join(merges),
858
mode=self.bzrdir._get_file_mode())
860
def _filter_parent_ids_by_ancestry(self, revision_ids):
861
"""Check that all merged revisions are proper 'heads'.
863
This will always return the first revision_id, and any merged revisions
866
if len(revision_ids) == 0:
868
graph = self.branch.repository.get_graph()
869
heads = graph.heads(revision_ids)
870
new_revision_ids = revision_ids[:1]
871
for revision_id in revision_ids[1:]:
872
if revision_id in heads and revision_id not in new_revision_ids:
873
new_revision_ids.append(revision_id)
874
if new_revision_ids != revision_ids:
875
trace.mutter('requested to set revision_ids = %s,'
876
' but filtered to %s', revision_ids, new_revision_ids)
877
return new_revision_ids
879
@needs_tree_write_lock
880
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
881
"""Set the parent ids to revision_ids.
883
See also set_parent_trees. This api will try to retrieve the tree data
884
for each element of revision_ids from the trees repository. If you have
885
tree data already available, it is more efficient to use
886
set_parent_trees rather than set_parent_ids. set_parent_ids is however
887
an easier API to use.
889
:param revision_ids: The revision_ids to set as the parent ids of this
890
working tree. Any of these may be ghosts.
892
self._check_parents_for_ghosts(revision_ids,
893
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
894
for revision_id in revision_ids:
895
_mod_revision.check_not_reserved_id(revision_id)
897
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
899
if len(revision_ids) > 0:
900
self.set_last_revision(revision_ids[0])
902
self.set_last_revision(_mod_revision.NULL_REVISION)
904
self._set_merges_from_parent_ids(revision_ids)
906
@needs_tree_write_lock
907
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
908
"""See MutableTree.set_parent_trees."""
909
parent_ids = [rev for (rev, tree) in parents_list]
910
for revision_id in parent_ids:
911
_mod_revision.check_not_reserved_id(revision_id)
913
self._check_parents_for_ghosts(parent_ids,
914
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
916
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
918
if len(parent_ids) == 0:
919
leftmost_parent_id = _mod_revision.NULL_REVISION
920
leftmost_parent_tree = None
922
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
924
if self._change_last_revision(leftmost_parent_id):
925
if leftmost_parent_tree is None:
926
# If we don't have a tree, fall back to reading the
927
# parent tree from the repository.
928
self._cache_basis_inventory(leftmost_parent_id)
930
inv = leftmost_parent_tree.inventory
931
xml = self._create_basis_xml_from_inventory(
932
leftmost_parent_id, inv)
933
self._write_basis_inventory(xml)
934
self._set_merges_from_parent_ids(parent_ids)
936
@needs_tree_write_lock
937
def set_pending_merges(self, rev_list):
938
parents = self.get_parent_ids()
939
leftmost = parents[:1]
940
new_parents = leftmost + rev_list
941
self.set_parent_ids(new_parents)
943
@needs_tree_write_lock
944
def set_merge_modified(self, modified_hashes):
946
for file_id, hash in modified_hashes.iteritems():
947
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
948
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
950
def _sha_from_stat(self, path, stat_result):
951
"""Get a sha digest from the tree's stat cache.
953
The default implementation assumes no stat cache is present.
955
:param path: The path.
956
:param stat_result: The stat result being looked up.
960
def _put_rio(self, filename, stanzas, header):
961
self._must_be_locked()
962
my_file = rio_file(stanzas, header)
963
self._transport.put_file(filename, my_file,
964
mode=self.bzrdir._get_file_mode())
966
@needs_write_lock # because merge pulls data into the branch.
967
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
968
merge_type=None, force=False):
969
"""Merge from a branch into this working tree.
971
:param branch: The branch to merge from.
972
:param to_revision: If non-None, the merge will merge to to_revision,
973
but not beyond it. to_revision does not need to be in the history
974
of the branch when it is supplied. If None, to_revision defaults to
975
branch.last_revision().
977
from bzrlib.merge import Merger, Merge3Merger
978
merger = Merger(self.branch, this_tree=self)
979
# check that there are no local alterations
980
if not force and self.has_changes():
981
raise errors.UncommittedChanges(self)
982
if to_revision is None:
983
to_revision = _mod_revision.ensure_null(branch.last_revision())
984
merger.other_rev_id = to_revision
985
if _mod_revision.is_null(merger.other_rev_id):
986
raise errors.NoCommits(branch)
987
self.branch.fetch(branch, last_revision=merger.other_rev_id)
988
merger.other_basis = merger.other_rev_id
989
merger.other_tree = self.branch.repository.revision_tree(
991
merger.other_branch = branch
992
if from_revision is None:
995
merger.set_base_revision(from_revision, branch)
996
if merger.base_rev_id == merger.other_rev_id:
997
raise errors.PointlessMerge
998
merger.backup_files = False
999
if merge_type is None:
1000
merger.merge_type = Merge3Merger
1002
merger.merge_type = merge_type
1003
merger.set_interesting_files(None)
1004
merger.show_base = False
1005
merger.reprocess = False
1006
conflicts = merger.do_merge()
1007
merger.set_pending()
1011
def merge_modified(self):
1012
"""Return a dictionary of files modified by a merge.
1014
The list is initialized by WorkingTree.set_merge_modified, which is
1015
typically called after we make some automatic updates to the tree
1018
This returns a map of file_id->sha1, containing only files which are
1019
still in the working inventory and have that text hash.
1022
hashfile = self._transport.get('merge-hashes')
1023
except errors.NoSuchFile:
1028
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
1029
raise errors.MergeModifiedFormatError()
1030
except StopIteration:
1031
raise errors.MergeModifiedFormatError()
1032
for s in RioReader(hashfile):
1033
# RioReader reads in Unicode, so convert file_ids back to utf8
1034
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
1035
if file_id not in self.inventory:
1037
text_hash = s.get("hash")
1038
if text_hash == self.get_file_sha1(file_id):
1039
merge_hashes[file_id] = text_hash
1045
def mkdir(self, path, file_id=None):
1046
"""See MutableTree.mkdir()."""
1048
file_id = generate_ids.gen_file_id(os.path.basename(path))
1049
os.mkdir(self.abspath(path))
1050
self.add(path, file_id, 'directory')
1053
def get_symlink_target(self, file_id):
1054
abspath = self.id2abspath(file_id)
1055
target = osutils.readlink(abspath)
1059
def subsume(self, other_tree):
1060
def add_children(inventory, entry):
1061
for child_entry in entry.children.values():
1062
inventory._byid[child_entry.file_id] = child_entry
1063
if child_entry.kind == 'directory':
1064
add_children(inventory, child_entry)
1065
if other_tree.get_root_id() == self.get_root_id():
1066
raise errors.BadSubsumeSource(self, other_tree,
1067
'Trees have the same root')
1069
other_tree_path = self.relpath(other_tree.basedir)
1070
except errors.PathNotChild:
1071
raise errors.BadSubsumeSource(self, other_tree,
1072
'Tree is not contained by the other')
1073
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
1074
if new_root_parent is None:
1075
raise errors.BadSubsumeSource(self, other_tree,
1076
'Parent directory is not versioned.')
1077
# We need to ensure that the result of a fetch will have a
1078
# versionedfile for the other_tree root, and only fetching into
1079
# RepositoryKnit2 guarantees that.
1080
if not self.branch.repository.supports_rich_root():
1081
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
1082
other_tree.lock_tree_write()
1084
new_parents = other_tree.get_parent_ids()
1085
other_root = other_tree.inventory.root
1086
other_root.parent_id = new_root_parent
1087
other_root.name = osutils.basename(other_tree_path)
1088
self.inventory.add(other_root)
1089
add_children(self.inventory, other_root)
1090
self._write_inventory(self.inventory)
1091
# normally we don't want to fetch whole repositories, but i think
1092
# here we really do want to consolidate the whole thing.
1093
for parent_id in other_tree.get_parent_ids():
1094
self.branch.fetch(other_tree.branch, parent_id)
1095
self.add_parent_tree_id(parent_id)
1098
other_tree.bzrdir.retire_bzrdir()
1100
def _setup_directory_is_tree_reference(self):
1101
if self._branch.repository._format.supports_tree_reference:
1102
self._directory_is_tree_reference = \
1103
self._directory_may_be_tree_reference
1105
self._directory_is_tree_reference = \
1106
self._directory_is_never_tree_reference
1108
def _directory_is_never_tree_reference(self, relpath):
1111
def _directory_may_be_tree_reference(self, relpath):
1112
# as a special case, if a directory contains control files then
1113
# it's a tree reference, except that the root of the tree is not
1114
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1115
# TODO: We could ask all the control formats whether they
1116
# recognize this directory, but at the moment there's no cheap api
1117
# to do that. Since we probably can only nest bzr checkouts and
1118
# they always use this name it's ok for now. -- mbp 20060306
1120
# FIXME: There is an unhandled case here of a subdirectory
1121
# containing .bzr but not a branch; that will probably blow up
1122
# when you try to commit it. It might happen if there is a
1123
# checkout in a subdirectory. This can be avoided by not adding
1126
@needs_tree_write_lock
1127
def extract(self, file_id, format=None):
1128
"""Extract a subtree from this tree.
1130
A new branch will be created, relative to the path for this tree.
1134
segments = osutils.splitpath(path)
1135
transport = self.branch.bzrdir.root_transport
1136
for name in segments:
1137
transport = transport.clone(name)
1138
transport.ensure_base()
1141
sub_path = self.id2path(file_id)
1142
branch_transport = mkdirs(sub_path)
1144
format = self.bzrdir.cloning_metadir()
1145
branch_transport.ensure_base()
1146
branch_bzrdir = format.initialize_on_transport(branch_transport)
1148
repo = branch_bzrdir.find_repository()
1149
except errors.NoRepositoryPresent:
1150
repo = branch_bzrdir.create_repository()
1151
if not repo.supports_rich_root():
1152
raise errors.RootNotRich()
1153
new_branch = branch_bzrdir.create_branch()
1154
new_branch.pull(self.branch)
1155
for parent_id in self.get_parent_ids():
1156
new_branch.fetch(self.branch, parent_id)
1157
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1158
if tree_transport.base != branch_transport.base:
1159
tree_bzrdir = format.initialize_on_transport(tree_transport)
1160
branch.BranchReferenceFormat().initialize(tree_bzrdir,
1161
target_branch=new_branch)
1163
tree_bzrdir = branch_bzrdir
1164
wt = tree_bzrdir.create_workingtree(_mod_revision.NULL_REVISION)
1165
wt.set_parent_ids(self.get_parent_ids())
1166
my_inv = self.inventory
1167
child_inv = inventory.Inventory(root_id=None)
1168
new_root = my_inv[file_id]
1169
my_inv.remove_recursive_id(file_id)
1170
new_root.parent_id = None
1171
child_inv.add(new_root)
1172
self._write_inventory(my_inv)
1173
wt._write_inventory(child_inv)
1176
def _serialize(self, inventory, out_file):
1177
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1180
def _deserialize(selt, in_file):
1181
return xml5.serializer_v5.read_inventory(in_file)
1184
"""Write the in memory inventory to disk."""
1185
# TODO: Maybe this should only write on dirty ?
1186
if self._control_files._lock_mode != 'w':
1187
raise errors.NotWriteLocked(self)
1189
self._serialize(self._inventory, sio)
1191
self._transport.put_file('inventory', sio,
1192
mode=self.bzrdir._get_file_mode())
1193
self._inventory_is_modified = False
1195
def _kind(self, relpath):
1196
return osutils.file_kind(self.abspath(relpath))
1198
def list_files(self, include_root=False, from_dir=None, recursive=True):
1199
"""List all files as (path, class, kind, id, entry).
1201
Lists, but does not descend into unversioned directories.
1202
This does not include files that have been deleted in this
1203
tree. Skips the control directory.
1205
:param include_root: if True, return an entry for the root
1206
:param from_dir: start from this directory or None for the root
1207
:param recursive: whether to recurse into subdirectories or not
1209
# list_files is an iterator, so @needs_read_lock doesn't work properly
1210
# with it. So callers should be careful to always read_lock the tree.
1211
if not self.is_locked():
1212
raise errors.ObjectNotLocked(self)
1214
inv = self.inventory
1215
if from_dir is None and include_root is True:
1216
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1217
# Convert these into local objects to save lookup times
1218
pathjoin = osutils.pathjoin
1219
file_kind = self._kind
1221
# transport.base ends in a slash, we want the piece
1222
# between the last two slashes
1223
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
1225
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1227
# directory file_id, relative path, absolute path, reverse sorted children
1228
if from_dir is not None:
1229
from_dir_id = inv.path2id(from_dir)
1230
if from_dir_id is None:
1231
# Directory not versioned
1233
from_dir_abspath = pathjoin(self.basedir, from_dir)
1235
from_dir_id = inv.root.file_id
1236
from_dir_abspath = self.basedir
1237
children = os.listdir(from_dir_abspath)
1239
# jam 20060527 The kernel sized tree seems equivalent whether we
1240
# use a deque and popleft to keep them sorted, or if we use a plain
1241
# list and just reverse() them.
1242
children = collections.deque(children)
1243
stack = [(from_dir_id, u'', from_dir_abspath, children)]
1245
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1248
f = children.popleft()
1249
## TODO: If we find a subdirectory with its own .bzr
1250
## directory, then that is a separate tree and we
1251
## should exclude it.
1253
# the bzrdir for this tree
1254
if transport_base_dir == f:
1257
# we know that from_dir_relpath and from_dir_abspath never end in a slash
1258
# and 'f' doesn't begin with one, we can do a string op, rather
1259
# than the checks of pathjoin(), all relative paths will have an extra slash
1261
fp = from_dir_relpath + '/' + f
1264
fap = from_dir_abspath + '/' + f
1266
f_ie = inv.get_child(from_dir_id, f)
1269
elif self.is_ignored(fp[1:]):
1272
# we may not have found this file, because of a unicode issue
1273
f_norm, can_access = osutils.normalized_filename(f)
1274
if f == f_norm or not can_access:
1275
# No change, so treat this file normally
1278
# this file can be accessed by a normalized path
1279
# check again if it is versioned
1280
# these lines are repeated here for performance
1282
fp = from_dir_relpath + '/' + f
1283
fap = from_dir_abspath + '/' + f
1284
f_ie = inv.get_child(from_dir_id, f)
1287
elif self.is_ignored(fp[1:]):
1294
# make a last minute entry
1296
yield fp[1:], c, fk, f_ie.file_id, f_ie
1299
yield fp[1:], c, fk, None, fk_entries[fk]()
1301
yield fp[1:], c, fk, None, TreeEntry()
1304
if fk != 'directory':
1307
# But do this child first if recursing down
1309
new_children = os.listdir(fap)
1311
new_children = collections.deque(new_children)
1312
stack.append((f_ie.file_id, fp, fap, new_children))
1313
# Break out of inner loop,
1314
# so that we start outer loop with child
1317
# if we finished all children, pop it off the stack
1320
@needs_tree_write_lock
1321
def move(self, from_paths, to_dir=None, after=False, **kwargs):
1324
to_dir must exist in the inventory.
1326
If to_dir exists and is a directory, the files are moved into
1327
it, keeping their old names.
1329
Note that to_dir is only the last component of the new name;
1330
this doesn't change the directory.
1332
For each entry in from_paths the move mode will be determined
1335
The first mode moves the file in the filesystem and updates the
1336
inventory. The second mode only updates the inventory without
1337
touching the file on the filesystem. This is the new mode introduced
1340
move uses the second mode if 'after == True' and the target is not
1341
versioned but present in the working tree.
1343
move uses the second mode if 'after == False' and the source is
1344
versioned but no longer in the working tree, and the target is not
1345
versioned but present in the working tree.
1347
move uses the first mode if 'after == False' and the source is
1348
versioned and present in the working tree, and the target is not
1349
versioned and not present in the working tree.
1351
Everything else results in an error.
1353
This returns a list of (from_path, to_path) pairs for each
1354
entry that is moved.
1359
# check for deprecated use of signature
1361
to_dir = kwargs.get('to_name', None)
1363
raise TypeError('You must supply a target directory')
1365
symbol_versioning.warn('The parameter to_name was deprecated'
1366
' in version 0.13. Use to_dir instead',
1369
# check destination directory
1370
if isinstance(from_paths, basestring):
1372
inv = self.inventory
1373
to_abs = self.abspath(to_dir)
1374
if not isdir(to_abs):
1375
raise errors.BzrMoveFailedError('',to_dir,
1376
errors.NotADirectory(to_abs))
1377
if not self.has_filename(to_dir):
1378
raise errors.BzrMoveFailedError('',to_dir,
1379
errors.NotInWorkingDirectory(to_dir))
1380
to_dir_id = inv.path2id(to_dir)
1381
if to_dir_id is None:
1382
raise errors.BzrMoveFailedError('',to_dir,
1383
errors.NotVersionedError(path=str(to_dir)))
1385
to_dir_ie = inv[to_dir_id]
1386
if to_dir_ie.kind != 'directory':
1387
raise errors.BzrMoveFailedError('',to_dir,
1388
errors.NotADirectory(to_abs))
1390
# create rename entries and tuples
1391
for from_rel in from_paths:
1392
from_tail = splitpath(from_rel)[-1]
1393
from_id = inv.path2id(from_rel)
1395
raise errors.BzrMoveFailedError(from_rel,to_dir,
1396
errors.NotVersionedError(path=str(from_rel)))
1398
from_entry = inv[from_id]
1399
from_parent_id = from_entry.parent_id
1400
to_rel = pathjoin(to_dir, from_tail)
1401
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1403
from_tail=from_tail,
1404
from_parent_id=from_parent_id,
1405
to_rel=to_rel, to_tail=from_tail,
1406
to_parent_id=to_dir_id)
1407
rename_entries.append(rename_entry)
1408
rename_tuples.append((from_rel, to_rel))
1410
# determine which move mode to use. checks also for movability
1411
rename_entries = self._determine_mv_mode(rename_entries, after)
1413
original_modified = self._inventory_is_modified
1416
self._inventory_is_modified = True
1417
self._move(rename_entries)
1419
# restore the inventory on error
1420
self._inventory_is_modified = original_modified
1422
self._write_inventory(inv)
1423
return rename_tuples
1425
def _determine_mv_mode(self, rename_entries, after=False):
1426
"""Determines for each from-to pair if both inventory and working tree
1427
or only the inventory has to be changed.
1429
Also does basic plausability tests.
1431
inv = self.inventory
1433
for rename_entry in rename_entries:
1434
# store to local variables for easier reference
1435
from_rel = rename_entry.from_rel
1436
from_id = rename_entry.from_id
1437
to_rel = rename_entry.to_rel
1438
to_id = inv.path2id(to_rel)
1439
only_change_inv = False
1441
# check the inventory for source and destination
1443
raise errors.BzrMoveFailedError(from_rel,to_rel,
1444
errors.NotVersionedError(path=str(from_rel)))
1445
if to_id is not None:
1446
raise errors.BzrMoveFailedError(from_rel,to_rel,
1447
errors.AlreadyVersionedError(path=str(to_rel)))
1449
# try to determine the mode for rename (only change inv or change
1450
# inv and file system)
1452
if not self.has_filename(to_rel):
1453
raise errors.BzrMoveFailedError(from_id,to_rel,
1454
errors.NoSuchFile(path=str(to_rel),
1455
extra="New file has not been created yet"))
1456
only_change_inv = True
1457
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1458
only_change_inv = True
1459
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1460
only_change_inv = False
1461
elif (not self.case_sensitive
1462
and from_rel.lower() == to_rel.lower()
1463
and self.has_filename(from_rel)):
1464
only_change_inv = False
1466
# something is wrong, so lets determine what exactly
1467
if not self.has_filename(from_rel) and \
1468
not self.has_filename(to_rel):
1469
raise errors.BzrRenameFailedError(from_rel,to_rel,
1470
errors.PathsDoNotExist(paths=(str(from_rel),
1473
raise errors.RenameFailedFilesExist(from_rel, to_rel)
1474
rename_entry.only_change_inv = only_change_inv
1475
return rename_entries
1477
def _move(self, rename_entries):
1478
"""Moves a list of files.
1480
Depending on the value of the flag 'only_change_inv', the
1481
file will be moved on the file system or not.
1483
inv = self.inventory
1486
for entry in rename_entries:
1488
self._move_entry(entry)
1490
self._rollback_move(moved)
1494
def _rollback_move(self, moved):
1495
"""Try to rollback a previous move in case of an filesystem error."""
1496
inv = self.inventory
1499
self._move_entry(WorkingTree._RenameEntry(
1500
entry.to_rel, entry.from_id,
1501
entry.to_tail, entry.to_parent_id, entry.from_rel,
1502
entry.from_tail, entry.from_parent_id,
1503
entry.only_change_inv))
1504
except errors.BzrMoveFailedError, e:
1505
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
1506
" The working tree is in an inconsistent state."
1507
" Please consider doing a 'bzr revert'."
1508
" Error message is: %s" % e)
1510
def _move_entry(self, entry):
1511
inv = self.inventory
1512
from_rel_abs = self.abspath(entry.from_rel)
1513
to_rel_abs = self.abspath(entry.to_rel)
1514
if from_rel_abs == to_rel_abs:
1515
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
1516
"Source and target are identical.")
1518
if not entry.only_change_inv:
1520
osutils.rename(from_rel_abs, to_rel_abs)
1522
raise errors.BzrMoveFailedError(entry.from_rel,
1524
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
1526
@needs_tree_write_lock
1527
def rename_one(self, from_rel, to_rel, after=False):
1530
This can change the directory or the filename or both.
1532
rename_one has several 'modes' to work. First, it can rename a physical
1533
file and change the file_id. That is the normal mode. Second, it can
1534
only change the file_id without touching any physical file. This is
1535
the new mode introduced in version 0.15.
1537
rename_one uses the second mode if 'after == True' and 'to_rel' is not
1538
versioned but present in the working tree.
1540
rename_one uses the second mode if 'after == False' and 'from_rel' is
1541
versioned but no longer in the working tree, and 'to_rel' is not
1542
versioned but present in the working tree.
1544
rename_one uses the first mode if 'after == False' and 'from_rel' is
1545
versioned and present in the working tree, and 'to_rel' is not
1546
versioned and not present in the working tree.
1548
Everything else results in an error.
1550
inv = self.inventory
1553
# create rename entries and tuples
1554
from_tail = splitpath(from_rel)[-1]
1555
from_id = inv.path2id(from_rel)
1557
# if file is missing in the inventory maybe it's in the basis_tree
1558
basis_tree = self.branch.basis_tree()
1559
from_id = basis_tree.path2id(from_rel)
1561
raise errors.BzrRenameFailedError(from_rel,to_rel,
1562
errors.NotVersionedError(path=str(from_rel)))
1563
# put entry back in the inventory so we can rename it
1564
from_entry = basis_tree.inventory[from_id].copy()
1567
from_entry = inv[from_id]
1568
from_parent_id = from_entry.parent_id
1569
to_dir, to_tail = os.path.split(to_rel)
1570
to_dir_id = inv.path2id(to_dir)
1571
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1573
from_tail=from_tail,
1574
from_parent_id=from_parent_id,
1575
to_rel=to_rel, to_tail=to_tail,
1576
to_parent_id=to_dir_id)
1577
rename_entries.append(rename_entry)
1579
# determine which move mode to use. checks also for movability
1580
rename_entries = self._determine_mv_mode(rename_entries, after)
1582
# check if the target changed directory and if the target directory is
1584
if to_dir_id is None:
1585
raise errors.BzrMoveFailedError(from_rel,to_rel,
1586
errors.NotVersionedError(path=str(to_dir)))
1588
# all checks done. now we can continue with our actual work
1589
mutter('rename_one:\n'
1594
' to_dir_id {%s}\n',
1595
from_id, from_rel, to_rel, to_dir, to_dir_id)
1597
self._move(rename_entries)
1598
self._write_inventory(inv)
1600
class _RenameEntry(object):
1601
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
1602
to_rel, to_tail, to_parent_id, only_change_inv=False):
1603
self.from_rel = from_rel
1604
self.from_id = from_id
1605
self.from_tail = from_tail
1606
self.from_parent_id = from_parent_id
1607
self.to_rel = to_rel
1608
self.to_tail = to_tail
1609
self.to_parent_id = to_parent_id
1610
self.only_change_inv = only_change_inv
1614
"""Return all unknown files.
1616
These are files in the working directory that are not versioned or
1617
control files or ignored.
1619
# force the extras method to be fully executed before returning, to
1620
# prevent race conditions with the lock
1622
[subp for subp in self.extras() if not self.is_ignored(subp)])
1624
@needs_tree_write_lock
1625
def unversion(self, file_ids):
1626
"""Remove the file ids in file_ids from the current versioned set.
1628
When a file_id is unversioned, all of its children are automatically
1631
:param file_ids: The file ids to stop versioning.
1632
:raises: NoSuchId if any fileid is not currently versioned.
1634
for file_id in file_ids:
1635
if file_id not in self._inventory:
1636
raise errors.NoSuchId(self, file_id)
1637
for file_id in file_ids:
1638
if self._inventory.has_id(file_id):
1639
self._inventory.remove_recursive_id(file_id)
1641
# in the future this should just set a dirty bit to wait for the
1642
# final unlock. However, until all methods of workingtree start
1643
# with the current in -memory inventory rather than triggering
1644
# a read, it is more complex - we need to teach read_inventory
1645
# to know when to read, and when to not read first... and possibly
1646
# to save first when the in memory one may be corrupted.
1647
# so for now, we just only write it if it is indeed dirty.
1649
self._write_inventory(self._inventory)
1651
def _iter_conflicts(self):
1653
for info in self.list_files():
1655
stem = get_conflicted_stem(path)
1658
if stem not in conflicted:
1659
conflicted.add(stem)
1663
def pull(self, source, overwrite=False, stop_revision=None,
1664
change_reporter=None, possible_transports=None, local=False):
1667
old_revision_info = self.branch.last_revision_info()
1668
basis_tree = self.basis_tree()
1669
count = self.branch.pull(source, overwrite, stop_revision,
1670
possible_transports=possible_transports,
1672
new_revision_info = self.branch.last_revision_info()
1673
if new_revision_info != old_revision_info:
1674
repository = self.branch.repository
1675
basis_tree.lock_read()
1677
new_basis_tree = self.branch.basis_tree()
1684
change_reporter=change_reporter)
1685
basis_root_id = basis_tree.get_root_id()
1686
new_root_id = new_basis_tree.get_root_id()
1687
if basis_root_id != new_root_id:
1688
self.set_root_id(new_root_id)
1691
# TODO - dedup parents list with things merged by pull ?
1692
# reuse the revisiontree we merged against to set the new
1694
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1695
# we have to pull the merge trees out again, because
1696
# merge_inner has set the ids. - this corner is not yet
1697
# layered well enough to prevent double handling.
1698
# XXX TODO: Fix the double handling: telling the tree about
1699
# the already known parent data is wasteful.
1700
merges = self.get_parent_ids()[1:]
1701
parent_trees.extend([
1702
(parent, repository.revision_tree(parent)) for
1704
self.set_parent_trees(parent_trees)
1710
def put_file_bytes_non_atomic(self, file_id, bytes):
1711
"""See MutableTree.put_file_bytes_non_atomic."""
1712
stream = file(self.id2abspath(file_id), 'wb')
1717
# TODO: update the hashcache here ?
1720
"""Yield all unversioned files in this WorkingTree.
1722
If there are any unversioned directories then only the directory is
1723
returned, not all its children. But if there are unversioned files
1724
under a versioned subdirectory, they are returned.
1726
Currently returned depth-first, sorted by name within directories.
1727
This is the same order used by 'osutils.walkdirs'.
1729
## TODO: Work from given directory downwards
1730
for path, dir_entry in self.inventory.directories():
1731
# mutter("search for unknowns in %r", path)
1732
dirabs = self.abspath(path)
1733
if not isdir(dirabs):
1734
# e.g. directory deleted
1738
for subf in os.listdir(dirabs):
1739
if self.bzrdir.is_control_filename(subf):
1741
if subf not in dir_entry.children:
1744
can_access) = osutils.normalized_filename(subf)
1745
except UnicodeDecodeError:
1746
path_os_enc = path.encode(osutils._fs_enc)
1747
relpath = path_os_enc + '/' + subf
1748
raise errors.BadFilenameEncoding(relpath,
1750
if subf_norm != subf and can_access:
1751
if subf_norm not in dir_entry.children:
1752
fl.append(subf_norm)
1758
subp = pathjoin(path, subf)
1761
def ignored_files(self):
1762
"""Yield list of PATH, IGNORE_PATTERN"""
1763
for subp in self.extras():
1764
pat = self.is_ignored(subp)
1768
def get_ignore_list(self):
1769
"""Return list of ignore patterns.
1771
Cached in the Tree object after the first call.
1773
ignoreset = getattr(self, '_ignoreset', None)
1774
if ignoreset is not None:
1777
ignore_globs = set()
1778
ignore_globs.update(ignores.get_runtime_ignores())
1779
ignore_globs.update(ignores.get_user_ignores())
1780
if self.has_filename(bzrlib.IGNORE_FILENAME):
1781
f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
1783
ignore_globs.update(ignores.parse_ignore_file(f))
1786
self._ignoreset = ignore_globs
1789
def _flush_ignore_list_cache(self):
1790
"""Resets the cached ignore list to force a cache rebuild."""
1791
self._ignoreset = None
1792
self._ignoreglobster = None
1794
def is_ignored(self, filename):
1795
r"""Check whether the filename matches an ignore pattern.
1797
Patterns containing '/' or '\' need to match the whole path;
1798
others match against only the last component. Patterns starting
1799
with '!' are ignore exceptions. Exceptions take precedence
1800
over regular patterns and cause the filename to not be ignored.
1802
If the file is ignored, returns the pattern which caused it to
1803
be ignored, otherwise None. So this can simply be used as a
1804
boolean if desired."""
1805
if getattr(self, '_ignoreglobster', None) is None:
1806
self._ignoreglobster = globbing.ExceptionGlobster(self.get_ignore_list())
1807
return self._ignoreglobster.match(filename)
1809
def kind(self, file_id):
1810
return file_kind(self.id2abspath(file_id))
1812
def stored_kind(self, file_id):
1813
"""See Tree.stored_kind"""
1814
return self.inventory[file_id].kind
1816
def _comparison_data(self, entry, path):
1817
abspath = self.abspath(path)
1819
stat_value = os.lstat(abspath)
1821
if getattr(e, 'errno', None) == errno.ENOENT:
1828
mode = stat_value.st_mode
1829
kind = osutils.file_kind_from_stat_mode(mode)
1830
if not supports_executable():
1831
executable = entry is not None and entry.executable
1833
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1834
return kind, executable, stat_value
1836
def _file_size(self, entry, stat_value):
1837
return stat_value.st_size
1839
def last_revision(self):
1840
"""Return the last revision of the branch for this tree.
1842
This format tree does not support a separate marker for last-revision
1843
compared to the branch.
1845
See MutableTree.last_revision
1847
return self._last_revision()
1850
def _last_revision(self):
1851
"""helper for get_parent_ids."""
1852
return _mod_revision.ensure_null(self.branch.last_revision())
1854
def is_locked(self):
1855
return self._control_files.is_locked()
1857
def _must_be_locked(self):
1858
if not self.is_locked():
1859
raise errors.ObjectNotLocked(self)
1861
def lock_read(self):
1862
"""Lock the tree for reading.
1864
This also locks the branch, and can be unlocked via self.unlock().
1866
:return: A bzrlib.lock.LogicalLockResult.
1868
if not self.is_locked():
1870
self.branch.lock_read()
1872
self._control_files.lock_read()
1873
return LogicalLockResult(self.unlock)
1875
self.branch.unlock()
1878
def lock_tree_write(self):
1879
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1881
:return: A bzrlib.lock.LogicalLockResult.
1883
if not self.is_locked():
1885
self.branch.lock_read()
1887
self._control_files.lock_write()
1888
return LogicalLockResult(self.unlock)
1890
self.branch.unlock()
1893
def lock_write(self):
1894
"""See MutableTree.lock_write, and WorkingTree.unlock.
1896
:return: A bzrlib.lock.LogicalLockResult.
1898
if not self.is_locked():
1900
self.branch.lock_write()
1902
self._control_files.lock_write()
1903
return LogicalLockResult(self.unlock)
1905
self.branch.unlock()
1908
def get_physical_lock_status(self):
1909
return self._control_files.get_physical_lock_status()
1911
def _basis_inventory_name(self):
1912
return 'basis-inventory-cache'
1914
def _reset_data(self):
1915
"""Reset transient data that cannot be revalidated."""
1916
self._inventory_is_modified = False
1917
f = self._transport.get('inventory')
1919
result = self._deserialize(f)
1922
self._set_inventory(result, dirty=False)
1924
@needs_tree_write_lock
1925
def set_last_revision(self, new_revision):
1926
"""Change the last revision in the working tree."""
1927
if self._change_last_revision(new_revision):
1928
self._cache_basis_inventory(new_revision)
1930
def _change_last_revision(self, new_revision):
1931
"""Template method part of set_last_revision to perform the change.
1933
This is used to allow WorkingTree3 instances to not affect branch
1934
when their last revision is set.
1936
if _mod_revision.is_null(new_revision):
1937
self.branch.set_revision_history([])
1940
self.branch.generate_revision_history(new_revision)
1941
except errors.NoSuchRevision:
1942
# not present in the repo - dont try to set it deeper than the tip
1943
self.branch.set_revision_history([new_revision])
1946
def _write_basis_inventory(self, xml):
1947
"""Write the basis inventory XML to the basis-inventory file"""
1948
path = self._basis_inventory_name()
1950
self._transport.put_file(path, sio,
1951
mode=self.bzrdir._get_file_mode())
1953
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1954
"""Create the text that will be saved in basis-inventory"""
1955
inventory.revision_id = revision_id
1956
return xml7.serializer_v7.write_inventory_to_string(inventory)
1958
def _cache_basis_inventory(self, new_revision):
1959
"""Cache new_revision as the basis inventory."""
1960
# TODO: this should allow the ready-to-use inventory to be passed in,
1961
# as commit already has that ready-to-use [while the format is the
1964
# this double handles the inventory - unpack and repack -
1965
# but is easier to understand. We can/should put a conditional
1966
# in here based on whether the inventory is in the latest format
1967
# - perhaps we should repack all inventories on a repository
1969
# the fast path is to copy the raw xml from the repository. If the
1970
# xml contains 'revision_id="', then we assume the right
1971
# revision_id is set. We must check for this full string, because a
1972
# root node id can legitimately look like 'revision_id' but cannot
1974
xml = self.branch.repository._get_inventory_xml(new_revision)
1975
firstline = xml.split('\n', 1)[0]
1976
if (not 'revision_id="' in firstline or
1977
'format="7"' not in firstline):
1978
inv = self.branch.repository._serializer.read_inventory_from_string(
1980
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1981
self._write_basis_inventory(xml)
1982
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1985
def read_basis_inventory(self):
1986
"""Read the cached basis inventory."""
1987
path = self._basis_inventory_name()
1988
return self._transport.get_bytes(path)
1991
def read_working_inventory(self):
1992
"""Read the working inventory.
1994
:raises errors.InventoryModified: read_working_inventory will fail
1995
when the current in memory inventory has been modified.
1997
# conceptually this should be an implementation detail of the tree.
1998
# XXX: Deprecate this.
1999
# ElementTree does its own conversion from UTF-8, so open in
2001
if self._inventory_is_modified:
2002
raise errors.InventoryModified(self)
2003
f = self._transport.get('inventory')
2005
result = self._deserialize(f)
2008
self._set_inventory(result, dirty=False)
2011
@needs_tree_write_lock
2012
def remove(self, files, verbose=False, to_file=None, keep_files=True,
2014
"""Remove nominated files from the working inventory.
2016
:files: File paths relative to the basedir.
2017
:keep_files: If true, the files will also be kept.
2018
:force: Delete files and directories, even if they are changed and
2019
even if the directories are not empty.
2021
if isinstance(files, basestring):
2027
unknown_nested_files=set()
2029
to_file = sys.stdout
2031
def recurse_directory_to_add_files(directory):
2032
# Recurse directory and add all files
2033
# so we can check if they have changed.
2034
for parent_info, file_infos in self.walkdirs(directory):
2035
for relpath, basename, kind, lstat, fileid, kind in file_infos:
2036
# Is it versioned or ignored?
2037
if self.path2id(relpath) or self.is_ignored(relpath):
2038
# Add nested content for deletion.
2039
new_files.add(relpath)
2041
# Files which are not versioned and not ignored
2042
# should be treated as unknown.
2043
unknown_nested_files.add((relpath, None, kind))
2045
for filename in files:
2046
# Get file name into canonical form.
2047
abspath = self.abspath(filename)
2048
filename = self.relpath(abspath)
2049
if len(filename) > 0:
2050
new_files.add(filename)
2051
recurse_directory_to_add_files(filename)
2053
files = list(new_files)
2056
return # nothing to do
2058
# Sort needed to first handle directory content before the directory
2059
files.sort(reverse=True)
2061
# Bail out if we are going to delete files we shouldn't
2062
if not keep_files and not force:
2063
has_changed_files = len(unknown_nested_files) > 0
2064
if not has_changed_files:
2065
for (file_id, path, content_change, versioned, parent_id, name,
2066
kind, executable) in self.iter_changes(self.basis_tree(),
2067
include_unchanged=True, require_versioned=False,
2068
want_unversioned=True, specific_files=files):
2069
if versioned == (False, False):
2070
# The record is unknown ...
2071
if not self.is_ignored(path[1]):
2072
# ... but not ignored
2073
has_changed_files = True
2075
elif (content_change and (kind[1] is not None) and
2076
osutils.is_inside_any(files, path[1])):
2077
# Versioned and changed, but not deleted, and still
2078
# in one of the dirs to be deleted.
2079
has_changed_files = True
2082
if has_changed_files:
2083
# Make delta show ALL applicable changes in error message.
2084
tree_delta = self.changes_from(self.basis_tree(),
2085
require_versioned=False, want_unversioned=True,
2086
specific_files=files)
2087
for unknown_file in unknown_nested_files:
2088
if unknown_file not in tree_delta.unversioned:
2089
tree_delta.unversioned.extend((unknown_file,))
2090
raise errors.BzrRemoveChangedFilesError(tree_delta)
2092
# Build inv_delta and delete files where applicable,
2093
# do this before any modifications to inventory.
2095
fid = self.path2id(f)
2098
message = "%s is not versioned." % (f,)
2101
# having removed it, it must be either ignored or unknown
2102
if self.is_ignored(f):
2106
# XXX: Really should be a more abstract reporter interface
2107
kind_ch = osutils.kind_marker(self.kind(fid))
2108
to_file.write(new_status + ' ' + f + kind_ch + '\n')
2110
inv_delta.append((f, None, fid, None))
2111
message = "removed %s" % (f,)
2114
abs_path = self.abspath(f)
2115
if osutils.lexists(abs_path):
2116
if (osutils.isdir(abs_path) and
2117
len(os.listdir(abs_path)) > 0):
2119
osutils.rmtree(abs_path)
2121
message = "%s is not an empty directory "\
2122
"and won't be deleted." % (f,)
2124
osutils.delete_any(abs_path)
2125
message = "deleted %s" % (f,)
2126
elif message is not None:
2127
# Only care if we haven't done anything yet.
2128
message = "%s does not exist." % (f,)
2130
# Print only one message (if any) per file.
2131
if message is not None:
2133
self.apply_inventory_delta(inv_delta)
2135
@needs_tree_write_lock
2136
def revert(self, filenames=None, old_tree=None, backups=True,
2137
pb=None, report_changes=False):
2138
from bzrlib.conflicts import resolve
2141
symbol_versioning.warn('Using [] to revert all files is deprecated'
2142
' as of bzr 0.91. Please use None (the default) instead.',
2143
DeprecationWarning, stacklevel=2)
2144
if old_tree is None:
2145
basis_tree = self.basis_tree()
2146
basis_tree.lock_read()
2147
old_tree = basis_tree
2151
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
2153
if filenames is None and len(self.get_parent_ids()) > 1:
2155
last_revision = self.last_revision()
2156
if last_revision != _mod_revision.NULL_REVISION:
2157
if basis_tree is None:
2158
basis_tree = self.basis_tree()
2159
basis_tree.lock_read()
2160
parent_trees.append((last_revision, basis_tree))
2161
self.set_parent_trees(parent_trees)
2164
resolve(self, filenames, ignore_misses=True, recursive=True)
2166
if basis_tree is not None:
2170
def revision_tree(self, revision_id):
2171
"""See Tree.revision_tree.
2173
WorkingTree can supply revision_trees for the basis revision only
2174
because there is only one cached inventory in the bzr directory.
2176
if revision_id == self.last_revision():
2178
xml = self.read_basis_inventory()
2179
except errors.NoSuchFile:
2183
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2184
# dont use the repository revision_tree api because we want
2185
# to supply the inventory.
2186
if inv.revision_id == revision_id:
2187
return revisiontree.RevisionTree(self.branch.repository,
2189
except errors.BadInventoryFormat:
2191
# raise if there was no inventory, or if we read the wrong inventory.
2192
raise errors.NoSuchRevisionInTree(self, revision_id)
2194
# XXX: This method should be deprecated in favour of taking in a proper
2195
# new Inventory object.
2196
@needs_tree_write_lock
2197
def set_inventory(self, new_inventory_list):
2198
from bzrlib.inventory import (Inventory,
2202
inv = Inventory(self.get_root_id())
2203
for path, file_id, parent, kind in new_inventory_list:
2204
name = os.path.basename(path)
2207
# fixme, there should be a factory function inv,add_??
2208
if kind == 'directory':
2209
inv.add(InventoryDirectory(file_id, name, parent))
2210
elif kind == 'file':
2211
inv.add(InventoryFile(file_id, name, parent))
2212
elif kind == 'symlink':
2213
inv.add(InventoryLink(file_id, name, parent))
2215
raise errors.BzrError("unknown kind %r" % kind)
2216
self._write_inventory(inv)
2218
@needs_tree_write_lock
2219
def set_root_id(self, file_id):
2220
"""Set the root id for this tree."""
2224
'WorkingTree.set_root_id with fileid=None')
2225
file_id = osutils.safe_file_id(file_id)
2226
self._set_root_id(file_id)
2228
def _set_root_id(self, file_id):
2229
"""Set the root id for this tree, in a format specific manner.
2231
:param file_id: The file id to assign to the root. It must not be
2232
present in the current inventory or an error will occur. It must
2233
not be None, but rather a valid file id.
2235
inv = self._inventory
2236
orig_root_id = inv.root.file_id
2237
# TODO: it might be nice to exit early if there was nothing
2238
# to do, saving us from trigger a sync on unlock.
2239
self._inventory_is_modified = True
2240
# we preserve the root inventory entry object, but
2241
# unlinkit from the byid index
2242
del inv._byid[inv.root.file_id]
2243
inv.root.file_id = file_id
2244
# and link it into the index with the new changed id.
2245
inv._byid[inv.root.file_id] = inv.root
2246
# and finally update all children to reference the new id.
2247
# XXX: this should be safe to just look at the root.children
2248
# list, not the WHOLE INVENTORY.
2251
if entry.parent_id == orig_root_id:
2252
entry.parent_id = inv.root.file_id
2255
"""See Branch.unlock.
2257
WorkingTree locking just uses the Branch locking facilities.
2258
This is current because all working trees have an embedded branch
2259
within them. IF in the future, we were to make branch data shareable
2260
between multiple working trees, i.e. via shared storage, then we
2261
would probably want to lock both the local tree, and the branch.
2263
raise NotImplementedError(self.unlock)
2267
def update(self, change_reporter=None, possible_transports=None,
2268
revision=None, old_tip=_marker):
2269
"""Update a working tree along its branch.
2271
This will update the branch if its bound too, which means we have
2272
multiple trees involved:
2274
- The new basis tree of the master.
2275
- The old basis tree of the branch.
2276
- The old basis tree of the working tree.
2277
- The current working tree state.
2279
Pathologically, all three may be different, and non-ancestors of each
2280
other. Conceptually we want to:
2282
- Preserve the wt.basis->wt.state changes
2283
- Transform the wt.basis to the new master basis.
2284
- Apply a merge of the old branch basis to get any 'local' changes from
2286
- Restore the wt.basis->wt.state changes.
2288
There isn't a single operation at the moment to do that, so we:
2289
- Merge current state -> basis tree of the master w.r.t. the old tree
2291
- Do a 'normal' merge of the old branch basis if it is relevant.
2293
:param revision: The target revision to update to. Must be in the
2295
:param old_tip: If branch.update() has already been run, the value it
2296
returned (old tip of the branch or None). _marker is used
2299
if self.branch.get_bound_location() is not None:
2301
update_branch = (old_tip is self._marker)
2303
self.lock_tree_write()
2304
update_branch = False
2307
old_tip = self.branch.update(possible_transports)
2309
if old_tip is self._marker:
2311
return self._update_tree(old_tip, change_reporter, revision)
2315
@needs_tree_write_lock
2316
def _update_tree(self, old_tip=None, change_reporter=None, revision=None):
2317
"""Update a tree to the master branch.
2319
:param old_tip: if supplied, the previous tip revision the branch,
2320
before it was changed to the master branch's tip.
2322
# here if old_tip is not None, it is the old tip of the branch before
2323
# it was updated from the master branch. This should become a pending
2324
# merge in the working tree to preserve the user existing work. we
2325
# cant set that until we update the working trees last revision to be
2326
# one from the new branch, because it will just get absorbed by the
2327
# parent de-duplication logic.
2329
# We MUST save it even if an error occurs, because otherwise the users
2330
# local work is unreferenced and will appear to have been lost.
2334
last_rev = self.get_parent_ids()[0]
2336
last_rev = _mod_revision.NULL_REVISION
2337
if revision is None:
2338
revision = self.branch.last_revision()
2340
old_tip = old_tip or _mod_revision.NULL_REVISION
2342
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
2343
# the branch we are bound to was updated
2344
# merge those changes in first
2345
base_tree = self.basis_tree()
2346
other_tree = self.branch.repository.revision_tree(old_tip)
2347
nb_conflicts = merge.merge_inner(self.branch, other_tree,
2348
base_tree, this_tree=self,
2349
change_reporter=change_reporter)
2351
self.add_parent_tree((old_tip, other_tree))
2352
trace.note('Rerun update after fixing the conflicts.')
2355
if last_rev != _mod_revision.ensure_null(revision):
2356
# the working tree is up to date with the branch
2357
# we can merge the specified revision from master
2358
to_tree = self.branch.repository.revision_tree(revision)
2359
to_root_id = to_tree.get_root_id()
2361
basis = self.basis_tree()
2364
if (basis.inventory.root is None
2365
or basis.inventory.root.file_id != to_root_id):
2366
self.set_root_id(to_root_id)
2371
# determine the branch point
2372
graph = self.branch.repository.get_graph()
2373
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2375
base_tree = self.branch.repository.revision_tree(base_rev_id)
2377
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
2379
change_reporter=change_reporter)
2380
self.set_last_revision(revision)
2381
# TODO - dedup parents list with things merged by pull ?
2382
# reuse the tree we've updated to to set the basis:
2383
parent_trees = [(revision, to_tree)]
2384
merges = self.get_parent_ids()[1:]
2385
# Ideally we ask the tree for the trees here, that way the working
2386
# tree can decide whether to give us the entire tree or give us a
2387
# lazy initialised tree. dirstate for instance will have the trees
2388
# in ram already, whereas a last-revision + basis-inventory tree
2389
# will not, but also does not need them when setting parents.
2390
for parent in merges:
2391
parent_trees.append(
2392
(parent, self.branch.repository.revision_tree(parent)))
2393
if not _mod_revision.is_null(old_tip):
2394
parent_trees.append(
2395
(old_tip, self.branch.repository.revision_tree(old_tip)))
2396
self.set_parent_trees(parent_trees)
2397
last_rev = parent_trees[0][0]
2400
def _write_hashcache_if_dirty(self):
2401
"""Write out the hashcache if it is dirty."""
2402
if self._hashcache.needs_write:
2404
self._hashcache.write()
2406
if e.errno not in (errno.EPERM, errno.EACCES):
2408
# TODO: jam 20061219 Should this be a warning? A single line
2409
# warning might be sufficient to let the user know what
2411
mutter('Could not write hashcache for %s\nError: %s',
2412
self._hashcache.cache_file_name(), e)
2414
@needs_tree_write_lock
2415
def _write_inventory(self, inv):
2416
"""Write inventory as the current inventory."""
2417
self._set_inventory(inv, dirty=True)
2420
def set_conflicts(self, arg):
2421
raise errors.UnsupportedOperation(self.set_conflicts, self)
2423
def add_conflicts(self, arg):
2424
raise errors.UnsupportedOperation(self.add_conflicts, self)
2427
def conflicts(self):
2428
conflicts = _mod_conflicts.ConflictList()
2429
for conflicted in self._iter_conflicts():
2432
if file_kind(self.abspath(conflicted)) != "file":
2434
except errors.NoSuchFile:
2437
for suffix in ('.THIS', '.OTHER'):
2439
kind = file_kind(self.abspath(conflicted+suffix))
2442
except errors.NoSuchFile:
2446
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
2447
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
2449
file_id=self.path2id(conflicted)))
2452
def walkdirs(self, prefix=""):
2453
"""Walk the directories of this tree.
2455
returns a generator which yields items in the form:
2456
((curren_directory_path, fileid),
2457
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
2460
This API returns a generator, which is only valid during the current
2461
tree transaction - within a single lock_read or lock_write duration.
2463
If the tree is not locked, it may cause an error to be raised,
2464
depending on the tree implementation.
2466
disk_top = self.abspath(prefix)
2467
if disk_top.endswith('/'):
2468
disk_top = disk_top[:-1]
2469
top_strip_len = len(disk_top) + 1
2470
inventory_iterator = self._walkdirs(prefix)
2471
disk_iterator = osutils.walkdirs(disk_top, prefix)
2473
current_disk = disk_iterator.next()
2474
disk_finished = False
2476
if not (e.errno == errno.ENOENT or
2477
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
2480
disk_finished = True
2482
current_inv = inventory_iterator.next()
2483
inv_finished = False
2484
except StopIteration:
2487
while not inv_finished or not disk_finished:
2489
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2490
cur_disk_dir_content) = current_disk
2492
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2493
cur_disk_dir_content) = ((None, None), None)
2494
if not disk_finished:
2495
# strip out .bzr dirs
2496
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2497
len(cur_disk_dir_content) > 0):
2498
# osutils.walkdirs can be made nicer -
2499
# yield the path-from-prefix rather than the pathjoined
2501
bzrdir_loc = bisect_left(cur_disk_dir_content,
2503
if (bzrdir_loc < len(cur_disk_dir_content)
2504
and self.bzrdir.is_control_filename(
2505
cur_disk_dir_content[bzrdir_loc][0])):
2506
# we dont yield the contents of, or, .bzr itself.
2507
del cur_disk_dir_content[bzrdir_loc]
2509
# everything is unknown
2512
# everything is missing
2515
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2517
# disk is before inventory - unknown
2518
dirblock = [(relpath, basename, kind, stat, None, None) for
2519
relpath, basename, kind, stat, top_path in
2520
cur_disk_dir_content]
2521
yield (cur_disk_dir_relpath, None), dirblock
2523
current_disk = disk_iterator.next()
2524
except StopIteration:
2525
disk_finished = True
2527
# inventory is before disk - missing.
2528
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2529
for relpath, basename, dkind, stat, fileid, kind in
2531
yield (current_inv[0][0], current_inv[0][1]), dirblock
2533
current_inv = inventory_iterator.next()
2534
except StopIteration:
2537
# versioned present directory
2538
# merge the inventory and disk data together
2540
for relpath, subiterator in itertools.groupby(sorted(
2541
current_inv[1] + cur_disk_dir_content,
2542
key=operator.itemgetter(0)), operator.itemgetter(1)):
2543
path_elements = list(subiterator)
2544
if len(path_elements) == 2:
2545
inv_row, disk_row = path_elements
2546
# versioned, present file
2547
dirblock.append((inv_row[0],
2548
inv_row[1], disk_row[2],
2549
disk_row[3], inv_row[4],
2551
elif len(path_elements[0]) == 5:
2553
dirblock.append((path_elements[0][0],
2554
path_elements[0][1], path_elements[0][2],
2555
path_elements[0][3], None, None))
2556
elif len(path_elements[0]) == 6:
2557
# versioned, absent file.
2558
dirblock.append((path_elements[0][0],
2559
path_elements[0][1], 'unknown', None,
2560
path_elements[0][4], path_elements[0][5]))
2562
raise NotImplementedError('unreachable code')
2563
yield current_inv[0], dirblock
2565
current_inv = inventory_iterator.next()
2566
except StopIteration:
2569
current_disk = disk_iterator.next()
2570
except StopIteration:
2571
disk_finished = True
2573
def _walkdirs(self, prefix=""):
2574
"""Walk the directories of this tree.
2576
:prefix: is used as the directrory to start with.
2577
returns a generator which yields items in the form:
2578
((curren_directory_path, fileid),
2579
[(file1_path, file1_name, file1_kind, None, file1_id,
2582
_directory = 'directory'
2583
# get the root in the inventory
2584
inv = self.inventory
2585
top_id = inv.path2id(prefix)
2589
pending = [(prefix, '', _directory, None, top_id, None)]
2592
currentdir = pending.pop()
2593
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2594
top_id = currentdir[4]
2596
relroot = currentdir[0] + '/'
2599
# FIXME: stash the node in pending
2601
if entry.kind == 'directory':
2602
for name, child in entry.sorted_children():
2603
dirblock.append((relroot + name, name, child.kind, None,
2604
child.file_id, child.kind
2606
yield (currentdir[0], entry.file_id), dirblock
2607
# push the user specified dirs from dirblock
2608
for dir in reversed(dirblock):
2609
if dir[2] == _directory:
2612
@needs_tree_write_lock
2613
def auto_resolve(self):
2614
"""Automatically resolve text conflicts according to contents.
2616
Only text conflicts are auto_resolvable. Files with no conflict markers
2617
are considered 'resolved', because bzr always puts conflict markers
2618
into files that have text conflicts. The corresponding .THIS .BASE and
2619
.OTHER files are deleted, as per 'resolve'.
2620
:return: a tuple of ConflictLists: (un_resolved, resolved).
2622
un_resolved = _mod_conflicts.ConflictList()
2623
resolved = _mod_conflicts.ConflictList()
2624
conflict_re = re.compile('^(<{7}|={7}|>{7})')
2625
for conflict in self.conflicts():
2626
if (conflict.typestring != 'text conflict' or
2627
self.kind(conflict.file_id) != 'file'):
2628
un_resolved.append(conflict)
2630
my_file = open(self.id2abspath(conflict.file_id), 'rb')
2632
for line in my_file:
2633
if conflict_re.search(line):
2634
un_resolved.append(conflict)
2637
resolved.append(conflict)
2640
resolved.remove_files(self)
2641
self.set_conflicts(un_resolved)
2642
return un_resolved, resolved
2645
def _check(self, references):
2646
"""Check the tree for consistency.
2648
:param references: A dict with keys matching the items returned by
2649
self._get_check_refs(), and values from looking those keys up in
2652
tree_basis = self.basis_tree()
2653
tree_basis.lock_read()
2655
repo_basis = references[('trees', self.last_revision())]
2656
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2657
raise errors.BzrCheckError(
2658
"Mismatched basis inventory content.")
2663
def _validate(self):
2664
"""Validate internal structures.
2666
This is meant mostly for the test suite. To give it a chance to detect
2667
corruption after actions have occurred. The default implementation is a
2670
:return: None. An exception should be raised if there is an error.
2674
def _get_rules_searcher(self, default_searcher):
2675
"""See Tree._get_rules_searcher."""
2676
if self._rules_searcher is None:
2677
self._rules_searcher = super(WorkingTree,
2678
self)._get_rules_searcher(default_searcher)
2679
return self._rules_searcher
2681
def get_shelf_manager(self):
2682
"""Return the ShelfManager for this WorkingTree."""
2683
from bzrlib.shelf import ShelfManager
2684
return ShelfManager(self, self._transport)
2687
class WorkingTree2(WorkingTree):
2688
"""This is the Format 2 working tree.
2690
This was the first weave based working tree.
2691
- uses os locks for locking.
2692
- uses the branch last-revision.
2695
def __init__(self, *args, **kwargs):
2696
super(WorkingTree2, self).__init__(*args, **kwargs)
2697
# WorkingTree2 has more of a constraint that self._inventory must
2698
# exist. Because this is an older format, we don't mind the overhead
2699
# caused by the extra computation here.
2701
# Newer WorkingTree's should only have self._inventory set when they
2703
if self._inventory is None:
2704
self.read_working_inventory()
2706
def _get_check_refs(self):
2707
"""Return the references needed to perform a check of this tree."""
2708
return [('trees', self.last_revision())]
2710
def lock_tree_write(self):
2711
"""See WorkingTree.lock_tree_write().
2713
In Format2 WorkingTrees we have a single lock for the branch and tree
2714
so lock_tree_write() degrades to lock_write().
2716
:return: An object with an unlock method which will release the lock
2719
self.branch.lock_write()
2721
self._control_files.lock_write()
2724
self.branch.unlock()
2728
# do non-implementation specific cleanup
2731
# we share control files:
2732
if self._control_files._lock_count == 3:
2733
# _inventory_is_modified is always False during a read lock.
2734
if self._inventory_is_modified:
2736
self._write_hashcache_if_dirty()
2738
# reverse order of locking.
2740
return self._control_files.unlock()
2742
self.branch.unlock()
2745
class WorkingTree3(WorkingTree):
2746
"""This is the Format 3 working tree.
2748
This differs from the base WorkingTree by:
2749
- having its own file lock
2750
- having its own last-revision property.
2752
This is new in bzr 0.8
2756
def _last_revision(self):
2757
"""See Mutable.last_revision."""
2759
return self._transport.get_bytes('last-revision')
2760
except errors.NoSuchFile:
2761
return _mod_revision.NULL_REVISION
2763
def _change_last_revision(self, revision_id):
2764
"""See WorkingTree._change_last_revision."""
2765
if revision_id is None or revision_id == _mod_revision.NULL_REVISION:
2767
self._transport.delete('last-revision')
2768
except errors.NoSuchFile:
2772
self._transport.put_bytes('last-revision', revision_id,
2773
mode=self.bzrdir._get_file_mode())
2776
def _get_check_refs(self):
2777
"""Return the references needed to perform a check of this tree."""
2778
return [('trees', self.last_revision())]
2780
@needs_tree_write_lock
2781
def set_conflicts(self, conflicts):
2782
self._put_rio('conflicts', conflicts.to_stanzas(),
2785
@needs_tree_write_lock
2786
def add_conflicts(self, new_conflicts):
2787
conflict_set = set(self.conflicts())
2788
conflict_set.update(set(list(new_conflicts)))
2789
self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2790
key=_mod_conflicts.Conflict.sort_key)))
2793
def conflicts(self):
2795
confile = self._transport.get('conflicts')
2796
except errors.NoSuchFile:
2797
return _mod_conflicts.ConflictList()
2800
if confile.next() != CONFLICT_HEADER_1 + '\n':
2801
raise errors.ConflictFormatError()
2802
except StopIteration:
2803
raise errors.ConflictFormatError()
2804
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2809
# do non-implementation specific cleanup
2811
if self._control_files._lock_count == 1:
2812
# _inventory_is_modified is always False during a read lock.
2813
if self._inventory_is_modified:
2815
self._write_hashcache_if_dirty()
2816
# reverse order of locking.
2818
return self._control_files.unlock()
2820
self.branch.unlock()
2823
def get_conflicted_stem(path):
2824
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2825
if path.endswith(suffix):
2826
return path[:-len(suffix)]
2829
class WorkingTreeFormat(object):
2830
"""An encapsulation of the initialization and open routines for a format.
2832
Formats provide three things:
2833
* An initialization routine,
2837
Formats are placed in an dict by their format string for reference
2838
during workingtree opening. Its not required that these be instances, they
2839
can be classes themselves with class methods - it simply depends on
2840
whether state is needed for a given format or not.
2842
Once a format is deprecated, just deprecate the initialize and open
2843
methods on the format class. Do not deprecate the object, as the
2844
object will be created every time regardless.
2847
_default_format = None
2848
"""The default format used for new trees."""
2851
"""The known formats."""
2853
requires_rich_root = False
2855
upgrade_recommended = False
2858
def find_format(klass, a_bzrdir):
2859
"""Return the format for the working tree object in a_bzrdir."""
2861
transport = a_bzrdir.get_workingtree_transport(None)
2862
format_string = transport.get_bytes("format")
2863
return klass._formats[format_string]
2864
except errors.NoSuchFile:
2865
raise errors.NoWorkingTree(base=transport.base)
2867
raise errors.UnknownFormatError(format=format_string,
2868
kind="working tree")
2870
def __eq__(self, other):
2871
return self.__class__ is other.__class__
2873
def __ne__(self, other):
2874
return not (self == other)
2877
def get_default_format(klass):
2878
"""Return the current default format."""
2879
return klass._default_format
2881
def get_format_string(self):
2882
"""Return the ASCII format string that identifies this format."""
2883
raise NotImplementedError(self.get_format_string)
2885
def get_format_description(self):
2886
"""Return the short description for this format."""
2887
raise NotImplementedError(self.get_format_description)
2889
def is_supported(self):
2890
"""Is this format supported?
2892
Supported formats can be initialized and opened.
2893
Unsupported formats may not support initialization or committing or
2894
some other features depending on the reason for not being supported.
2898
def supports_content_filtering(self):
2899
"""True if this format supports content filtering."""
2902
def supports_views(self):
2903
"""True if this format supports stored views."""
2907
def register_format(klass, format):
2908
klass._formats[format.get_format_string()] = format
2911
def set_default_format(klass, format):
2912
klass._default_format = format
2915
def unregister_format(klass, format):
2916
del klass._formats[format.get_format_string()]
2919
class WorkingTreeFormat2(WorkingTreeFormat):
2920
"""The second working tree format.
2922
This format modified the hash cache from the format 1 hash cache.
2925
upgrade_recommended = True
2927
def get_format_description(self):
2928
"""See WorkingTreeFormat.get_format_description()."""
2929
return "Working tree format 2"
2931
def _stub_initialize_on_transport(self, transport, file_mode):
2932
"""Workaround: create control files for a remote working tree.
2934
This ensures that it can later be updated and dealt with locally,
2935
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2936
no working tree. (See bug #43064).
2939
inv = inventory.Inventory()
2940
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2942
transport.put_file('inventory', sio, file_mode)
2943
transport.put_bytes('pending-merges', '', file_mode)
2945
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2946
accelerator_tree=None, hardlink=False):
2947
"""See WorkingTreeFormat.initialize()."""
2948
if not isinstance(a_bzrdir.transport, LocalTransport):
2949
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2950
if from_branch is not None:
2951
branch = from_branch
2953
branch = a_bzrdir.open_branch()
2954
if revision_id is None:
2955
revision_id = _mod_revision.ensure_null(branch.last_revision())
2958
branch.generate_revision_history(revision_id)
2961
inv = inventory.Inventory()
2962
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2968
basis_tree = branch.repository.revision_tree(revision_id)
2969
if basis_tree.inventory.root is not None:
2970
wt.set_root_id(basis_tree.get_root_id())
2971
# set the parent list and cache the basis tree.
2972
if _mod_revision.is_null(revision_id):
2975
parent_trees = [(revision_id, basis_tree)]
2976
wt.set_parent_trees(parent_trees)
2977
transform.build_tree(basis_tree, wt)
2981
super(WorkingTreeFormat2, self).__init__()
2982
self._matchingbzrdir = bzrdir.BzrDirFormat6()
2984
def open(self, a_bzrdir, _found=False):
2985
"""Return the WorkingTree object for a_bzrdir
2987
_found is a private parameter, do not use it. It is used to indicate
2988
if format probing has already been done.
2991
# we are being called directly and must probe.
2992
raise NotImplementedError
2993
if not isinstance(a_bzrdir.transport, LocalTransport):
2994
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2995
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
3001
class WorkingTreeFormat3(WorkingTreeFormat):
3002
"""The second working tree format updated to record a format marker.
3005
- exists within a metadir controlling .bzr
3006
- includes an explicit version marker for the workingtree control
3007
files, separate from the BzrDir format
3008
- modifies the hash cache format
3010
- uses a LockDir to guard access for writes.
3013
upgrade_recommended = True
3015
def get_format_string(self):
3016
"""See WorkingTreeFormat.get_format_string()."""
3017
return "Bazaar-NG Working Tree format 3"
3019
def get_format_description(self):
3020
"""See WorkingTreeFormat.get_format_description()."""
3021
return "Working tree format 3"
3023
_lock_file_name = 'lock'
3024
_lock_class = LockDir
3026
_tree_class = WorkingTree3
3028
def __get_matchingbzrdir(self):
3029
return bzrdir.BzrDirMetaFormat1()
3031
_matchingbzrdir = property(__get_matchingbzrdir)
3033
def _open_control_files(self, a_bzrdir):
3034
transport = a_bzrdir.get_workingtree_transport(None)
3035
return LockableFiles(transport, self._lock_file_name,
3038
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
3039
accelerator_tree=None, hardlink=False):
3040
"""See WorkingTreeFormat.initialize().
3042
:param revision_id: if supplied, create a working tree at a different
3043
revision than the branch is at.
3044
:param accelerator_tree: A tree which can be used for retrieving file
3045
contents more quickly than the revision tree, i.e. a workingtree.
3046
The revision tree will be used for cases where accelerator_tree's
3047
content is different.
3048
:param hardlink: If true, hard-link files from accelerator_tree,
3051
if not isinstance(a_bzrdir.transport, LocalTransport):
3052
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3053
transport = a_bzrdir.get_workingtree_transport(self)
3054
control_files = self._open_control_files(a_bzrdir)
3055
control_files.create_lock()
3056
control_files.lock_write()
3057
transport.put_bytes('format', self.get_format_string(),
3058
mode=a_bzrdir._get_file_mode())
3059
if from_branch is not None:
3060
branch = from_branch
3062
branch = a_bzrdir.open_branch()
3063
if revision_id is None:
3064
revision_id = _mod_revision.ensure_null(branch.last_revision())
3065
# WorkingTree3 can handle an inventory which has a unique root id.
3066
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
3067
# those trees. And because there isn't a format bump inbetween, we
3068
# are maintaining compatibility with older clients.
3069
# inv = Inventory(root_id=gen_root_id())
3070
inv = self._initial_inventory()
3071
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3077
_control_files=control_files)
3078
wt.lock_tree_write()
3080
basis_tree = branch.repository.revision_tree(revision_id)
3081
# only set an explicit root id if there is one to set.
3082
if basis_tree.inventory.root is not None:
3083
wt.set_root_id(basis_tree.get_root_id())
3084
if revision_id == _mod_revision.NULL_REVISION:
3085
wt.set_parent_trees([])
3087
wt.set_parent_trees([(revision_id, basis_tree)])
3088
transform.build_tree(basis_tree, wt)
3090
# Unlock in this order so that the unlock-triggers-flush in
3091
# WorkingTree is given a chance to fire.
3092
control_files.unlock()
3096
def _initial_inventory(self):
3097
return inventory.Inventory()
3100
super(WorkingTreeFormat3, self).__init__()
3102
def open(self, a_bzrdir, _found=False):
3103
"""Return the WorkingTree object for a_bzrdir
3105
_found is a private parameter, do not use it. It is used to indicate
3106
if format probing has already been done.
3109
# we are being called directly and must probe.
3110
raise NotImplementedError
3111
if not isinstance(a_bzrdir.transport, LocalTransport):
3112
raise errors.NotLocalUrl(a_bzrdir.transport.base)
3113
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
3116
def _open(self, a_bzrdir, control_files):
3117
"""Open the tree itself.
3119
:param a_bzrdir: the dir for the tree.
3120
:param control_files: the control files for the tree.
3122
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
3126
_control_files=control_files)
3129
return self.get_format_string()
3132
__default_format = WorkingTreeFormat6()
3133
WorkingTreeFormat.register_format(__default_format)
3134
WorkingTreeFormat.register_format(WorkingTreeFormat5())
3135
WorkingTreeFormat.register_format(WorkingTreeFormat4())
3136
WorkingTreeFormat.register_format(WorkingTreeFormat3())
3137
WorkingTreeFormat.set_default_format(__default_format)
3138
# formats which have no format string are not discoverable
3139
# and not independently creatable, so are not registered.
3140
_legacy_formats = [WorkingTreeFormat2(),