1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""WorkingTree object and friends.
19
A WorkingTree represents the editable working copy of a branch.
20
Operations which represent the WorkingTree are also done here,
21
such as renaming or adding files. The WorkingTree has an inventory
22
which is updated by these operations. A commit produces a
23
new revision based on the workingtree and its inventory.
25
At the moment every WorkingTree has its own branch. Remote
26
WorkingTrees aren't supported.
28
To get a WorkingTree, call bzrdir.open_workingtree() or
29
WorkingTree.open(dir).
32
# TODO: Give the workingtree sole responsibility for the working inventory;
33
# remove the variable and references to it from the branch. This may require
34
# updating the commit code so as to update the inventory within the working
35
# copy, and making sure there's only one WorkingTree for any directory on disk.
36
# At the moment they may alias the inventory and have old copies of it in
37
# memory. (Now done? -- mbp 20060309)
39
from cStringIO import StringIO
43
from bzrlib.lazy_import import lazy_import
44
lazy_import(globals(), """
45
from bisect import bisect_left
59
conflicts as _mod_conflicts,
67
revision as _mod_revision,
81
from bzrlib.transport import get_transport
83
from bzrlib.workingtree_4 import WorkingTreeFormat4, WorkingTreeFormat5
86
from bzrlib import symbol_versioning
87
from bzrlib.decorators import needs_read_lock, needs_write_lock
88
from bzrlib.inventory import InventoryEntry, Inventory, ROOT_ID, TreeReference
89
from bzrlib.lockable_files import LockableFiles
90
from bzrlib.lockdir import LockDir
91
import bzrlib.mutabletree
92
from bzrlib.mutabletree import needs_tree_write_lock
93
from bzrlib import osutils
94
from bzrlib.osutils import (
106
from bzrlib.trace import mutter, note
107
from bzrlib.transport.local import LocalTransport
108
from bzrlib.progress import DummyProgress, ProgressPhase
109
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
110
from bzrlib.rio import RioReader, rio_file, Stanza
111
from bzrlib.symbol_versioning import (deprecated_passed,
114
DEPRECATED_PARAMETER,
118
MERGE_MODIFIED_HEADER_1 = "BZR merge-modified list format 1"
119
CONFLICT_HEADER_1 = "BZR conflict list format 1"
121
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
124
class TreeEntry(object):
125
"""An entry that implements the minimum interface used by commands.
127
This needs further inspection, it may be better to have
128
InventoryEntries without ids - though that seems wrong. For now,
129
this is a parallel hierarchy to InventoryEntry, and needs to become
130
one of several things: decorates to that hierarchy, children of, or
132
Another note is that these objects are currently only used when there is
133
no InventoryEntry available - i.e. for unversioned objects.
134
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
137
def __eq__(self, other):
138
# yes, this us ugly, TODO: best practice __eq__ style.
139
return (isinstance(other, TreeEntry)
140
and other.__class__ == self.__class__)
142
def kind_character(self):
146
class TreeDirectory(TreeEntry):
147
"""See TreeEntry. This is a directory in a working tree."""
149
def __eq__(self, other):
150
return (isinstance(other, TreeDirectory)
151
and other.__class__ == self.__class__)
153
def kind_character(self):
157
class TreeFile(TreeEntry):
158
"""See TreeEntry. This is a regular file in a working tree."""
160
def __eq__(self, other):
161
return (isinstance(other, TreeFile)
162
and other.__class__ == self.__class__)
164
def kind_character(self):
168
class TreeLink(TreeEntry):
169
"""See TreeEntry. This is a symlink in a working tree."""
171
def __eq__(self, other):
172
return (isinstance(other, TreeLink)
173
and other.__class__ == self.__class__)
175
def kind_character(self):
179
class WorkingTree(bzrlib.mutabletree.MutableTree):
180
"""Working copy tree.
182
The inventory is held in the `Branch` working-inventory, and the
183
files are in a directory on disk.
185
It is possible for a `WorkingTree` to have a filename which is
186
not listed in the Inventory and vice versa.
189
# override this to set the strategy for storing views
190
def _make_views(self):
191
return views.DisabledViews(self)
193
def __init__(self, basedir='.',
194
branch=DEPRECATED_PARAMETER,
200
"""Construct a WorkingTree instance. This is not a public API.
202
:param branch: A branch to override probing for the branch.
204
self._format = _format
205
self.bzrdir = _bzrdir
207
raise errors.BzrError("Please use bzrdir.open_workingtree or "
208
"WorkingTree.open() to obtain a WorkingTree.")
209
basedir = safe_unicode(basedir)
210
mutter("opening working tree %r", basedir)
211
if deprecated_passed(branch):
212
self._branch = branch
214
self._branch = self.bzrdir.open_branch()
215
self.basedir = realpath(basedir)
216
# if branch is at our basedir and is a format 6 or less
217
if isinstance(self._format, WorkingTreeFormat2):
218
# share control object
219
self._control_files = self.branch.control_files
221
# assume all other formats have their own control files.
222
self._control_files = _control_files
223
self._transport = self._control_files._transport
224
# update the whole cache up front and write to disk if anything changed;
225
# in the future we might want to do this more selectively
226
# two possible ways offer themselves : in self._unlock, write the cache
227
# if needed, or, when the cache sees a change, append it to the hash
228
# cache file, and have the parser take the most recent entry for a
230
wt_trans = self.bzrdir.get_workingtree_transport(None)
231
cache_filename = wt_trans.local_abspath('stat-cache')
232
self._hashcache = hashcache.HashCache(basedir, cache_filename,
233
self.bzrdir._get_file_mode())
236
# is this scan needed ? it makes things kinda slow.
243
if _inventory is None:
244
# This will be acquired on lock_read() or lock_write()
245
self._inventory_is_modified = False
246
self._inventory = None
248
# the caller of __init__ has provided an inventory,
249
# we assume they know what they are doing - as its only
250
# the Format factory and creation methods that are
251
# permitted to do this.
252
self._set_inventory(_inventory, dirty=False)
253
self._detect_case_handling()
254
self._rules_searcher = None
255
self.views = self._make_views()
257
def _detect_case_handling(self):
258
wt_trans = self.bzrdir.get_workingtree_transport(None)
260
wt_trans.stat("FoRMaT")
261
except errors.NoSuchFile:
262
self.case_sensitive = True
264
self.case_sensitive = False
266
self._setup_directory_is_tree_reference()
269
fget=lambda self: self._branch,
270
doc="""The branch this WorkingTree is connected to.
272
This cannot be set - it is reflective of the actual disk structure
273
the working tree has been constructed from.
276
def break_lock(self):
277
"""Break a lock if one is present from another instance.
279
Uses the ui factory to ask for confirmation if the lock may be from
282
This will probe the repository for its lock as well.
284
self._control_files.break_lock()
285
self.branch.break_lock()
287
def requires_rich_root(self):
288
return self._format.requires_rich_root
290
def supports_tree_reference(self):
293
def supports_content_filtering(self):
294
return self._format.supports_content_filtering()
296
def supports_views(self):
297
return self.views.supports_views()
299
def _set_inventory(self, inv, dirty):
300
"""Set the internal cached inventory.
302
:param inv: The inventory to set.
303
:param dirty: A boolean indicating whether the inventory is the same
304
logical inventory as whats on disk. If True the inventory is not
305
the same and should be written to disk or data will be lost, if
306
False then the inventory is the same as that on disk and any
307
serialisation would be unneeded overhead.
309
self._inventory = inv
310
self._inventory_is_modified = dirty
313
def open(path=None, _unsupported=False):
314
"""Open an existing working tree at path.
318
path = osutils.getcwd()
319
control = bzrdir.BzrDir.open(path, _unsupported)
320
return control.open_workingtree(_unsupported)
323
def open_containing(path=None):
324
"""Open an existing working tree which has its root about path.
326
This probes for a working tree at path and searches upwards from there.
328
Basically we keep looking up until we find the control directory or
329
run into /. If there isn't one, raises NotBranchError.
330
TODO: give this a new exception.
331
If there is one, it is returned, along with the unused portion of path.
333
:return: The WorkingTree that contains 'path', and the rest of path
336
path = osutils.getcwd()
337
control, relpath = bzrdir.BzrDir.open_containing(path)
339
return control.open_workingtree(), relpath
342
def open_downlevel(path=None):
343
"""Open an unsupported working tree.
345
Only intended for advanced situations like upgrading part of a bzrdir.
347
return WorkingTree.open(path, _unsupported=True)
350
def find_trees(location):
351
def list_current(transport):
352
return [d for d in transport.list_dir('') if d != '.bzr']
353
def evaluate(bzrdir):
355
tree = bzrdir.open_workingtree()
356
except errors.NoWorkingTree:
360
transport = get_transport(location)
361
iterator = bzrdir.BzrDir.find_bzrdirs(transport, evaluate=evaluate,
362
list_current=list_current)
363
return [t for t in iterator if t is not None]
365
# should be deprecated - this is slow and in any case treating them as a
366
# container is (we now know) bad style -- mbp 20070302
367
## @deprecated_method(zero_fifteen)
369
"""Iterate through file_ids for this tree.
371
file_ids are in a WorkingTree if they are in the working inventory
372
and the working file exists.
374
inv = self._inventory
375
for path, ie in inv.iter_entries():
376
if osutils.lexists(self.abspath(path)):
379
def all_file_ids(self):
380
"""See Tree.iter_all_file_ids"""
381
return set(self.inventory)
384
return "<%s of %s>" % (self.__class__.__name__,
385
getattr(self, 'basedir', None))
387
def abspath(self, filename):
388
return pathjoin(self.basedir, filename)
390
def basis_tree(self):
391
"""Return RevisionTree for the current last revision.
393
If the left most parent is a ghost then the returned tree will be an
394
empty tree - one obtained by calling
395
repository.revision_tree(NULL_REVISION).
398
revision_id = self.get_parent_ids()[0]
400
# no parents, return an empty revision tree.
401
# in the future this should return the tree for
402
# 'empty:' - the implicit root empty tree.
403
return self.branch.repository.revision_tree(
404
_mod_revision.NULL_REVISION)
406
return self.revision_tree(revision_id)
407
except errors.NoSuchRevision:
409
# No cached copy available, retrieve from the repository.
410
# FIXME? RBC 20060403 should we cache the inventory locally
413
return self.branch.repository.revision_tree(revision_id)
414
except (errors.RevisionNotPresent, errors.NoSuchRevision):
415
# the basis tree *may* be a ghost or a low level error may have
416
# occured. If the revision is present, its a problem, if its not
418
if self.branch.repository.has_revision(revision_id):
420
# the basis tree is a ghost so return an empty tree.
421
return self.branch.repository.revision_tree(
422
_mod_revision.NULL_REVISION)
425
self._flush_ignore_list_cache()
427
def relpath(self, path):
428
"""Return the local path portion from a given path.
430
The path may be absolute or relative. If its a relative path it is
431
interpreted relative to the python current working directory.
433
return osutils.relpath(self.basedir, path)
435
def has_filename(self, filename):
436
return osutils.lexists(self.abspath(filename))
438
def get_file(self, file_id, path=None):
439
return self.get_file_with_stat(file_id, path)[0]
441
def get_file_with_stat(self, file_id, path=None, _fstat=os.fstat):
442
"""See MutableTree.get_file_with_stat."""
444
path = self.id2path(file_id)
445
file_obj = self.get_file_byname(path)
446
return (file_obj, _fstat(file_obj.fileno()))
448
def get_file_byname(self, filename):
449
return file(self.abspath(filename), 'rb')
451
def get_file_lines(self, file_id, path=None):
452
"""See Tree.get_file_lines()"""
453
file = self.get_file(file_id, path)
455
return file.readlines()
460
def annotate_iter(self, file_id, default_revision=CURRENT_REVISION):
461
"""See Tree.annotate_iter
463
This implementation will use the basis tree implementation if possible.
464
Lines not in the basis are attributed to CURRENT_REVISION
466
If there are pending merges, lines added by those merges will be
467
incorrectly attributed to CURRENT_REVISION (but after committing, the
468
attribution will be correct).
470
basis = self.basis_tree()
473
changes = self.iter_changes(basis, True, [self.id2path(file_id)],
474
require_versioned=True).next()
475
changed_content, kind = changes[2], changes[6]
476
if not changed_content:
477
return basis.annotate_iter(file_id)
481
if kind[0] != 'file':
484
old_lines = list(basis.annotate_iter(file_id))
486
for tree in self.branch.repository.revision_trees(
487
self.get_parent_ids()[1:]):
488
if file_id not in tree:
490
old.append(list(tree.annotate_iter(file_id)))
491
return annotate.reannotate(old, self.get_file(file_id).readlines(),
496
def _get_ancestors(self, default_revision):
497
ancestors = set([default_revision])
498
for parent_id in self.get_parent_ids():
499
ancestors.update(self.branch.repository.get_ancestry(
500
parent_id, topo_sorted=False))
503
def get_parent_ids(self):
504
"""See Tree.get_parent_ids.
506
This implementation reads the pending merges list and last_revision
507
value and uses that to decide what the parents list should be.
509
last_rev = _mod_revision.ensure_null(self._last_revision())
510
if _mod_revision.NULL_REVISION == last_rev:
515
merges_file = self._transport.get('pending-merges')
516
except errors.NoSuchFile:
519
for l in merges_file.readlines():
520
revision_id = l.rstrip('\n')
521
parents.append(revision_id)
525
def get_root_id(self):
526
"""Return the id of this trees root"""
527
return self._inventory.root.file_id
529
def _get_store_filename(self, file_id):
530
## XXX: badly named; this is not in the store at all
531
return self.abspath(self.id2path(file_id))
534
def clone(self, to_bzrdir, revision_id=None):
535
"""Duplicate this working tree into to_bzr, including all state.
537
Specifically modified files are kept as modified, but
538
ignored and unknown files are discarded.
540
If you want to make a new line of development, see bzrdir.sprout()
543
If not None, the cloned tree will have its last revision set to
544
revision, and and difference between the source trees last revision
545
and this one merged in.
547
# assumes the target bzr dir format is compatible.
548
result = to_bzrdir.create_workingtree()
549
self.copy_content_into(result, revision_id)
553
def copy_content_into(self, tree, revision_id=None):
554
"""Copy the current content and user files of this tree into tree."""
555
tree.set_root_id(self.get_root_id())
556
if revision_id is None:
557
merge.transform_tree(tree, self)
559
# TODO now merge from tree.last_revision to revision (to preserve
560
# user local changes)
561
merge.transform_tree(tree, self)
562
tree.set_parent_ids([revision_id])
564
def id2abspath(self, file_id):
565
return self.abspath(self.id2path(file_id))
567
def has_id(self, file_id):
568
# files that have been deleted are excluded
570
if not inv.has_id(file_id):
572
path = inv.id2path(file_id)
573
return osutils.lexists(self.abspath(path))
575
def has_or_had_id(self, file_id):
576
if file_id == self.inventory.root.file_id:
578
return self.inventory.has_id(file_id)
580
__contains__ = has_id
582
def get_file_size(self, file_id):
583
"""See Tree.get_file_size"""
585
return os.path.getsize(self.id2abspath(file_id))
587
if e.errno != errno.ENOENT:
593
def get_file_sha1(self, file_id, path=None, stat_value=None):
595
path = self._inventory.id2path(file_id)
596
return self._hashcache.get_sha1(path, stat_value)
598
def get_file_mtime(self, file_id, path=None):
600
path = self.inventory.id2path(file_id)
601
return os.lstat(self.abspath(path)).st_mtime
603
def _is_executable_from_path_and_stat_from_basis(self, path, stat_result):
604
file_id = self.path2id(path)
605
return self._inventory[file_id].executable
607
def _is_executable_from_path_and_stat_from_stat(self, path, stat_result):
608
mode = stat_result.st_mode
609
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
611
if not supports_executable():
612
def is_executable(self, file_id, path=None):
613
return self._inventory[file_id].executable
615
_is_executable_from_path_and_stat = \
616
_is_executable_from_path_and_stat_from_basis
618
def is_executable(self, file_id, path=None):
620
path = self.id2path(file_id)
621
mode = os.lstat(self.abspath(path)).st_mode
622
return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
624
_is_executable_from_path_and_stat = \
625
_is_executable_from_path_and_stat_from_stat
627
@needs_tree_write_lock
628
def _add(self, files, ids, kinds):
629
"""See MutableTree._add."""
630
# TODO: Re-adding a file that is removed in the working copy
631
# should probably put it back with the previous ID.
632
# the read and write working inventory should not occur in this
633
# function - they should be part of lock_write and unlock.
635
for f, file_id, kind in zip(files, ids, kinds):
637
inv.add_path(f, kind=kind)
639
inv.add_path(f, kind=kind, file_id=file_id)
640
self._inventory_is_modified = True
642
@needs_tree_write_lock
643
def _gather_kinds(self, files, kinds):
644
"""See MutableTree._gather_kinds."""
645
for pos, f in enumerate(files):
646
if kinds[pos] is None:
647
fullpath = normpath(self.abspath(f))
649
kinds[pos] = file_kind(fullpath)
651
if e.errno == errno.ENOENT:
652
raise errors.NoSuchFile(fullpath)
655
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
656
"""Add revision_id as a parent.
658
This is equivalent to retrieving the current list of parent ids
659
and setting the list to its value plus revision_id.
661
:param revision_id: The revision id to add to the parent list. It may
662
be a ghost revision as long as its not the first parent to be added,
663
or the allow_leftmost_as_ghost parameter is set True.
664
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
666
parents = self.get_parent_ids() + [revision_id]
667
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
668
or allow_leftmost_as_ghost)
670
@needs_tree_write_lock
671
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
672
"""Add revision_id, tree tuple as a parent.
674
This is equivalent to retrieving the current list of parent trees
675
and setting the list to its value plus parent_tuple. See also
676
add_parent_tree_id - if you only have a parent id available it will be
677
simpler to use that api. If you have the parent already available, using
678
this api is preferred.
680
:param parent_tuple: The (revision id, tree) to add to the parent list.
681
If the revision_id is a ghost, pass None for the tree.
682
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
684
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
685
if len(parent_ids) > 1:
686
# the leftmost may have already been a ghost, preserve that if it
688
allow_leftmost_as_ghost = True
689
self.set_parent_ids(parent_ids,
690
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
692
@needs_tree_write_lock
693
def add_pending_merge(self, *revision_ids):
694
# TODO: Perhaps should check at this point that the
695
# history of the revision is actually present?
696
parents = self.get_parent_ids()
698
for rev_id in revision_ids:
699
if rev_id in parents:
701
parents.append(rev_id)
704
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
706
def path_content_summary(self, path, _lstat=os.lstat,
707
_mapper=osutils.file_kind_from_stat_mode):
708
"""See Tree.path_content_summary."""
709
abspath = self.abspath(path)
711
stat_result = _lstat(abspath)
713
if getattr(e, 'errno', None) == errno.ENOENT:
715
return ('missing', None, None, None)
716
# propagate other errors
718
kind = _mapper(stat_result.st_mode)
720
size = stat_result.st_size
721
# try for a stat cache lookup
722
executable = self._is_executable_from_path_and_stat(path, stat_result)
723
return (kind, size, executable, self._sha_from_stat(
725
elif kind == 'directory':
726
# perhaps it looks like a plain directory, but it's really a
728
if self._directory_is_tree_reference(path):
729
kind = 'tree-reference'
730
return kind, None, None, None
731
elif kind == 'symlink':
732
return ('symlink', None, None,
733
os.readlink(abspath.encode(osutils._fs_enc)
734
).decode(osutils._fs_enc))
736
return (kind, None, None, None)
738
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
739
"""Common ghost checking functionality from set_parent_*.
741
This checks that the left hand-parent exists if there are any
744
if len(revision_ids) > 0:
745
leftmost_id = revision_ids[0]
746
if (not allow_leftmost_as_ghost and not
747
self.branch.repository.has_revision(leftmost_id)):
748
raise errors.GhostRevisionUnusableHere(leftmost_id)
750
def _set_merges_from_parent_ids(self, parent_ids):
751
merges = parent_ids[1:]
752
self._transport.put_bytes('pending-merges', '\n'.join(merges),
753
mode=self._control_files._file_mode)
755
def _filter_parent_ids_by_ancestry(self, revision_ids):
756
"""Check that all merged revisions are proper 'heads'.
758
This will always return the first revision_id, and any merged revisions
761
if len(revision_ids) == 0:
763
graph = self.branch.repository.get_graph()
764
heads = graph.heads(revision_ids)
765
new_revision_ids = revision_ids[:1]
766
for revision_id in revision_ids[1:]:
767
if revision_id in heads and revision_id not in new_revision_ids:
768
new_revision_ids.append(revision_id)
769
if new_revision_ids != revision_ids:
770
trace.mutter('requested to set revision_ids = %s,'
771
' but filtered to %s', revision_ids, new_revision_ids)
772
return new_revision_ids
774
@needs_tree_write_lock
775
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
776
"""Set the parent ids to revision_ids.
778
See also set_parent_trees. This api will try to retrieve the tree data
779
for each element of revision_ids from the trees repository. If you have
780
tree data already available, it is more efficient to use
781
set_parent_trees rather than set_parent_ids. set_parent_ids is however
782
an easier API to use.
784
:param revision_ids: The revision_ids to set as the parent ids of this
785
working tree. Any of these may be ghosts.
787
self._check_parents_for_ghosts(revision_ids,
788
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
789
for revision_id in revision_ids:
790
_mod_revision.check_not_reserved_id(revision_id)
792
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
794
if len(revision_ids) > 0:
795
self.set_last_revision(revision_ids[0])
797
self.set_last_revision(_mod_revision.NULL_REVISION)
799
self._set_merges_from_parent_ids(revision_ids)
801
@needs_tree_write_lock
802
def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
803
"""See MutableTree.set_parent_trees."""
804
parent_ids = [rev for (rev, tree) in parents_list]
805
for revision_id in parent_ids:
806
_mod_revision.check_not_reserved_id(revision_id)
808
self._check_parents_for_ghosts(parent_ids,
809
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
811
parent_ids = self._filter_parent_ids_by_ancestry(parent_ids)
813
if len(parent_ids) == 0:
814
leftmost_parent_id = _mod_revision.NULL_REVISION
815
leftmost_parent_tree = None
817
leftmost_parent_id, leftmost_parent_tree = parents_list[0]
819
if self._change_last_revision(leftmost_parent_id):
820
if leftmost_parent_tree is None:
821
# If we don't have a tree, fall back to reading the
822
# parent tree from the repository.
823
self._cache_basis_inventory(leftmost_parent_id)
825
inv = leftmost_parent_tree.inventory
826
xml = self._create_basis_xml_from_inventory(
827
leftmost_parent_id, inv)
828
self._write_basis_inventory(xml)
829
self._set_merges_from_parent_ids(parent_ids)
831
@needs_tree_write_lock
832
def set_pending_merges(self, rev_list):
833
parents = self.get_parent_ids()
834
leftmost = parents[:1]
835
new_parents = leftmost + rev_list
836
self.set_parent_ids(new_parents)
838
@needs_tree_write_lock
839
def set_merge_modified(self, modified_hashes):
841
for file_id, hash in modified_hashes.iteritems():
842
yield Stanza(file_id=file_id.decode('utf8'), hash=hash)
843
self._put_rio('merge-hashes', iter_stanzas(), MERGE_MODIFIED_HEADER_1)
845
def _sha_from_stat(self, path, stat_result):
846
"""Get a sha digest from the tree's stat cache.
848
The default implementation assumes no stat cache is present.
850
:param path: The path.
851
:param stat_result: The stat result being looked up.
855
def _put_rio(self, filename, stanzas, header):
856
self._must_be_locked()
857
my_file = rio_file(stanzas, header)
858
self._transport.put_file(filename, my_file,
859
mode=self._control_files._file_mode)
861
@needs_write_lock # because merge pulls data into the branch.
862
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
864
"""Merge from a branch into this working tree.
866
:param branch: The branch to merge from.
867
:param to_revision: If non-None, the merge will merge to to_revision,
868
but not beyond it. to_revision does not need to be in the history
869
of the branch when it is supplied. If None, to_revision defaults to
870
branch.last_revision().
872
from bzrlib.merge import Merger, Merge3Merger
873
pb = bzrlib.ui.ui_factory.nested_progress_bar()
875
merger = Merger(self.branch, this_tree=self, pb=pb)
876
merger.pp = ProgressPhase("Merge phase", 5, pb)
877
merger.pp.next_phase()
878
# check that there are no
880
merger.check_basis(check_clean=True, require_commits=False)
881
if to_revision is None:
882
to_revision = _mod_revision.ensure_null(branch.last_revision())
883
merger.other_rev_id = to_revision
884
if _mod_revision.is_null(merger.other_rev_id):
885
raise errors.NoCommits(branch)
886
self.branch.fetch(branch, last_revision=merger.other_rev_id)
887
merger.other_basis = merger.other_rev_id
888
merger.other_tree = self.branch.repository.revision_tree(
890
merger.other_branch = branch
891
merger.pp.next_phase()
892
if from_revision is None:
895
merger.set_base_revision(from_revision, branch)
896
if merger.base_rev_id == merger.other_rev_id:
897
raise errors.PointlessMerge
898
merger.backup_files = False
899
if merge_type is None:
900
merger.merge_type = Merge3Merger
902
merger.merge_type = merge_type
903
merger.set_interesting_files(None)
904
merger.show_base = False
905
merger.reprocess = False
906
conflicts = merger.do_merge()
913
def merge_modified(self):
914
"""Return a dictionary of files modified by a merge.
916
The list is initialized by WorkingTree.set_merge_modified, which is
917
typically called after we make some automatic updates to the tree
920
This returns a map of file_id->sha1, containing only files which are
921
still in the working inventory and have that text hash.
924
hashfile = self._transport.get('merge-hashes')
925
except errors.NoSuchFile:
930
if hashfile.next() != MERGE_MODIFIED_HEADER_1 + '\n':
931
raise errors.MergeModifiedFormatError()
932
except StopIteration:
933
raise errors.MergeModifiedFormatError()
934
for s in RioReader(hashfile):
935
# RioReader reads in Unicode, so convert file_ids back to utf8
936
file_id = osutils.safe_file_id(s.get("file_id"), warn=False)
937
if file_id not in self.inventory:
939
text_hash = s.get("hash")
940
if text_hash == self.get_file_sha1(file_id):
941
merge_hashes[file_id] = text_hash
947
def mkdir(self, path, file_id=None):
948
"""See MutableTree.mkdir()."""
950
file_id = generate_ids.gen_file_id(os.path.basename(path))
951
os.mkdir(self.abspath(path))
952
self.add(path, file_id, 'directory')
955
def get_symlink_target(self, file_id):
956
return os.readlink(self.id2abspath(file_id).encode(osutils._fs_enc))
959
def subsume(self, other_tree):
960
def add_children(inventory, entry):
961
for child_entry in entry.children.values():
962
inventory._byid[child_entry.file_id] = child_entry
963
if child_entry.kind == 'directory':
964
add_children(inventory, child_entry)
965
if other_tree.get_root_id() == self.get_root_id():
966
raise errors.BadSubsumeSource(self, other_tree,
967
'Trees have the same root')
969
other_tree_path = self.relpath(other_tree.basedir)
970
except errors.PathNotChild:
971
raise errors.BadSubsumeSource(self, other_tree,
972
'Tree is not contained by the other')
973
new_root_parent = self.path2id(osutils.dirname(other_tree_path))
974
if new_root_parent is None:
975
raise errors.BadSubsumeSource(self, other_tree,
976
'Parent directory is not versioned.')
977
# We need to ensure that the result of a fetch will have a
978
# versionedfile for the other_tree root, and only fetching into
979
# RepositoryKnit2 guarantees that.
980
if not self.branch.repository.supports_rich_root():
981
raise errors.SubsumeTargetNeedsUpgrade(other_tree)
982
other_tree.lock_tree_write()
984
new_parents = other_tree.get_parent_ids()
985
other_root = other_tree.inventory.root
986
other_root.parent_id = new_root_parent
987
other_root.name = osutils.basename(other_tree_path)
988
self.inventory.add(other_root)
989
add_children(self.inventory, other_root)
990
self._write_inventory(self.inventory)
991
# normally we don't want to fetch whole repositories, but i think
992
# here we really do want to consolidate the whole thing.
993
for parent_id in other_tree.get_parent_ids():
994
self.branch.fetch(other_tree.branch, parent_id)
995
self.add_parent_tree_id(parent_id)
998
other_tree.bzrdir.retire_bzrdir()
1000
def _setup_directory_is_tree_reference(self):
1001
if self._branch.repository._format.supports_tree_reference:
1002
self._directory_is_tree_reference = \
1003
self._directory_may_be_tree_reference
1005
self._directory_is_tree_reference = \
1006
self._directory_is_never_tree_reference
1008
def _directory_is_never_tree_reference(self, relpath):
1011
def _directory_may_be_tree_reference(self, relpath):
1012
# as a special case, if a directory contains control files then
1013
# it's a tree reference, except that the root of the tree is not
1014
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
1015
# TODO: We could ask all the control formats whether they
1016
# recognize this directory, but at the moment there's no cheap api
1017
# to do that. Since we probably can only nest bzr checkouts and
1018
# they always use this name it's ok for now. -- mbp 20060306
1020
# FIXME: There is an unhandled case here of a subdirectory
1021
# containing .bzr but not a branch; that will probably blow up
1022
# when you try to commit it. It might happen if there is a
1023
# checkout in a subdirectory. This can be avoided by not adding
1026
@needs_tree_write_lock
1027
def extract(self, file_id, format=None):
1028
"""Extract a subtree from this tree.
1030
A new branch will be created, relative to the path for this tree.
1034
segments = osutils.splitpath(path)
1035
transport = self.branch.bzrdir.root_transport
1036
for name in segments:
1037
transport = transport.clone(name)
1038
transport.ensure_base()
1041
sub_path = self.id2path(file_id)
1042
branch_transport = mkdirs(sub_path)
1044
format = self.bzrdir.cloning_metadir()
1045
branch_transport.ensure_base()
1046
branch_bzrdir = format.initialize_on_transport(branch_transport)
1048
repo = branch_bzrdir.find_repository()
1049
except errors.NoRepositoryPresent:
1050
repo = branch_bzrdir.create_repository()
1051
if not repo.supports_rich_root():
1052
raise errors.RootNotRich()
1053
new_branch = branch_bzrdir.create_branch()
1054
new_branch.pull(self.branch)
1055
for parent_id in self.get_parent_ids():
1056
new_branch.fetch(self.branch, parent_id)
1057
tree_transport = self.bzrdir.root_transport.clone(sub_path)
1058
if tree_transport.base != branch_transport.base:
1059
tree_bzrdir = format.initialize_on_transport(tree_transport)
1060
branch.BranchReferenceFormat().initialize(tree_bzrdir, new_branch)
1062
tree_bzrdir = branch_bzrdir
1063
wt = tree_bzrdir.create_workingtree(NULL_REVISION)
1064
wt.set_parent_ids(self.get_parent_ids())
1065
my_inv = self.inventory
1066
child_inv = Inventory(root_id=None)
1067
new_root = my_inv[file_id]
1068
my_inv.remove_recursive_id(file_id)
1069
new_root.parent_id = None
1070
child_inv.add(new_root)
1071
self._write_inventory(my_inv)
1072
wt._write_inventory(child_inv)
1075
def _serialize(self, inventory, out_file):
1076
xml5.serializer_v5.write_inventory(self._inventory, out_file,
1079
def _deserialize(selt, in_file):
1080
return xml5.serializer_v5.read_inventory(in_file)
1083
"""Write the in memory inventory to disk."""
1084
# TODO: Maybe this should only write on dirty ?
1085
if self._control_files._lock_mode != 'w':
1086
raise errors.NotWriteLocked(self)
1088
self._serialize(self._inventory, sio)
1090
self._transport.put_file('inventory', sio,
1091
mode=self._control_files._file_mode)
1092
self._inventory_is_modified = False
1094
def _kind(self, relpath):
1095
return osutils.file_kind(self.abspath(relpath))
1097
def list_files(self, include_root=False):
1098
"""Recursively list all files as (path, class, kind, id, entry).
1100
Lists, but does not descend into unversioned directories.
1102
This does not include files that have been deleted in this
1105
Skips the control directory.
1107
# list_files is an iterator, so @needs_read_lock doesn't work properly
1108
# with it. So callers should be careful to always read_lock the tree.
1109
if not self.is_locked():
1110
raise errors.ObjectNotLocked(self)
1112
inv = self.inventory
1113
if include_root is True:
1114
yield ('', 'V', 'directory', inv.root.file_id, inv.root)
1115
# Convert these into local objects to save lookup times
1116
pathjoin = osutils.pathjoin
1117
file_kind = self._kind
1119
# transport.base ends in a slash, we want the piece
1120
# between the last two slashes
1121
transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
1123
fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
1125
# directory file_id, relative path, absolute path, reverse sorted children
1126
children = os.listdir(self.basedir)
1128
# jam 20060527 The kernel sized tree seems equivalent whether we
1129
# use a deque and popleft to keep them sorted, or if we use a plain
1130
# list and just reverse() them.
1131
children = collections.deque(children)
1132
stack = [(inv.root.file_id, u'', self.basedir, children)]
1134
from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
1137
f = children.popleft()
1138
## TODO: If we find a subdirectory with its own .bzr
1139
## directory, then that is a separate tree and we
1140
## should exclude it.
1142
# the bzrdir for this tree
1143
if transport_base_dir == f:
1146
# we know that from_dir_relpath and from_dir_abspath never end in a slash
1147
# and 'f' doesn't begin with one, we can do a string op, rather
1148
# than the checks of pathjoin(), all relative paths will have an extra slash
1150
fp = from_dir_relpath + '/' + f
1153
fap = from_dir_abspath + '/' + f
1155
f_ie = inv.get_child(from_dir_id, f)
1158
elif self.is_ignored(fp[1:]):
1161
# we may not have found this file, because of a unicode issue
1162
f_norm, can_access = osutils.normalized_filename(f)
1163
if f == f_norm or not can_access:
1164
# No change, so treat this file normally
1167
# this file can be accessed by a normalized path
1168
# check again if it is versioned
1169
# these lines are repeated here for performance
1171
fp = from_dir_relpath + '/' + f
1172
fap = from_dir_abspath + '/' + f
1173
f_ie = inv.get_child(from_dir_id, f)
1176
elif self.is_ignored(fp[1:]):
1183
# make a last minute entry
1185
yield fp[1:], c, fk, f_ie.file_id, f_ie
1188
yield fp[1:], c, fk, None, fk_entries[fk]()
1190
yield fp[1:], c, fk, None, TreeEntry()
1193
if fk != 'directory':
1196
# But do this child first
1197
new_children = os.listdir(fap)
1199
new_children = collections.deque(new_children)
1200
stack.append((f_ie.file_id, fp, fap, new_children))
1201
# Break out of inner loop,
1202
# so that we start outer loop with child
1205
# if we finished all children, pop it off the stack
1208
@needs_tree_write_lock
1209
def move(self, from_paths, to_dir=None, after=False, **kwargs):
1212
to_dir must exist in the inventory.
1214
If to_dir exists and is a directory, the files are moved into
1215
it, keeping their old names.
1217
Note that to_dir is only the last component of the new name;
1218
this doesn't change the directory.
1220
For each entry in from_paths the move mode will be determined
1223
The first mode moves the file in the filesystem and updates the
1224
inventory. The second mode only updates the inventory without
1225
touching the file on the filesystem. This is the new mode introduced
1228
move uses the second mode if 'after == True' and the target is not
1229
versioned but present in the working tree.
1231
move uses the second mode if 'after == False' and the source is
1232
versioned but no longer in the working tree, and the target is not
1233
versioned but present in the working tree.
1235
move uses the first mode if 'after == False' and the source is
1236
versioned and present in the working tree, and the target is not
1237
versioned and not present in the working tree.
1239
Everything else results in an error.
1241
This returns a list of (from_path, to_path) pairs for each
1242
entry that is moved.
1247
# check for deprecated use of signature
1249
to_dir = kwargs.get('to_name', None)
1251
raise TypeError('You must supply a target directory')
1253
symbol_versioning.warn('The parameter to_name was deprecated'
1254
' in version 0.13. Use to_dir instead',
1257
# check destination directory
1258
if isinstance(from_paths, basestring):
1260
inv = self.inventory
1261
to_abs = self.abspath(to_dir)
1262
if not isdir(to_abs):
1263
raise errors.BzrMoveFailedError('',to_dir,
1264
errors.NotADirectory(to_abs))
1265
if not self.has_filename(to_dir):
1266
raise errors.BzrMoveFailedError('',to_dir,
1267
errors.NotInWorkingDirectory(to_dir))
1268
to_dir_id = inv.path2id(to_dir)
1269
if to_dir_id is None:
1270
raise errors.BzrMoveFailedError('',to_dir,
1271
errors.NotVersionedError(path=str(to_dir)))
1273
to_dir_ie = inv[to_dir_id]
1274
if to_dir_ie.kind != 'directory':
1275
raise errors.BzrMoveFailedError('',to_dir,
1276
errors.NotADirectory(to_abs))
1278
# create rename entries and tuples
1279
for from_rel in from_paths:
1280
from_tail = splitpath(from_rel)[-1]
1281
from_id = inv.path2id(from_rel)
1283
raise errors.BzrMoveFailedError(from_rel,to_dir,
1284
errors.NotVersionedError(path=str(from_rel)))
1286
from_entry = inv[from_id]
1287
from_parent_id = from_entry.parent_id
1288
to_rel = pathjoin(to_dir, from_tail)
1289
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1291
from_tail=from_tail,
1292
from_parent_id=from_parent_id,
1293
to_rel=to_rel, to_tail=from_tail,
1294
to_parent_id=to_dir_id)
1295
rename_entries.append(rename_entry)
1296
rename_tuples.append((from_rel, to_rel))
1298
# determine which move mode to use. checks also for movability
1299
rename_entries = self._determine_mv_mode(rename_entries, after)
1301
original_modified = self._inventory_is_modified
1304
self._inventory_is_modified = True
1305
self._move(rename_entries)
1307
# restore the inventory on error
1308
self._inventory_is_modified = original_modified
1310
self._write_inventory(inv)
1311
return rename_tuples
1313
def _determine_mv_mode(self, rename_entries, after=False):
1314
"""Determines for each from-to pair if both inventory and working tree
1315
or only the inventory has to be changed.
1317
Also does basic plausability tests.
1319
inv = self.inventory
1321
for rename_entry in rename_entries:
1322
# store to local variables for easier reference
1323
from_rel = rename_entry.from_rel
1324
from_id = rename_entry.from_id
1325
to_rel = rename_entry.to_rel
1326
to_id = inv.path2id(to_rel)
1327
only_change_inv = False
1329
# check the inventory for source and destination
1331
raise errors.BzrMoveFailedError(from_rel,to_rel,
1332
errors.NotVersionedError(path=str(from_rel)))
1333
if to_id is not None:
1334
raise errors.BzrMoveFailedError(from_rel,to_rel,
1335
errors.AlreadyVersionedError(path=str(to_rel)))
1337
# try to determine the mode for rename (only change inv or change
1338
# inv and file system)
1340
if not self.has_filename(to_rel):
1341
raise errors.BzrMoveFailedError(from_id,to_rel,
1342
errors.NoSuchFile(path=str(to_rel),
1343
extra="New file has not been created yet"))
1344
only_change_inv = True
1345
elif not self.has_filename(from_rel) and self.has_filename(to_rel):
1346
only_change_inv = True
1347
elif self.has_filename(from_rel) and not self.has_filename(to_rel):
1348
only_change_inv = False
1349
elif (not self.case_sensitive
1350
and from_rel.lower() == to_rel.lower()
1351
and self.has_filename(from_rel)):
1352
only_change_inv = False
1354
# something is wrong, so lets determine what exactly
1355
if not self.has_filename(from_rel) and \
1356
not self.has_filename(to_rel):
1357
raise errors.BzrRenameFailedError(from_rel,to_rel,
1358
errors.PathsDoNotExist(paths=(str(from_rel),
1361
raise errors.RenameFailedFilesExist(from_rel, to_rel)
1362
rename_entry.only_change_inv = only_change_inv
1363
return rename_entries
1365
def _move(self, rename_entries):
1366
"""Moves a list of files.
1368
Depending on the value of the flag 'only_change_inv', the
1369
file will be moved on the file system or not.
1371
inv = self.inventory
1374
for entry in rename_entries:
1376
self._move_entry(entry)
1378
self._rollback_move(moved)
1382
def _rollback_move(self, moved):
1383
"""Try to rollback a previous move in case of an filesystem error."""
1384
inv = self.inventory
1387
self._move_entry(_RenameEntry(entry.to_rel, entry.from_id,
1388
entry.to_tail, entry.to_parent_id, entry.from_rel,
1389
entry.from_tail, entry.from_parent_id,
1390
entry.only_change_inv))
1391
except errors.BzrMoveFailedError, e:
1392
raise errors.BzrMoveFailedError( '', '', "Rollback failed."
1393
" The working tree is in an inconsistent state."
1394
" Please consider doing a 'bzr revert'."
1395
" Error message is: %s" % e)
1397
def _move_entry(self, entry):
1398
inv = self.inventory
1399
from_rel_abs = self.abspath(entry.from_rel)
1400
to_rel_abs = self.abspath(entry.to_rel)
1401
if from_rel_abs == to_rel_abs:
1402
raise errors.BzrMoveFailedError(entry.from_rel, entry.to_rel,
1403
"Source and target are identical.")
1405
if not entry.only_change_inv:
1407
osutils.rename(from_rel_abs, to_rel_abs)
1409
raise errors.BzrMoveFailedError(entry.from_rel,
1411
inv.rename(entry.from_id, entry.to_parent_id, entry.to_tail)
1413
@needs_tree_write_lock
1414
def rename_one(self, from_rel, to_rel, after=False):
1417
This can change the directory or the filename or both.
1419
rename_one has several 'modes' to work. First, it can rename a physical
1420
file and change the file_id. That is the normal mode. Second, it can
1421
only change the file_id without touching any physical file. This is
1422
the new mode introduced in version 0.15.
1424
rename_one uses the second mode if 'after == True' and 'to_rel' is not
1425
versioned but present in the working tree.
1427
rename_one uses the second mode if 'after == False' and 'from_rel' is
1428
versioned but no longer in the working tree, and 'to_rel' is not
1429
versioned but present in the working tree.
1431
rename_one uses the first mode if 'after == False' and 'from_rel' is
1432
versioned and present in the working tree, and 'to_rel' is not
1433
versioned and not present in the working tree.
1435
Everything else results in an error.
1437
inv = self.inventory
1440
# create rename entries and tuples
1441
from_tail = splitpath(from_rel)[-1]
1442
from_id = inv.path2id(from_rel)
1444
raise errors.BzrRenameFailedError(from_rel,to_rel,
1445
errors.NotVersionedError(path=str(from_rel)))
1446
from_entry = inv[from_id]
1447
from_parent_id = from_entry.parent_id
1448
to_dir, to_tail = os.path.split(to_rel)
1449
to_dir_id = inv.path2id(to_dir)
1450
rename_entry = WorkingTree._RenameEntry(from_rel=from_rel,
1452
from_tail=from_tail,
1453
from_parent_id=from_parent_id,
1454
to_rel=to_rel, to_tail=to_tail,
1455
to_parent_id=to_dir_id)
1456
rename_entries.append(rename_entry)
1458
# determine which move mode to use. checks also for movability
1459
rename_entries = self._determine_mv_mode(rename_entries, after)
1461
# check if the target changed directory and if the target directory is
1463
if to_dir_id is None:
1464
raise errors.BzrMoveFailedError(from_rel,to_rel,
1465
errors.NotVersionedError(path=str(to_dir)))
1467
# all checks done. now we can continue with our actual work
1468
mutter('rename_one:\n'
1473
' to_dir_id {%s}\n',
1474
from_id, from_rel, to_rel, to_dir, to_dir_id)
1476
self._move(rename_entries)
1477
self._write_inventory(inv)
1479
class _RenameEntry(object):
1480
def __init__(self, from_rel, from_id, from_tail, from_parent_id,
1481
to_rel, to_tail, to_parent_id, only_change_inv=False):
1482
self.from_rel = from_rel
1483
self.from_id = from_id
1484
self.from_tail = from_tail
1485
self.from_parent_id = from_parent_id
1486
self.to_rel = to_rel
1487
self.to_tail = to_tail
1488
self.to_parent_id = to_parent_id
1489
self.only_change_inv = only_change_inv
1493
"""Return all unknown files.
1495
These are files in the working directory that are not versioned or
1496
control files or ignored.
1498
# force the extras method to be fully executed before returning, to
1499
# prevent race conditions with the lock
1501
[subp for subp in self.extras() if not self.is_ignored(subp)])
1503
@needs_tree_write_lock
1504
def unversion(self, file_ids):
1505
"""Remove the file ids in file_ids from the current versioned set.
1507
When a file_id is unversioned, all of its children are automatically
1510
:param file_ids: The file ids to stop versioning.
1511
:raises: NoSuchId if any fileid is not currently versioned.
1513
for file_id in file_ids:
1514
if self._inventory.has_id(file_id):
1515
self._inventory.remove_recursive_id(file_id)
1517
raise errors.NoSuchId(self, file_id)
1519
# in the future this should just set a dirty bit to wait for the
1520
# final unlock. However, until all methods of workingtree start
1521
# with the current in -memory inventory rather than triggering
1522
# a read, it is more complex - we need to teach read_inventory
1523
# to know when to read, and when to not read first... and possibly
1524
# to save first when the in memory one may be corrupted.
1525
# so for now, we just only write it if it is indeed dirty.
1527
self._write_inventory(self._inventory)
1529
def _iter_conflicts(self):
1531
for info in self.list_files():
1533
stem = get_conflicted_stem(path)
1536
if stem not in conflicted:
1537
conflicted.add(stem)
1541
def pull(self, source, overwrite=False, stop_revision=None,
1542
change_reporter=None, possible_transports=None):
1543
top_pb = bzrlib.ui.ui_factory.nested_progress_bar()
1546
pp = ProgressPhase("Pull phase", 2, top_pb)
1548
old_revision_info = self.branch.last_revision_info()
1549
basis_tree = self.basis_tree()
1550
count = self.branch.pull(source, overwrite, stop_revision,
1551
possible_transports=possible_transports)
1552
new_revision_info = self.branch.last_revision_info()
1553
if new_revision_info != old_revision_info:
1555
repository = self.branch.repository
1556
pb = bzrlib.ui.ui_factory.nested_progress_bar()
1557
basis_tree.lock_read()
1559
new_basis_tree = self.branch.basis_tree()
1566
change_reporter=change_reporter)
1567
if (basis_tree.inventory.root is None and
1568
new_basis_tree.inventory.root is not None):
1569
self.set_root_id(new_basis_tree.get_root_id())
1573
# TODO - dedup parents list with things merged by pull ?
1574
# reuse the revisiontree we merged against to set the new
1576
parent_trees = [(self.branch.last_revision(), new_basis_tree)]
1577
# we have to pull the merge trees out again, because
1578
# merge_inner has set the ids. - this corner is not yet
1579
# layered well enough to prevent double handling.
1580
# XXX TODO: Fix the double handling: telling the tree about
1581
# the already known parent data is wasteful.
1582
merges = self.get_parent_ids()[1:]
1583
parent_trees.extend([
1584
(parent, repository.revision_tree(parent)) for
1586
self.set_parent_trees(parent_trees)
1593
def put_file_bytes_non_atomic(self, file_id, bytes):
1594
"""See MutableTree.put_file_bytes_non_atomic."""
1595
stream = file(self.id2abspath(file_id), 'wb')
1600
# TODO: update the hashcache here ?
1603
"""Yield all unversioned files in this WorkingTree.
1605
If there are any unversioned directories then only the directory is
1606
returned, not all its children. But if there are unversioned files
1607
under a versioned subdirectory, they are returned.
1609
Currently returned depth-first, sorted by name within directories.
1610
This is the same order used by 'osutils.walkdirs'.
1612
## TODO: Work from given directory downwards
1613
for path, dir_entry in self.inventory.directories():
1614
# mutter("search for unknowns in %r", path)
1615
dirabs = self.abspath(path)
1616
if not isdir(dirabs):
1617
# e.g. directory deleted
1621
for subf in os.listdir(dirabs):
1624
if subf not in dir_entry.children:
1627
can_access) = osutils.normalized_filename(subf)
1628
except UnicodeDecodeError:
1629
path_os_enc = path.encode(osutils._fs_enc)
1630
relpath = path_os_enc + '/' + subf
1631
raise errors.BadFilenameEncoding(relpath,
1633
if subf_norm != subf and can_access:
1634
if subf_norm not in dir_entry.children:
1635
fl.append(subf_norm)
1641
subp = pathjoin(path, subf)
1644
def ignored_files(self):
1645
"""Yield list of PATH, IGNORE_PATTERN"""
1646
for subp in self.extras():
1647
pat = self.is_ignored(subp)
1651
def get_ignore_list(self):
1652
"""Return list of ignore patterns.
1654
Cached in the Tree object after the first call.
1656
ignoreset = getattr(self, '_ignoreset', None)
1657
if ignoreset is not None:
1660
ignore_globs = set()
1661
ignore_globs.update(ignores.get_runtime_ignores())
1662
ignore_globs.update(ignores.get_user_ignores())
1663
if self.has_filename(bzrlib.IGNORE_FILENAME):
1664
f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
1666
ignore_globs.update(ignores.parse_ignore_file(f))
1669
self._ignoreset = ignore_globs
1672
def _flush_ignore_list_cache(self):
1673
"""Resets the cached ignore list to force a cache rebuild."""
1674
self._ignoreset = None
1675
self._ignoreglobster = None
1677
def is_ignored(self, filename):
1678
r"""Check whether the filename matches an ignore pattern.
1680
Patterns containing '/' or '\' need to match the whole path;
1681
others match against only the last component.
1683
If the file is ignored, returns the pattern which caused it to
1684
be ignored, otherwise None. So this can simply be used as a
1685
boolean if desired."""
1686
if getattr(self, '_ignoreglobster', None) is None:
1687
self._ignoreglobster = globbing.Globster(self.get_ignore_list())
1688
return self._ignoreglobster.match(filename)
1690
def kind(self, file_id):
1691
return file_kind(self.id2abspath(file_id))
1693
def stored_kind(self, file_id):
1694
"""See Tree.stored_kind"""
1695
return self.inventory[file_id].kind
1697
def _comparison_data(self, entry, path):
1698
abspath = self.abspath(path)
1700
stat_value = os.lstat(abspath)
1702
if getattr(e, 'errno', None) == errno.ENOENT:
1709
mode = stat_value.st_mode
1710
kind = osutils.file_kind_from_stat_mode(mode)
1711
if not supports_executable():
1712
executable = entry is not None and entry.executable
1714
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1715
return kind, executable, stat_value
1717
def _file_size(self, entry, stat_value):
1718
return stat_value.st_size
1720
def last_revision(self):
1721
"""Return the last revision of the branch for this tree.
1723
This format tree does not support a separate marker for last-revision
1724
compared to the branch.
1726
See MutableTree.last_revision
1728
return self._last_revision()
1731
def _last_revision(self):
1732
"""helper for get_parent_ids."""
1733
return _mod_revision.ensure_null(self.branch.last_revision())
1735
def is_locked(self):
1736
return self._control_files.is_locked()
1738
def _must_be_locked(self):
1739
if not self.is_locked():
1740
raise errors.ObjectNotLocked(self)
1742
def lock_read(self):
1743
"""See Branch.lock_read, and WorkingTree.unlock."""
1744
if not self.is_locked():
1746
self.branch.lock_read()
1748
return self._control_files.lock_read()
1750
self.branch.unlock()
1753
def lock_tree_write(self):
1754
"""See MutableTree.lock_tree_write, and WorkingTree.unlock."""
1755
if not self.is_locked():
1757
self.branch.lock_read()
1759
return self._control_files.lock_write()
1761
self.branch.unlock()
1764
def lock_write(self):
1765
"""See MutableTree.lock_write, and WorkingTree.unlock."""
1766
if not self.is_locked():
1768
self.branch.lock_write()
1770
return self._control_files.lock_write()
1772
self.branch.unlock()
1775
def get_physical_lock_status(self):
1776
return self._control_files.get_physical_lock_status()
1778
def _basis_inventory_name(self):
1779
return 'basis-inventory-cache'
1781
def _reset_data(self):
1782
"""Reset transient data that cannot be revalidated."""
1783
self._inventory_is_modified = False
1784
result = self._deserialize(self._transport.get('inventory'))
1785
self._set_inventory(result, dirty=False)
1787
@needs_tree_write_lock
1788
def set_last_revision(self, new_revision):
1789
"""Change the last revision in the working tree."""
1790
if self._change_last_revision(new_revision):
1791
self._cache_basis_inventory(new_revision)
1793
def _change_last_revision(self, new_revision):
1794
"""Template method part of set_last_revision to perform the change.
1796
This is used to allow WorkingTree3 instances to not affect branch
1797
when their last revision is set.
1799
if _mod_revision.is_null(new_revision):
1800
self.branch.set_revision_history([])
1803
self.branch.generate_revision_history(new_revision)
1804
except errors.NoSuchRevision:
1805
# not present in the repo - dont try to set it deeper than the tip
1806
self.branch.set_revision_history([new_revision])
1809
def _write_basis_inventory(self, xml):
1810
"""Write the basis inventory XML to the basis-inventory file"""
1811
path = self._basis_inventory_name()
1813
self._transport.put_file(path, sio,
1814
mode=self._control_files._file_mode)
1816
def _create_basis_xml_from_inventory(self, revision_id, inventory):
1817
"""Create the text that will be saved in basis-inventory"""
1818
inventory.revision_id = revision_id
1819
return xml7.serializer_v7.write_inventory_to_string(inventory)
1821
def _cache_basis_inventory(self, new_revision):
1822
"""Cache new_revision as the basis inventory."""
1823
# TODO: this should allow the ready-to-use inventory to be passed in,
1824
# as commit already has that ready-to-use [while the format is the
1827
# this double handles the inventory - unpack and repack -
1828
# but is easier to understand. We can/should put a conditional
1829
# in here based on whether the inventory is in the latest format
1830
# - perhaps we should repack all inventories on a repository
1832
# the fast path is to copy the raw xml from the repository. If the
1833
# xml contains 'revision_id="', then we assume the right
1834
# revision_id is set. We must check for this full string, because a
1835
# root node id can legitimately look like 'revision_id' but cannot
1837
xml = self.branch.repository.get_inventory_xml(new_revision)
1838
firstline = xml.split('\n', 1)[0]
1839
if (not 'revision_id="' in firstline or
1840
'format="7"' not in firstline):
1841
inv = self.branch.repository.deserialise_inventory(
1843
xml = self._create_basis_xml_from_inventory(new_revision, inv)
1844
self._write_basis_inventory(xml)
1845
except (errors.NoSuchRevision, errors.RevisionNotPresent):
1848
def read_basis_inventory(self):
1849
"""Read the cached basis inventory."""
1850
path = self._basis_inventory_name()
1851
return self._transport.get_bytes(path)
1854
def read_working_inventory(self):
1855
"""Read the working inventory.
1857
:raises errors.InventoryModified: read_working_inventory will fail
1858
when the current in memory inventory has been modified.
1860
# conceptually this should be an implementation detail of the tree.
1861
# XXX: Deprecate this.
1862
# ElementTree does its own conversion from UTF-8, so open in
1864
if self._inventory_is_modified:
1865
raise errors.InventoryModified(self)
1866
result = self._deserialize(self._transport.get('inventory'))
1867
self._set_inventory(result, dirty=False)
1870
@needs_tree_write_lock
1871
def remove(self, files, verbose=False, to_file=None, keep_files=True,
1873
"""Remove nominated files from the working inventory.
1875
:files: File paths relative to the basedir.
1876
:keep_files: If true, the files will also be kept.
1877
:force: Delete files and directories, even if they are changed and
1878
even if the directories are not empty.
1880
if isinstance(files, basestring):
1886
unknown_nested_files=set()
1888
def recurse_directory_to_add_files(directory):
1889
# Recurse directory and add all files
1890
# so we can check if they have changed.
1891
for parent_info, file_infos in\
1892
self.walkdirs(directory):
1893
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1894
# Is it versioned or ignored?
1895
if self.path2id(relpath) or self.is_ignored(relpath):
1896
# Add nested content for deletion.
1897
new_files.add(relpath)
1899
# Files which are not versioned and not ignored
1900
# should be treated as unknown.
1901
unknown_nested_files.add((relpath, None, kind))
1903
for filename in files:
1904
# Get file name into canonical form.
1905
abspath = self.abspath(filename)
1906
filename = self.relpath(abspath)
1907
if len(filename) > 0:
1908
new_files.add(filename)
1909
recurse_directory_to_add_files(filename)
1911
files = list(new_files)
1914
return # nothing to do
1916
# Sort needed to first handle directory content before the directory
1917
files.sort(reverse=True)
1919
# Bail out if we are going to delete files we shouldn't
1920
if not keep_files and not force:
1921
has_changed_files = len(unknown_nested_files) > 0
1922
if not has_changed_files:
1923
for (file_id, path, content_change, versioned, parent_id, name,
1924
kind, executable) in self.iter_changes(self.basis_tree(),
1925
include_unchanged=True, require_versioned=False,
1926
want_unversioned=True, specific_files=files):
1927
if versioned == (False, False):
1928
# The record is unknown ...
1929
if not self.is_ignored(path[1]):
1930
# ... but not ignored
1931
has_changed_files = True
1933
elif content_change and (kind[1] is not None):
1934
# Versioned and changed, but not deleted
1935
has_changed_files = True
1938
if has_changed_files:
1939
# Make delta show ALL applicable changes in error message.
1940
tree_delta = self.changes_from(self.basis_tree(),
1941
require_versioned=False, want_unversioned=True,
1942
specific_files=files)
1943
for unknown_file in unknown_nested_files:
1944
if unknown_file not in tree_delta.unversioned:
1945
tree_delta.unversioned.extend((unknown_file,))
1946
raise errors.BzrRemoveChangedFilesError(tree_delta)
1948
# Build inv_delta and delete files where applicaple,
1949
# do this before any modifications to inventory.
1951
fid = self.path2id(f)
1954
message = "%s is not versioned." % (f,)
1957
# having removed it, it must be either ignored or unknown
1958
if self.is_ignored(f):
1962
textui.show_status(new_status, self.kind(fid), f,
1965
inv_delta.append((f, None, fid, None))
1966
message = "removed %s" % (f,)
1969
abs_path = self.abspath(f)
1970
if osutils.lexists(abs_path):
1971
if (osutils.isdir(abs_path) and
1972
len(os.listdir(abs_path)) > 0):
1974
osutils.rmtree(abs_path)
1976
message = "%s is not an empty directory "\
1977
"and won't be deleted." % (f,)
1979
osutils.delete_any(abs_path)
1980
message = "deleted %s" % (f,)
1981
elif message is not None:
1982
# Only care if we haven't done anything yet.
1983
message = "%s does not exist." % (f,)
1985
# Print only one message (if any) per file.
1986
if message is not None:
1988
self.apply_inventory_delta(inv_delta)
1990
@needs_tree_write_lock
1991
def revert(self, filenames=None, old_tree=None, backups=True,
1992
pb=DummyProgress(), report_changes=False):
1993
from bzrlib.conflicts import resolve
1996
symbol_versioning.warn('Using [] to revert all files is deprecated'
1997
' as of bzr 0.91. Please use None (the default) instead.',
1998
DeprecationWarning, stacklevel=2)
1999
if old_tree is None:
2000
basis_tree = self.basis_tree()
2001
basis_tree.lock_read()
2002
old_tree = basis_tree
2006
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
2008
if filenames is None and len(self.get_parent_ids()) > 1:
2010
last_revision = self.last_revision()
2011
if last_revision != NULL_REVISION:
2012
if basis_tree is None:
2013
basis_tree = self.basis_tree()
2014
basis_tree.lock_read()
2015
parent_trees.append((last_revision, basis_tree))
2016
self.set_parent_trees(parent_trees)
2019
resolve(self, filenames, ignore_misses=True, recursive=True)
2021
if basis_tree is not None:
2025
def revision_tree(self, revision_id):
2026
"""See Tree.revision_tree.
2028
WorkingTree can supply revision_trees for the basis revision only
2029
because there is only one cached inventory in the bzr directory.
2031
if revision_id == self.last_revision():
2033
xml = self.read_basis_inventory()
2034
except errors.NoSuchFile:
2038
inv = xml7.serializer_v7.read_inventory_from_string(xml)
2039
# dont use the repository revision_tree api because we want
2040
# to supply the inventory.
2041
if inv.revision_id == revision_id:
2042
return revisiontree.RevisionTree(self.branch.repository,
2044
except errors.BadInventoryFormat:
2046
# raise if there was no inventory, or if we read the wrong inventory.
2047
raise errors.NoSuchRevisionInTree(self, revision_id)
2049
# XXX: This method should be deprecated in favour of taking in a proper
2050
# new Inventory object.
2051
@needs_tree_write_lock
2052
def set_inventory(self, new_inventory_list):
2053
from bzrlib.inventory import (Inventory,
2058
inv = Inventory(self.get_root_id())
2059
for path, file_id, parent, kind in new_inventory_list:
2060
name = os.path.basename(path)
2063
# fixme, there should be a factory function inv,add_??
2064
if kind == 'directory':
2065
inv.add(InventoryDirectory(file_id, name, parent))
2066
elif kind == 'file':
2067
inv.add(InventoryFile(file_id, name, parent))
2068
elif kind == 'symlink':
2069
inv.add(InventoryLink(file_id, name, parent))
2071
raise errors.BzrError("unknown kind %r" % kind)
2072
self._write_inventory(inv)
2074
@needs_tree_write_lock
2075
def set_root_id(self, file_id):
2076
"""Set the root id for this tree."""
2080
'WorkingTree.set_root_id with fileid=None')
2081
file_id = osutils.safe_file_id(file_id)
2082
self._set_root_id(file_id)
2084
def _set_root_id(self, file_id):
2085
"""Set the root id for this tree, in a format specific manner.
2087
:param file_id: The file id to assign to the root. It must not be
2088
present in the current inventory or an error will occur. It must
2089
not be None, but rather a valid file id.
2091
inv = self._inventory
2092
orig_root_id = inv.root.file_id
2093
# TODO: it might be nice to exit early if there was nothing
2094
# to do, saving us from trigger a sync on unlock.
2095
self._inventory_is_modified = True
2096
# we preserve the root inventory entry object, but
2097
# unlinkit from the byid index
2098
del inv._byid[inv.root.file_id]
2099
inv.root.file_id = file_id
2100
# and link it into the index with the new changed id.
2101
inv._byid[inv.root.file_id] = inv.root
2102
# and finally update all children to reference the new id.
2103
# XXX: this should be safe to just look at the root.children
2104
# list, not the WHOLE INVENTORY.
2107
if entry.parent_id == orig_root_id:
2108
entry.parent_id = inv.root.file_id
2111
"""See Branch.unlock.
2113
WorkingTree locking just uses the Branch locking facilities.
2114
This is current because all working trees have an embedded branch
2115
within them. IF in the future, we were to make branch data shareable
2116
between multiple working trees, i.e. via shared storage, then we
2117
would probably want to lock both the local tree, and the branch.
2119
raise NotImplementedError(self.unlock)
2121
def update(self, change_reporter=None, possible_transports=None):
2122
"""Update a working tree along its branch.
2124
This will update the branch if its bound too, which means we have
2125
multiple trees involved:
2127
- The new basis tree of the master.
2128
- The old basis tree of the branch.
2129
- The old basis tree of the working tree.
2130
- The current working tree state.
2132
Pathologically, all three may be different, and non-ancestors of each
2133
other. Conceptually we want to:
2135
- Preserve the wt.basis->wt.state changes
2136
- Transform the wt.basis to the new master basis.
2137
- Apply a merge of the old branch basis to get any 'local' changes from
2139
- Restore the wt.basis->wt.state changes.
2141
There isn't a single operation at the moment to do that, so we:
2142
- Merge current state -> basis tree of the master w.r.t. the old tree
2144
- Do a 'normal' merge of the old branch basis if it is relevant.
2146
if self.branch.get_bound_location() is not None:
2148
update_branch = True
2150
self.lock_tree_write()
2151
update_branch = False
2154
old_tip = self.branch.update(possible_transports)
2157
return self._update_tree(old_tip, change_reporter)
2161
@needs_tree_write_lock
2162
def _update_tree(self, old_tip=None, change_reporter=None):
2163
"""Update a tree to the master branch.
2165
:param old_tip: if supplied, the previous tip revision the branch,
2166
before it was changed to the master branch's tip.
2168
# here if old_tip is not None, it is the old tip of the branch before
2169
# it was updated from the master branch. This should become a pending
2170
# merge in the working tree to preserve the user existing work. we
2171
# cant set that until we update the working trees last revision to be
2172
# one from the new branch, because it will just get absorbed by the
2173
# parent de-duplication logic.
2175
# We MUST save it even if an error occurs, because otherwise the users
2176
# local work is unreferenced and will appear to have been lost.
2180
last_rev = self.get_parent_ids()[0]
2182
last_rev = _mod_revision.NULL_REVISION
2183
if last_rev != _mod_revision.ensure_null(self.branch.last_revision()):
2184
# merge tree state up to new branch tip.
2185
basis = self.basis_tree()
2188
to_tree = self.branch.basis_tree()
2189
if basis.inventory.root is None:
2190
self.set_root_id(to_tree.get_root_id())
2192
result += merge.merge_inner(
2197
change_reporter=change_reporter)
2200
# TODO - dedup parents list with things merged by pull ?
2201
# reuse the tree we've updated to to set the basis:
2202
parent_trees = [(self.branch.last_revision(), to_tree)]
2203
merges = self.get_parent_ids()[1:]
2204
# Ideally we ask the tree for the trees here, that way the working
2205
# tree can decide whether to give us teh entire tree or give us a
2206
# lazy initialised tree. dirstate for instance will have the trees
2207
# in ram already, whereas a last-revision + basis-inventory tree
2208
# will not, but also does not need them when setting parents.
2209
for parent in merges:
2210
parent_trees.append(
2211
(parent, self.branch.repository.revision_tree(parent)))
2212
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2213
parent_trees.append(
2214
(old_tip, self.branch.repository.revision_tree(old_tip)))
2215
self.set_parent_trees(parent_trees)
2216
last_rev = parent_trees[0][0]
2218
# the working tree had the same last-revision as the master
2219
# branch did. We may still have pivot local work from the local
2220
# branch into old_tip:
2221
if (old_tip is not None and not _mod_revision.is_null(old_tip)):
2222
self.add_parent_tree_id(old_tip)
2223
if (old_tip is not None and not _mod_revision.is_null(old_tip)
2224
and old_tip != last_rev):
2225
# our last revision was not the prior branch last revision
2226
# and we have converted that last revision to a pending merge.
2227
# base is somewhere between the branch tip now
2228
# and the now pending merge
2230
# Since we just modified the working tree and inventory, flush out
2231
# the current state, before we modify it again.
2232
# TODO: jam 20070214 WorkingTree3 doesn't require this, dirstate
2233
# requires it only because TreeTransform directly munges the
2234
# inventory and calls tree._write_inventory(). Ultimately we
2235
# should be able to remove this extra flush.
2237
graph = self.branch.repository.get_graph()
2238
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
2240
base_tree = self.branch.repository.revision_tree(base_rev_id)
2241
other_tree = self.branch.repository.revision_tree(old_tip)
2242
result += merge.merge_inner(
2247
change_reporter=change_reporter)
2250
def _write_hashcache_if_dirty(self):
2251
"""Write out the hashcache if it is dirty."""
2252
if self._hashcache.needs_write:
2254
self._hashcache.write()
2256
if e.errno not in (errno.EPERM, errno.EACCES):
2258
# TODO: jam 20061219 Should this be a warning? A single line
2259
# warning might be sufficient to let the user know what
2261
mutter('Could not write hashcache for %s\nError: %s',
2262
self._hashcache.cache_file_name(), e)
2264
@needs_tree_write_lock
2265
def _write_inventory(self, inv):
2266
"""Write inventory as the current inventory."""
2267
self._set_inventory(inv, dirty=True)
2270
def set_conflicts(self, arg):
2271
raise errors.UnsupportedOperation(self.set_conflicts, self)
2273
def add_conflicts(self, arg):
2274
raise errors.UnsupportedOperation(self.add_conflicts, self)
2277
def conflicts(self):
2278
conflicts = _mod_conflicts.ConflictList()
2279
for conflicted in self._iter_conflicts():
2282
if file_kind(self.abspath(conflicted)) != "file":
2284
except errors.NoSuchFile:
2287
for suffix in ('.THIS', '.OTHER'):
2289
kind = file_kind(self.abspath(conflicted+suffix))
2292
except errors.NoSuchFile:
2296
ctype = {True: 'text conflict', False: 'contents conflict'}[text]
2297
conflicts.append(_mod_conflicts.Conflict.factory(ctype,
2299
file_id=self.path2id(conflicted)))
2302
def walkdirs(self, prefix=""):
2303
"""Walk the directories of this tree.
2305
returns a generator which yields items in the form:
2306
((curren_directory_path, fileid),
2307
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
2310
This API returns a generator, which is only valid during the current
2311
tree transaction - within a single lock_read or lock_write duration.
2313
If the tree is not locked, it may cause an error to be raised,
2314
depending on the tree implementation.
2316
disk_top = self.abspath(prefix)
2317
if disk_top.endswith('/'):
2318
disk_top = disk_top[:-1]
2319
top_strip_len = len(disk_top) + 1
2320
inventory_iterator = self._walkdirs(prefix)
2321
disk_iterator = osutils.walkdirs(disk_top, prefix)
2323
current_disk = disk_iterator.next()
2324
disk_finished = False
2326
if not (e.errno == errno.ENOENT or
2327
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
2330
disk_finished = True
2332
current_inv = inventory_iterator.next()
2333
inv_finished = False
2334
except StopIteration:
2337
while not inv_finished or not disk_finished:
2339
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2340
cur_disk_dir_content) = current_disk
2342
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
2343
cur_disk_dir_content) = ((None, None), None)
2344
if not disk_finished:
2345
# strip out .bzr dirs
2346
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
2347
len(cur_disk_dir_content) > 0):
2348
# osutils.walkdirs can be made nicer -
2349
# yield the path-from-prefix rather than the pathjoined
2351
bzrdir_loc = bisect_left(cur_disk_dir_content,
2353
if (bzrdir_loc < len(cur_disk_dir_content)
2354
and cur_disk_dir_content[bzrdir_loc][0] == '.bzr'):
2355
# we dont yield the contents of, or, .bzr itself.
2356
del cur_disk_dir_content[bzrdir_loc]
2358
# everything is unknown
2361
# everything is missing
2364
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
2366
# disk is before inventory - unknown
2367
dirblock = [(relpath, basename, kind, stat, None, None) for
2368
relpath, basename, kind, stat, top_path in
2369
cur_disk_dir_content]
2370
yield (cur_disk_dir_relpath, None), dirblock
2372
current_disk = disk_iterator.next()
2373
except StopIteration:
2374
disk_finished = True
2376
# inventory is before disk - missing.
2377
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
2378
for relpath, basename, dkind, stat, fileid, kind in
2380
yield (current_inv[0][0], current_inv[0][1]), dirblock
2382
current_inv = inventory_iterator.next()
2383
except StopIteration:
2386
# versioned present directory
2387
# merge the inventory and disk data together
2389
for relpath, subiterator in itertools.groupby(sorted(
2390
current_inv[1] + cur_disk_dir_content,
2391
key=operator.itemgetter(0)), operator.itemgetter(1)):
2392
path_elements = list(subiterator)
2393
if len(path_elements) == 2:
2394
inv_row, disk_row = path_elements
2395
# versioned, present file
2396
dirblock.append((inv_row[0],
2397
inv_row[1], disk_row[2],
2398
disk_row[3], inv_row[4],
2400
elif len(path_elements[0]) == 5:
2402
dirblock.append((path_elements[0][0],
2403
path_elements[0][1], path_elements[0][2],
2404
path_elements[0][3], None, None))
2405
elif len(path_elements[0]) == 6:
2406
# versioned, absent file.
2407
dirblock.append((path_elements[0][0],
2408
path_elements[0][1], 'unknown', None,
2409
path_elements[0][4], path_elements[0][5]))
2411
raise NotImplementedError('unreachable code')
2412
yield current_inv[0], dirblock
2414
current_inv = inventory_iterator.next()
2415
except StopIteration:
2418
current_disk = disk_iterator.next()
2419
except StopIteration:
2420
disk_finished = True
2422
def _walkdirs(self, prefix=""):
2423
"""Walk the directories of this tree.
2425
:prefix: is used as the directrory to start with.
2426
returns a generator which yields items in the form:
2427
((curren_directory_path, fileid),
2428
[(file1_path, file1_name, file1_kind, None, file1_id,
2431
_directory = 'directory'
2432
# get the root in the inventory
2433
inv = self.inventory
2434
top_id = inv.path2id(prefix)
2438
pending = [(prefix, '', _directory, None, top_id, None)]
2441
currentdir = pending.pop()
2442
# 0 - relpath, 1- basename, 2- kind, 3- stat, 4-id, 5-kind
2443
top_id = currentdir[4]
2445
relroot = currentdir[0] + '/'
2448
# FIXME: stash the node in pending
2450
if entry.kind == 'directory':
2451
for name, child in entry.sorted_children():
2452
dirblock.append((relroot + name, name, child.kind, None,
2453
child.file_id, child.kind
2455
yield (currentdir[0], entry.file_id), dirblock
2456
# push the user specified dirs from dirblock
2457
for dir in reversed(dirblock):
2458
if dir[2] == _directory:
2461
@needs_tree_write_lock
2462
def auto_resolve(self):
2463
"""Automatically resolve text conflicts according to contents.
2465
Only text conflicts are auto_resolvable. Files with no conflict markers
2466
are considered 'resolved', because bzr always puts conflict markers
2467
into files that have text conflicts. The corresponding .THIS .BASE and
2468
.OTHER files are deleted, as per 'resolve'.
2469
:return: a tuple of ConflictLists: (un_resolved, resolved).
2471
un_resolved = _mod_conflicts.ConflictList()
2472
resolved = _mod_conflicts.ConflictList()
2473
conflict_re = re.compile('^(<{7}|={7}|>{7})')
2474
for conflict in self.conflicts():
2475
if (conflict.typestring != 'text conflict' or
2476
self.kind(conflict.file_id) != 'file'):
2477
un_resolved.append(conflict)
2479
my_file = open(self.id2abspath(conflict.file_id), 'rb')
2481
for line in my_file:
2482
if conflict_re.search(line):
2483
un_resolved.append(conflict)
2486
resolved.append(conflict)
2489
resolved.remove_files(self)
2490
self.set_conflicts(un_resolved)
2491
return un_resolved, resolved
2495
tree_basis = self.basis_tree()
2496
tree_basis.lock_read()
2498
repo_basis = self.branch.repository.revision_tree(
2499
self.last_revision())
2500
if len(list(repo_basis.iter_changes(tree_basis))) > 0:
2501
raise errors.BzrCheckError(
2502
"Mismatched basis inventory content.")
2507
def _validate(self):
2508
"""Validate internal structures.
2510
This is meant mostly for the test suite. To give it a chance to detect
2511
corruption after actions have occurred. The default implementation is a
2514
:return: None. An exception should be raised if there is an error.
2519
def _get_rules_searcher(self, default_searcher):
2520
"""See Tree._get_rules_searcher."""
2521
if self._rules_searcher is None:
2522
self._rules_searcher = super(WorkingTree,
2523
self)._get_rules_searcher(default_searcher)
2524
return self._rules_searcher
2526
def get_shelf_manager(self):
2527
"""Return the ShelfManager for this WorkingTree."""
2528
from bzrlib.shelf import ShelfManager
2529
return ShelfManager(self, self._transport)
2532
class WorkingTree2(WorkingTree):
2533
"""This is the Format 2 working tree.
2535
This was the first weave based working tree.
2536
- uses os locks for locking.
2537
- uses the branch last-revision.
2540
def __init__(self, *args, **kwargs):
2541
super(WorkingTree2, self).__init__(*args, **kwargs)
2542
# WorkingTree2 has more of a constraint that self._inventory must
2543
# exist. Because this is an older format, we don't mind the overhead
2544
# caused by the extra computation here.
2546
# Newer WorkingTree's should only have self._inventory set when they
2548
if self._inventory is None:
2549
self.read_working_inventory()
2551
def lock_tree_write(self):
2552
"""See WorkingTree.lock_tree_write().
2554
In Format2 WorkingTrees we have a single lock for the branch and tree
2555
so lock_tree_write() degrades to lock_write().
2557
self.branch.lock_write()
2559
return self._control_files.lock_write()
2561
self.branch.unlock()
2565
# do non-implementation specific cleanup
2568
# we share control files:
2569
if self._control_files._lock_count == 3:
2570
# _inventory_is_modified is always False during a read lock.
2571
if self._inventory_is_modified:
2573
self._write_hashcache_if_dirty()
2575
# reverse order of locking.
2577
return self._control_files.unlock()
2579
self.branch.unlock()
2582
class WorkingTree3(WorkingTree):
2583
"""This is the Format 3 working tree.
2585
This differs from the base WorkingTree by:
2586
- having its own file lock
2587
- having its own last-revision property.
2589
This is new in bzr 0.8
2593
def _last_revision(self):
2594
"""See Mutable.last_revision."""
2596
return self._transport.get_bytes('last-revision')
2597
except errors.NoSuchFile:
2598
return _mod_revision.NULL_REVISION
2600
def _change_last_revision(self, revision_id):
2601
"""See WorkingTree._change_last_revision."""
2602
if revision_id is None or revision_id == NULL_REVISION:
2604
self._transport.delete('last-revision')
2605
except errors.NoSuchFile:
2609
self._transport.put_bytes('last-revision', revision_id,
2610
mode=self._control_files._file_mode)
2613
@needs_tree_write_lock
2614
def set_conflicts(self, conflicts):
2615
self._put_rio('conflicts', conflicts.to_stanzas(),
2618
@needs_tree_write_lock
2619
def add_conflicts(self, new_conflicts):
2620
conflict_set = set(self.conflicts())
2621
conflict_set.update(set(list(new_conflicts)))
2622
self.set_conflicts(_mod_conflicts.ConflictList(sorted(conflict_set,
2623
key=_mod_conflicts.Conflict.sort_key)))
2626
def conflicts(self):
2628
confile = self._transport.get('conflicts')
2629
except errors.NoSuchFile:
2630
return _mod_conflicts.ConflictList()
2633
if confile.next() != CONFLICT_HEADER_1 + '\n':
2634
raise errors.ConflictFormatError()
2635
except StopIteration:
2636
raise errors.ConflictFormatError()
2637
return _mod_conflicts.ConflictList.from_stanzas(RioReader(confile))
2642
# do non-implementation specific cleanup
2644
if self._control_files._lock_count == 1:
2645
# _inventory_is_modified is always False during a read lock.
2646
if self._inventory_is_modified:
2648
self._write_hashcache_if_dirty()
2649
# reverse order of locking.
2651
return self._control_files.unlock()
2653
self.branch.unlock()
2656
def get_conflicted_stem(path):
2657
for suffix in _mod_conflicts.CONFLICT_SUFFIXES:
2658
if path.endswith(suffix):
2659
return path[:-len(suffix)]
2662
class WorkingTreeFormat(object):
2663
"""An encapsulation of the initialization and open routines for a format.
2665
Formats provide three things:
2666
* An initialization routine,
2670
Formats are placed in an dict by their format string for reference
2671
during workingtree opening. Its not required that these be instances, they
2672
can be classes themselves with class methods - it simply depends on
2673
whether state is needed for a given format or not.
2675
Once a format is deprecated, just deprecate the initialize and open
2676
methods on the format class. Do not deprecate the object, as the
2677
object will be created every time regardless.
2680
_default_format = None
2681
"""The default format used for new trees."""
2684
"""The known formats."""
2686
requires_rich_root = False
2688
upgrade_recommended = False
2691
def find_format(klass, a_bzrdir):
2692
"""Return the format for the working tree object in a_bzrdir."""
2694
transport = a_bzrdir.get_workingtree_transport(None)
2695
format_string = transport.get("format").read()
2696
return klass._formats[format_string]
2697
except errors.NoSuchFile:
2698
raise errors.NoWorkingTree(base=transport.base)
2700
raise errors.UnknownFormatError(format=format_string,
2701
kind="working tree")
2703
def __eq__(self, other):
2704
return self.__class__ is other.__class__
2706
def __ne__(self, other):
2707
return not (self == other)
2710
def get_default_format(klass):
2711
"""Return the current default format."""
2712
return klass._default_format
2714
def get_format_string(self):
2715
"""Return the ASCII format string that identifies this format."""
2716
raise NotImplementedError(self.get_format_string)
2718
def get_format_description(self):
2719
"""Return the short description for this format."""
2720
raise NotImplementedError(self.get_format_description)
2722
def is_supported(self):
2723
"""Is this format supported?
2725
Supported formats can be initialized and opened.
2726
Unsupported formats may not support initialization or committing or
2727
some other features depending on the reason for not being supported.
2731
def supports_content_filtering(self):
2732
"""True if this format supports content filtering."""
2735
def supports_views(self):
2736
"""True if this format supports stored views."""
2740
def register_format(klass, format):
2741
klass._formats[format.get_format_string()] = format
2744
def set_default_format(klass, format):
2745
klass._default_format = format
2748
def unregister_format(klass, format):
2749
del klass._formats[format.get_format_string()]
2752
class WorkingTreeFormat2(WorkingTreeFormat):
2753
"""The second working tree format.
2755
This format modified the hash cache from the format 1 hash cache.
2758
upgrade_recommended = True
2760
def get_format_description(self):
2761
"""See WorkingTreeFormat.get_format_description()."""
2762
return "Working tree format 2"
2764
def _stub_initialize_on_transport(self, transport, file_mode):
2765
"""Workaround: create control files for a remote working tree.
2767
This ensures that it can later be updated and dealt with locally,
2768
since BzrDirFormat6 and BzrDirFormat5 cannot represent dirs with
2769
no working tree. (See bug #43064).
2773
xml5.serializer_v5.write_inventory(inv, sio, working=True)
2775
transport.put_file('inventory', sio, file_mode)
2776
transport.put_bytes('pending-merges', '', file_mode)
2778
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2779
accelerator_tree=None, hardlink=False):
2780
"""See WorkingTreeFormat.initialize()."""
2781
if not isinstance(a_bzrdir.transport, LocalTransport):
2782
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2783
if from_branch is not None:
2784
branch = from_branch
2786
branch = a_bzrdir.open_branch()
2787
if revision_id is None:
2788
revision_id = _mod_revision.ensure_null(branch.last_revision())
2791
branch.generate_revision_history(revision_id)
2795
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2801
basis_tree = branch.repository.revision_tree(revision_id)
2802
if basis_tree.inventory.root is not None:
2803
wt.set_root_id(basis_tree.get_root_id())
2804
# set the parent list and cache the basis tree.
2805
if _mod_revision.is_null(revision_id):
2808
parent_trees = [(revision_id, basis_tree)]
2809
wt.set_parent_trees(parent_trees)
2810
transform.build_tree(basis_tree, wt)
2814
super(WorkingTreeFormat2, self).__init__()
2815
self._matchingbzrdir = bzrdir.BzrDirFormat6()
2817
def open(self, a_bzrdir, _found=False):
2818
"""Return the WorkingTree object for a_bzrdir
2820
_found is a private parameter, do not use it. It is used to indicate
2821
if format probing has already been done.
2824
# we are being called directly and must probe.
2825
raise NotImplementedError
2826
if not isinstance(a_bzrdir.transport, LocalTransport):
2827
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2828
wt = WorkingTree2(a_bzrdir.root_transport.local_abspath('.'),
2834
class WorkingTreeFormat3(WorkingTreeFormat):
2835
"""The second working tree format updated to record a format marker.
2838
- exists within a metadir controlling .bzr
2839
- includes an explicit version marker for the workingtree control
2840
files, separate from the BzrDir format
2841
- modifies the hash cache format
2843
- uses a LockDir to guard access for writes.
2846
upgrade_recommended = True
2848
def get_format_string(self):
2849
"""See WorkingTreeFormat.get_format_string()."""
2850
return "Bazaar-NG Working Tree format 3"
2852
def get_format_description(self):
2853
"""See WorkingTreeFormat.get_format_description()."""
2854
return "Working tree format 3"
2856
_lock_file_name = 'lock'
2857
_lock_class = LockDir
2859
_tree_class = WorkingTree3
2861
def __get_matchingbzrdir(self):
2862
return bzrdir.BzrDirMetaFormat1()
2864
_matchingbzrdir = property(__get_matchingbzrdir)
2866
def _open_control_files(self, a_bzrdir):
2867
transport = a_bzrdir.get_workingtree_transport(None)
2868
return LockableFiles(transport, self._lock_file_name,
2871
def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
2872
accelerator_tree=None, hardlink=False):
2873
"""See WorkingTreeFormat.initialize().
2875
:param revision_id: if supplied, create a working tree at a different
2876
revision than the branch is at.
2877
:param accelerator_tree: A tree which can be used for retrieving file
2878
contents more quickly than the revision tree, i.e. a workingtree.
2879
The revision tree will be used for cases where accelerator_tree's
2880
content is different.
2881
:param hardlink: If true, hard-link files from accelerator_tree,
2884
if not isinstance(a_bzrdir.transport, LocalTransport):
2885
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2886
transport = a_bzrdir.get_workingtree_transport(self)
2887
control_files = self._open_control_files(a_bzrdir)
2888
control_files.create_lock()
2889
control_files.lock_write()
2890
transport.put_bytes('format', self.get_format_string(),
2891
mode=control_files._file_mode)
2892
if from_branch is not None:
2893
branch = from_branch
2895
branch = a_bzrdir.open_branch()
2896
if revision_id is None:
2897
revision_id = _mod_revision.ensure_null(branch.last_revision())
2898
# WorkingTree3 can handle an inventory which has a unique root id.
2899
# as of bzr 0.12. However, bzr 0.11 and earlier fail to handle
2900
# those trees. And because there isn't a format bump inbetween, we
2901
# are maintaining compatibility with older clients.
2902
# inv = Inventory(root_id=gen_root_id())
2903
inv = self._initial_inventory()
2904
wt = self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
2910
_control_files=control_files)
2911
wt.lock_tree_write()
2913
basis_tree = branch.repository.revision_tree(revision_id)
2914
# only set an explicit root id if there is one to set.
2915
if basis_tree.inventory.root is not None:
2916
wt.set_root_id(basis_tree.get_root_id())
2917
if revision_id == NULL_REVISION:
2918
wt.set_parent_trees([])
2920
wt.set_parent_trees([(revision_id, basis_tree)])
2921
transform.build_tree(basis_tree, wt)
2923
# Unlock in this order so that the unlock-triggers-flush in
2924
# WorkingTree is given a chance to fire.
2925
control_files.unlock()
2929
def _initial_inventory(self):
2933
super(WorkingTreeFormat3, self).__init__()
2935
def open(self, a_bzrdir, _found=False):
2936
"""Return the WorkingTree object for a_bzrdir
2938
_found is a private parameter, do not use it. It is used to indicate
2939
if format probing has already been done.
2942
# we are being called directly and must probe.
2943
raise NotImplementedError
2944
if not isinstance(a_bzrdir.transport, LocalTransport):
2945
raise errors.NotLocalUrl(a_bzrdir.transport.base)
2946
wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
2949
def _open(self, a_bzrdir, control_files):
2950
"""Open the tree itself.
2952
:param a_bzrdir: the dir for the tree.
2953
:param control_files: the control files for the tree.
2955
return self._tree_class(a_bzrdir.root_transport.local_abspath('.'),
2959
_control_files=control_files)
2962
return self.get_format_string()
2965
__default_format = WorkingTreeFormat4()
2966
WorkingTreeFormat.register_format(__default_format)
2967
WorkingTreeFormat.register_format(WorkingTreeFormat5())
2968
WorkingTreeFormat.register_format(WorkingTreeFormat3())
2969
WorkingTreeFormat.set_default_format(__default_format)
2970
# formats which have no format string are not discoverable
2971
# and not independently creatable, so are not registered.
2972
_legacy_formats = [WorkingTreeFormat2(),