1
# Copyright (C) 2005-2011 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.
23
At the moment every WorkingTree has its own branch. Remote
24
WorkingTrees aren't supported.
26
To get a WorkingTree, call controldir.open_workingtree() or
27
WorkingTree.open(dir).
30
from __future__ import absolute_import
39
from .lazy_import import lazy_import
40
lazy_import(globals(), """
41
from bisect import bisect_left
48
conflicts as _mod_conflicts,
51
filters as _mod_filters,
54
revision as _mod_revision,
66
from .decorators import needs_read_lock, needs_write_lock
67
from .i18n import gettext
68
from . import mutabletree
69
from .mutabletree import needs_tree_write_lock
73
from .trace import mutter, note
76
ERROR_PATH_NOT_FOUND = 3 # WindowsError errno code, equivalent to ENOENT
79
class SettingFileIdUnsupported(errors.BzrError):
81
_fmt = "This format does not support setting file ids."""
84
class TreeEntry(object):
85
"""An entry that implements the minimum interface used by commands.
87
This needs further inspection, it may be better to have
88
InventoryEntries without ids - though that seems wrong. For now,
89
this is a parallel hierarchy to InventoryEntry, and needs to become
90
one of several things: decorates to that hierarchy, children of, or
92
Another note is that these objects are currently only used when there is
93
no InventoryEntry available - i.e. for unversioned objects.
94
Perhaps they should be UnversionedEntry et al. ? - RBC 20051003
97
def __eq__(self, other):
98
# yes, this us ugly, TODO: best practice __eq__ style.
99
return (isinstance(other, TreeEntry)
100
and other.__class__ == self.__class__)
102
def kind_character(self):
106
class TreeDirectory(TreeEntry):
107
"""See TreeEntry. This is a directory in a working tree."""
109
def __eq__(self, other):
110
return (isinstance(other, TreeDirectory)
111
and other.__class__ == self.__class__)
113
def kind_character(self):
117
class TreeFile(TreeEntry):
118
"""See TreeEntry. This is a regular file in a working tree."""
120
def __eq__(self, other):
121
return (isinstance(other, TreeFile)
122
and other.__class__ == self.__class__)
124
def kind_character(self):
128
class TreeLink(TreeEntry):
129
"""See TreeEntry. This is a symlink in a working tree."""
131
def __eq__(self, other):
132
return (isinstance(other, TreeLink)
133
and other.__class__ == self.__class__)
135
def kind_character(self):
139
class WorkingTree(mutabletree.MutableTree,
140
controldir.ControlComponent):
141
"""Working copy tree.
143
:ivar basedir: The root of the tree on disk. This is a unicode path object
144
(as opposed to a URL).
147
# override this to set the strategy for storing views
148
def _make_views(self):
149
return views.DisabledViews(self)
151
def __init__(self, basedir='.',
157
"""Construct a WorkingTree instance. This is not a public API.
159
:param branch: A branch to override probing for the branch.
161
self._format = _format
162
self.controldir = _controldir
164
raise errors.BzrError("Please use controldir.open_workingtree or "
165
"WorkingTree.open() to obtain a WorkingTree.")
166
basedir = osutils.safe_unicode(basedir)
167
mutter("opening working tree %r", basedir)
168
if branch is not None:
169
self._branch = branch
171
self._branch = self.controldir.open_branch()
172
self.basedir = osutils.realpath(basedir)
173
self._transport = _transport
174
self._rules_searcher = None
175
self.views = self._make_views()
178
def user_transport(self):
179
return self.controldir.user_transport
182
def control_transport(self):
183
return self._transport
185
def is_control_filename(self, filename):
186
"""True if filename is the name of a control file in this tree.
188
:param filename: A filename within the tree. This is a relative path
189
from the root of this tree.
191
This is true IF and ONLY IF the filename is part of the meta data
192
that bzr controls in this tree. I.E. a random .bzr directory placed
193
on disk will not be a control file for this tree.
195
return self.controldir.is_control_filename(filename)
198
fget=lambda self: self._branch,
199
doc="""The branch this WorkingTree is connected to.
201
This cannot be set - it is reflective of the actual disk structure
202
the working tree has been constructed from.
205
def has_versioned_directories(self):
206
"""See `Tree.has_versioned_directories`."""
207
return self._format.supports_versioned_directories
209
def _supports_executable(self):
210
if sys.platform == 'win32':
212
# FIXME: Ideally this should check the file system
215
def break_lock(self):
216
"""Break a lock if one is present from another instance.
218
Uses the ui factory to ask for confirmation if the lock may be from
221
This will probe the repository for its lock as well.
223
raise NotImplementedError(self.break_lock)
225
def requires_rich_root(self):
226
return self._format.requires_rich_root
228
def supports_tree_reference(self):
231
def supports_content_filtering(self):
232
return self._format.supports_content_filtering()
234
def supports_views(self):
235
return self.views.supports_views()
237
def supports_setting_file_ids(self):
238
return self._format.supports_setting_file_ids
240
def get_config_stack(self):
241
"""Retrieve the config stack for this tree.
243
:return: A ``breezy.config.Stack``
245
# For the moment, just provide the branch config stack.
246
return self.branch.get_config_stack()
249
def open(path=None, _unsupported=False):
250
"""Open an existing working tree at path.
254
path = osutils.getcwd()
255
control = controldir.ControlDir.open(path, _unsupported=_unsupported)
256
return control.open_workingtree(unsupported=_unsupported)
259
def open_containing(path=None):
260
"""Open an existing working tree which has its root about path.
262
This probes for a working tree at path and searches upwards from there.
264
Basically we keep looking up until we find the control directory or
265
run into /. If there isn't one, raises NotBranchError.
266
TODO: give this a new exception.
267
If there is one, it is returned, along with the unused portion of path.
269
:return: The WorkingTree that contains 'path', and the rest of path
272
path = osutils.getcwd()
273
control, relpath = controldir.ControlDir.open_containing(path)
274
return control.open_workingtree(), relpath
277
def open_containing_paths(file_list, default_directory=None,
278
canonicalize=True, apply_view=True):
279
"""Open the WorkingTree that contains a set of paths.
281
Fail if the paths given are not all in a single tree.
283
This is used for the many command-line interfaces that take a list of
284
any number of files and that require they all be in the same tree.
286
if default_directory is None:
287
default_directory = u'.'
288
# recommended replacement for builtins.internal_tree_files
289
if file_list is None or len(file_list) == 0:
290
tree = WorkingTree.open_containing(default_directory)[0]
291
# XXX: doesn't really belong here, and seems to have the strange
292
# side effect of making it return a bunch of files, not the whole
293
# tree -- mbp 20100716
294
if tree.supports_views() and apply_view:
295
view_files = tree.views.lookup_view()
297
file_list = view_files
298
view_str = views.view_display_str(view_files)
299
note(gettext("Ignoring files outside view. View is %s") % view_str)
300
return tree, file_list
301
if default_directory == u'.':
304
seed = default_directory
305
file_list = [osutils.pathjoin(default_directory, f)
307
tree = WorkingTree.open_containing(seed)[0]
308
return tree, tree.safe_relpath_files(file_list, canonicalize,
309
apply_view=apply_view)
311
def safe_relpath_files(self, file_list, canonicalize=True, apply_view=True):
312
"""Convert file_list into a list of relpaths in tree.
314
:param self: A tree to operate on.
315
:param file_list: A list of user provided paths or None.
316
:param apply_view: if True and a view is set, apply it or check that
317
specified files are within it
318
:return: A list of relative paths.
319
:raises errors.PathNotChild: When a provided path is in a different self
322
if file_list is None:
324
if self.supports_views() and apply_view:
325
view_files = self.views.lookup_view()
329
# self.relpath exists as a "thunk" to osutils, but canonical_relpath
330
# doesn't - fix that up here before we enter the loop.
332
fixer = lambda p: osutils.canonical_relpath(self.basedir, p)
335
for filename in file_list:
336
relpath = fixer(osutils.dereference_path(filename))
337
if view_files and not osutils.is_inside_any(view_files, relpath):
338
raise views.FileOutsideView(filename, view_files)
339
new_list.append(relpath)
343
def open_downlevel(path=None):
344
"""Open an unsupported working tree.
346
Only intended for advanced situations like upgrading part of a controldir.
348
return WorkingTree.open(path, _unsupported=True)
351
def find_trees(location):
352
def list_current(transport):
353
return [d for d in transport.list_dir('')
354
if not controldir.is_control_filename(d)]
355
def evaluate(controldir):
357
tree = controldir.open_workingtree()
358
except errors.NoWorkingTree:
362
t = transport.get_transport(location)
363
iterator = controldir.ControlDir.find_controldirs(t, evaluate=evaluate,
364
list_current=list_current)
365
return [tr for tr in iterator if tr is not None]
368
return "<%s of %s>" % (self.__class__.__name__,
369
getattr(self, 'basedir', None))
371
def abspath(self, filename):
372
return osutils.pathjoin(self.basedir, filename)
374
def basis_tree(self):
375
"""Return RevisionTree for the current last revision.
377
If the left most parent is a ghost then the returned tree will be an
378
empty tree - one obtained by calling
379
repository.revision_tree(NULL_REVISION).
382
revision_id = self.get_parent_ids()[0]
384
# no parents, return an empty revision tree.
385
# in the future this should return the tree for
386
# 'empty:' - the implicit root empty tree.
387
return self.branch.repository.revision_tree(
388
_mod_revision.NULL_REVISION)
390
return self.revision_tree(revision_id)
391
except errors.NoSuchRevision:
393
# No cached copy available, retrieve from the repository.
394
# FIXME? RBC 20060403 should we cache the inventory locally
397
return self.branch.repository.revision_tree(revision_id)
398
except (errors.RevisionNotPresent, errors.NoSuchRevision):
399
# the basis tree *may* be a ghost or a low level error may have
400
# occurred. If the revision is present, its a problem, if its not
402
if self.branch.repository.has_revision(revision_id):
404
# the basis tree is a ghost so return an empty tree.
405
return self.branch.repository.revision_tree(
406
_mod_revision.NULL_REVISION)
408
def relpath(self, path):
409
"""Return the local path portion from a given path.
411
The path may be absolute or relative. If its a relative path it is
412
interpreted relative to the python current working directory.
414
return osutils.relpath(self.basedir, path)
416
def has_filename(self, filename):
417
return osutils.lexists(self.abspath(filename))
419
def get_file(self, file_id, path=None, filtered=True):
420
return self.get_file_with_stat(file_id, path, filtered=filtered)[0]
422
def get_file_with_stat(self, file_id, path=None, filtered=True,
423
_fstat=osutils.fstat):
424
"""See Tree.get_file_with_stat."""
426
path = self.id2path(file_id)
427
file_obj = self.get_file_byname(path, filtered=False)
428
stat_value = _fstat(file_obj.fileno())
429
if filtered and self.supports_content_filtering():
430
filters = self._content_filter_stack(path)
431
file_obj = _mod_filters.filtered_input_file(file_obj, filters)
432
return (file_obj, stat_value)
434
def get_file_text(self, file_id, path=None, filtered=True):
435
my_file = self.get_file(file_id, path=path, filtered=filtered)
437
return my_file.read()
441
def get_file_byname(self, filename, filtered=True):
442
path = self.abspath(filename)
444
if filtered and self.supports_content_filtering():
445
filters = self._content_filter_stack(filename)
446
return _mod_filters.filtered_input_file(f, filters)
450
def get_file_lines(self, file_id, path=None, filtered=True):
451
"""See Tree.get_file_lines()"""
452
file = self.get_file(file_id, path, filtered=filtered)
454
return file.readlines()
458
def get_parent_ids(self):
459
"""See Tree.get_parent_ids.
461
This implementation reads the pending merges list and last_revision
462
value and uses that to decide what the parents list should be.
464
last_rev = _mod_revision.ensure_null(self._last_revision())
465
if _mod_revision.NULL_REVISION == last_rev:
470
merges_bytes = self._transport.get_bytes('pending-merges')
471
except errors.NoSuchFile:
474
for l in osutils.split_lines(merges_bytes):
475
revision_id = l.rstrip('\n')
476
parents.append(revision_id)
479
def get_root_id(self):
480
"""Return the id of this trees root"""
481
raise NotImplementedError(self.get_root_id)
484
def clone(self, to_controldir, revision_id=None):
485
"""Duplicate this working tree into to_bzr, including all state.
487
Specifically modified files are kept as modified, but
488
ignored and unknown files are discarded.
490
If you want to make a new line of development, see ControlDir.sprout()
493
If not None, the cloned tree will have its last revision set to
494
revision, and difference between the source trees last revision
495
and this one merged in.
497
# assumes the target bzr dir format is compatible.
498
result = to_controldir.create_workingtree()
499
self.copy_content_into(result, revision_id)
503
def copy_content_into(self, tree, revision_id=None):
504
"""Copy the current content and user files of this tree into tree."""
505
tree.set_root_id(self.get_root_id())
506
if revision_id is None:
507
merge.transform_tree(tree, self)
509
# TODO now merge from tree.last_revision to revision (to preserve
510
# user local changes)
512
other_tree = self.revision_tree(revision_id)
513
except errors.NoSuchRevision:
514
other_tree = self.branch.repository.revision_tree(revision_id)
516
merge.transform_tree(tree, other_tree)
517
if revision_id == _mod_revision.NULL_REVISION:
520
new_parents = [revision_id]
521
tree.set_parent_ids(new_parents)
523
def id2abspath(self, file_id):
524
return self.abspath(self.id2path(file_id))
526
def get_file_size(self, file_id):
527
"""See Tree.get_file_size"""
528
# XXX: this returns the on-disk size; it should probably return the
531
return os.path.getsize(self.id2abspath(file_id))
533
if e.errno != errno.ENOENT:
538
@needs_tree_write_lock
539
def _gather_kinds(self, files, kinds):
540
"""See MutableTree._gather_kinds."""
541
for pos, f in enumerate(files):
542
if kinds[pos] is None:
543
fullpath = osutils.normpath(self.abspath(f))
545
kinds[pos] = osutils.file_kind(fullpath)
547
if e.errno == errno.ENOENT:
548
raise errors.NoSuchFile(fullpath)
551
def add_parent_tree_id(self, revision_id, allow_leftmost_as_ghost=False):
552
"""Add revision_id as a parent.
554
This is equivalent to retrieving the current list of parent ids
555
and setting the list to its value plus revision_id.
557
:param revision_id: The revision id to add to the parent list. It may
558
be a ghost revision as long as its not the first parent to be
559
added, or the allow_leftmost_as_ghost parameter is set True.
560
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
562
parents = self.get_parent_ids() + [revision_id]
563
self.set_parent_ids(parents, allow_leftmost_as_ghost=len(parents) > 1
564
or allow_leftmost_as_ghost)
566
@needs_tree_write_lock
567
def add_parent_tree(self, parent_tuple, allow_leftmost_as_ghost=False):
568
"""Add revision_id, tree tuple as a parent.
570
This is equivalent to retrieving the current list of parent trees
571
and setting the list to its value plus parent_tuple. See also
572
add_parent_tree_id - if you only have a parent id available it will be
573
simpler to use that api. If you have the parent already available, using
574
this api is preferred.
576
:param parent_tuple: The (revision id, tree) to add to the parent list.
577
If the revision_id is a ghost, pass None for the tree.
578
:param allow_leftmost_as_ghost: Allow the first parent to be a ghost.
580
parent_ids = self.get_parent_ids() + [parent_tuple[0]]
581
if len(parent_ids) > 1:
582
# the leftmost may have already been a ghost, preserve that if it
584
allow_leftmost_as_ghost = True
585
self.set_parent_ids(parent_ids,
586
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
588
@needs_tree_write_lock
589
def add_pending_merge(self, *revision_ids):
590
# TODO: Perhaps should check at this point that the
591
# history of the revision is actually present?
592
parents = self.get_parent_ids()
594
for rev_id in revision_ids:
595
if rev_id in parents:
597
parents.append(rev_id)
600
self.set_parent_ids(parents, allow_leftmost_as_ghost=True)
602
def path_content_summary(self, path, _lstat=os.lstat,
603
_mapper=osutils.file_kind_from_stat_mode):
604
"""See Tree.path_content_summary."""
605
abspath = self.abspath(path)
607
stat_result = _lstat(abspath)
609
if getattr(e, 'errno', None) == errno.ENOENT:
611
return ('missing', None, None, None)
612
# propagate other errors
614
kind = _mapper(stat_result.st_mode)
616
return self._file_content_summary(path, stat_result)
617
elif kind == 'directory':
618
# perhaps it looks like a plain directory, but it's really a
620
if self._directory_is_tree_reference(path):
621
kind = 'tree-reference'
622
return kind, None, None, None
623
elif kind == 'symlink':
624
target = osutils.readlink(abspath)
625
return ('symlink', None, None, target)
627
return (kind, None, None, None)
629
def _file_content_summary(self, path, stat_result):
630
size = stat_result.st_size
631
executable = self._is_executable_from_path_and_stat(path, stat_result)
632
# try for a stat cache lookup
633
return ('file', size, executable, self._sha_from_stat(
636
def _check_parents_for_ghosts(self, revision_ids, allow_leftmost_as_ghost):
637
"""Common ghost checking functionality from set_parent_*.
639
This checks that the left hand-parent exists if there are any
642
if len(revision_ids) > 0:
643
leftmost_id = revision_ids[0]
644
if (not allow_leftmost_as_ghost and not
645
self.branch.repository.has_revision(leftmost_id)):
646
raise errors.GhostRevisionUnusableHere(leftmost_id)
648
def _set_merges_from_parent_ids(self, parent_ids):
649
merges = parent_ids[1:]
650
self._transport.put_bytes('pending-merges', '\n'.join(merges),
651
mode=self.controldir._get_file_mode())
653
def _filter_parent_ids_by_ancestry(self, revision_ids):
654
"""Check that all merged revisions are proper 'heads'.
656
This will always return the first revision_id, and any merged revisions
659
if len(revision_ids) == 0:
661
graph = self.branch.repository.get_graph()
662
heads = graph.heads(revision_ids)
663
new_revision_ids = revision_ids[:1]
664
for revision_id in revision_ids[1:]:
665
if revision_id in heads and revision_id not in new_revision_ids:
666
new_revision_ids.append(revision_id)
667
if new_revision_ids != revision_ids:
668
mutter('requested to set revision_ids = %s,'
669
' but filtered to %s', revision_ids, new_revision_ids)
670
return new_revision_ids
672
@needs_tree_write_lock
673
def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
674
"""Set the parent ids to revision_ids.
676
See also set_parent_trees. This api will try to retrieve the tree data
677
for each element of revision_ids from the trees repository. If you have
678
tree data already available, it is more efficient to use
679
set_parent_trees rather than set_parent_ids. set_parent_ids is however
680
an easier API to use.
682
:param revision_ids: The revision_ids to set as the parent ids of this
683
working tree. Any of these may be ghosts.
685
self._check_parents_for_ghosts(revision_ids,
686
allow_leftmost_as_ghost=allow_leftmost_as_ghost)
687
for revision_id in revision_ids:
688
_mod_revision.check_not_reserved_id(revision_id)
690
revision_ids = self._filter_parent_ids_by_ancestry(revision_ids)
692
if len(revision_ids) > 0:
693
self.set_last_revision(revision_ids[0])
695
self.set_last_revision(_mod_revision.NULL_REVISION)
697
self._set_merges_from_parent_ids(revision_ids)
699
@needs_tree_write_lock
700
def set_pending_merges(self, rev_list):
701
parents = self.get_parent_ids()
702
leftmost = parents[:1]
703
new_parents = leftmost + rev_list
704
self.set_parent_ids(new_parents)
706
@needs_tree_write_lock
707
def set_merge_modified(self, modified_hashes):
708
"""Set the merge modified hashes."""
709
raise NotImplementedError(self.set_merge_modified)
711
def _sha_from_stat(self, path, stat_result):
712
"""Get a sha digest from the tree's stat cache.
714
The default implementation assumes no stat cache is present.
716
:param path: The path.
717
:param stat_result: The stat result being looked up.
721
@needs_write_lock # because merge pulls data into the branch.
722
def merge_from_branch(self, branch, to_revision=None, from_revision=None,
723
merge_type=None, force=False):
724
"""Merge from a branch into this working tree.
726
:param branch: The branch to merge from.
727
:param to_revision: If non-None, the merge will merge to to_revision,
728
but not beyond it. to_revision does not need to be in the history
729
of the branch when it is supplied. If None, to_revision defaults to
730
branch.last_revision().
732
from .merge import Merger, Merge3Merger
733
merger = Merger(self.branch, this_tree=self)
734
# check that there are no local alterations
735
if not force and self.has_changes():
736
raise errors.UncommittedChanges(self)
737
if to_revision is None:
738
to_revision = _mod_revision.ensure_null(branch.last_revision())
739
merger.other_rev_id = to_revision
740
if _mod_revision.is_null(merger.other_rev_id):
741
raise errors.NoCommits(branch)
742
self.branch.fetch(branch, last_revision=merger.other_rev_id)
743
merger.other_basis = merger.other_rev_id
744
merger.other_tree = self.branch.repository.revision_tree(
746
merger.other_branch = branch
747
if from_revision is None:
750
merger.set_base_revision(from_revision, branch)
751
if merger.base_rev_id == merger.other_rev_id:
752
raise errors.PointlessMerge
753
merger.backup_files = False
754
if merge_type is None:
755
merger.merge_type = Merge3Merger
757
merger.merge_type = merge_type
758
merger.set_interesting_files(None)
759
merger.show_base = False
760
merger.reprocess = False
761
conflicts = merger.do_merge()
765
def merge_modified(self):
766
"""Return a dictionary of files modified by a merge.
768
The list is initialized by WorkingTree.set_merge_modified, which is
769
typically called after we make some automatic updates to the tree
772
This returns a map of file_id->sha1, containing only files which are
773
still in the working inventory and have that text hash.
775
raise NotImplementedError(self.merge_modified)
778
def mkdir(self, path, file_id=None):
779
"""See MutableTree.mkdir()."""
781
file_id = generate_ids.gen_file_id(os.path.basename(path))
782
elif not self.supports_setting_file_ids():
783
raise SettingFileIdUnsupported()
784
os.mkdir(self.abspath(path))
785
self.add(path, file_id, 'directory')
788
def get_symlink_target(self, file_id, path=None):
790
abspath = self.abspath(path)
792
abspath = self.id2abspath(file_id)
793
target = osutils.readlink(abspath)
796
def subsume(self, other_tree):
797
raise NotImplementedError(self.subsume)
799
def _setup_directory_is_tree_reference(self):
800
if self._branch.repository._format.supports_tree_reference:
801
self._directory_is_tree_reference = \
802
self._directory_may_be_tree_reference
804
self._directory_is_tree_reference = \
805
self._directory_is_never_tree_reference
807
def _directory_is_never_tree_reference(self, relpath):
810
def _directory_may_be_tree_reference(self, relpath):
811
# as a special case, if a directory contains control files then
812
# it's a tree reference, except that the root of the tree is not
813
return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
814
# TODO: We could ask all the control formats whether they
815
# recognize this directory, but at the moment there's no cheap api
816
# to do that. Since we probably can only nest bzr checkouts and
817
# they always use this name it's ok for now. -- mbp 20060306
819
# FIXME: There is an unhandled case here of a subdirectory
820
# containing .bzr but not a branch; that will probably blow up
821
# when you try to commit it. It might happen if there is a
822
# checkout in a subdirectory. This can be avoided by not adding
825
def extract(self, file_id, format=None):
826
"""Extract a subtree from this tree.
828
A new branch will be created, relative to the path for this tree.
830
raise NotImplementedError(self.extract)
833
"""Write the in memory meta data to disk."""
834
raise NotImplementedError(self.flush)
836
def _kind(self, relpath):
837
return osutils.file_kind(self.abspath(relpath))
839
def list_files(self, include_root=False, from_dir=None, recursive=True):
840
"""List all files as (path, class, kind, id, entry).
842
Lists, but does not descend into unversioned directories.
843
This does not include files that have been deleted in this
844
tree. Skips the control directory.
846
:param include_root: if True, return an entry for the root
847
:param from_dir: start from this directory or None for the root
848
:param recursive: whether to recurse into subdirectories or not
850
raise NotImplementedError(self.list_files)
852
def move(self, from_paths, to_dir=None, after=False):
855
to_dir must be known to the working tree.
857
If to_dir exists and is a directory, the files are moved into
858
it, keeping their old names.
860
Note that to_dir is only the last component of the new name;
861
this doesn't change the directory.
863
For each entry in from_paths the move mode will be determined
866
The first mode moves the file in the filesystem and updates the
867
working tree metadata. The second mode only updates the working tree
868
metadata without touching the file on the filesystem.
870
move uses the second mode if 'after == True' and the target is not
871
versioned but present in the working tree.
873
move uses the second mode if 'after == False' and the source is
874
versioned but no longer in the working tree, and the target is not
875
versioned but present in the working tree.
877
move uses the first mode if 'after == False' and the source is
878
versioned and present in the working tree, and the target is not
879
versioned and not present in the working tree.
881
Everything else results in an error.
883
This returns a list of (from_path, to_path) pairs for each
886
raise NotImplementedError(self.move)
888
@needs_tree_write_lock
889
def rename_one(self, from_rel, to_rel, after=False):
892
This can change the directory or the filename or both.
894
rename_one has several 'modes' to work. First, it can rename a physical
895
file and change the file_id. That is the normal mode. Second, it can
896
only change the file_id without touching any physical file.
898
rename_one uses the second mode if 'after == True' and 'to_rel' is
899
either not versioned or newly added, and present in the working tree.
901
rename_one uses the second mode if 'after == False' and 'from_rel' is
902
versioned but no longer in the working tree, and 'to_rel' is not
903
versioned but present in the working tree.
905
rename_one uses the first mode if 'after == False' and 'from_rel' is
906
versioned and present in the working tree, and 'to_rel' is not
907
versioned and not present in the working tree.
909
Everything else results in an error.
911
raise NotImplementedError(self.rename_one)
915
"""Return all unknown files.
917
These are files in the working directory that are not versioned or
918
control files or ignored.
920
# force the extras method to be fully executed before returning, to
921
# prevent race conditions with the lock
923
[subp for subp in self.extras() if not self.is_ignored(subp)])
925
def unversion(self, file_ids):
926
"""Remove the file ids in file_ids from the current versioned set.
928
When a file_id is unversioned, all of its children are automatically
931
:param file_ids: The file ids to stop versioning.
932
:raises: NoSuchId if any fileid is not currently versioned.
934
raise NotImplementedError(self.unversion)
937
def pull(self, source, overwrite=False, stop_revision=None,
938
change_reporter=None, possible_transports=None, local=False,
942
old_revision_info = self.branch.last_revision_info()
943
basis_tree = self.basis_tree()
944
count = self.branch.pull(source, overwrite, stop_revision,
945
possible_transports=possible_transports,
947
new_revision_info = self.branch.last_revision_info()
948
if new_revision_info != old_revision_info:
949
repository = self.branch.repository
950
if repository._format.fast_deltas:
951
parent_ids = self.get_parent_ids()
953
basis_id = parent_ids[0]
954
basis_tree = repository.revision_tree(basis_id)
955
basis_tree.lock_read()
957
new_basis_tree = self.branch.basis_tree()
963
change_reporter=change_reporter,
965
basis_root_id = basis_tree.get_root_id()
966
new_root_id = new_basis_tree.get_root_id()
967
if new_root_id is not None and basis_root_id != new_root_id:
968
self.set_root_id(new_root_id)
971
# TODO - dedup parents list with things merged by pull ?
972
# reuse the revisiontree we merged against to set the new
975
if self.branch.last_revision() != _mod_revision.NULL_REVISION:
977
(self.branch.last_revision(), new_basis_tree))
978
# we have to pull the merge trees out again, because
979
# merge_inner has set the ids. - this corner is not yet
980
# layered well enough to prevent double handling.
981
# XXX TODO: Fix the double handling: telling the tree about
982
# the already known parent data is wasteful.
983
merges = self.get_parent_ids()[1:]
984
parent_trees.extend([
985
(parent, repository.revision_tree(parent)) for
987
self.set_parent_trees(parent_trees)
993
def put_file_bytes_non_atomic(self, file_id, bytes):
994
"""See MutableTree.put_file_bytes_non_atomic."""
995
stream = file(self.id2abspath(file_id), 'wb')
1002
"""Yield all unversioned files in this WorkingTree.
1004
If there are any unversioned directories then only the directory is
1005
returned, not all its children. But if there are unversioned files
1006
under a versioned subdirectory, they are returned.
1008
Currently returned depth-first, sorted by name within directories.
1009
This is the same order used by 'osutils.walkdirs'.
1011
raise NotImplementedError(self.extras)
1013
def ignored_files(self):
1014
"""Yield list of PATH, IGNORE_PATTERN"""
1015
for subp in self.extras():
1016
pat = self.is_ignored(subp)
1020
def is_ignored(self, filename):
1021
r"""Check whether the filename matches an ignore pattern.
1023
raise NotImplementedError(self.is_ignored)
1025
def kind(self, file_id):
1026
return osutils.file_kind(self.id2abspath(file_id))
1028
def stored_kind(self, file_id):
1029
"""See Tree.stored_kind"""
1030
raise NotImplementedError(self.stored_kind)
1032
def _comparison_data(self, entry, path):
1033
abspath = self.abspath(path)
1035
stat_value = os.lstat(abspath)
1036
except OSError as e:
1037
if getattr(e, 'errno', None) == errno.ENOENT:
1044
mode = stat_value.st_mode
1045
kind = osutils.file_kind_from_stat_mode(mode)
1046
if not self._supports_executable():
1047
executable = entry is not None and entry.executable
1049
executable = bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
1050
return kind, executable, stat_value
1052
def _file_size(self, entry, stat_value):
1053
return stat_value.st_size
1055
def last_revision(self):
1056
"""Return the last revision of the branch for this tree.
1058
This format tree does not support a separate marker for last-revision
1059
compared to the branch.
1061
See MutableTree.last_revision
1063
return self._last_revision()
1066
def _last_revision(self):
1067
"""helper for get_parent_ids."""
1068
return _mod_revision.ensure_null(self.branch.last_revision())
1070
def is_locked(self):
1071
"""Check if this tree is locked."""
1072
raise NotImplementedError(self.is_locked)
1074
def lock_read(self):
1075
"""Lock the tree for reading.
1077
This also locks the branch, and can be unlocked via self.unlock().
1079
:return: A breezy.lock.LogicalLockResult.
1081
raise NotImplementedError(self.lock_read)
1083
def lock_tree_write(self):
1084
"""See MutableTree.lock_tree_write, and WorkingTree.unlock.
1086
:return: A breezy.lock.LogicalLockResult.
1088
raise NotImplementedError(self.lock_tree_write)
1090
def lock_write(self):
1091
"""See MutableTree.lock_write, and WorkingTree.unlock.
1093
:return: A breezy.lock.LogicalLockResult.
1095
raise NotImplementedError(self.lock_write)
1097
def get_physical_lock_status(self):
1098
raise NotImplementedError(self.get_physical_lock_status)
1100
def set_last_revision(self, new_revision):
1101
"""Change the last revision in the working tree."""
1102
raise NotImplementedError(self.set_last_revision)
1104
def _change_last_revision(self, new_revision):
1105
"""Template method part of set_last_revision to perform the change.
1107
This is used to allow WorkingTree3 instances to not affect branch
1108
when their last revision is set.
1110
if _mod_revision.is_null(new_revision):
1111
self.branch.set_last_revision_info(0, new_revision)
1113
_mod_revision.check_not_reserved_id(new_revision)
1115
self.branch.generate_revision_history(new_revision)
1116
except errors.NoSuchRevision:
1117
# not present in the repo - dont try to set it deeper than the tip
1118
self.branch._set_revision_history([new_revision])
1121
@needs_tree_write_lock
1122
def remove(self, files, verbose=False, to_file=None, keep_files=True,
1124
"""Remove nominated files from the working tree metadata.
1126
:files: File paths relative to the basedir.
1127
:keep_files: If true, the files will also be kept.
1128
:force: Delete files and directories, even if they are changed and
1129
even if the directories are not empty.
1131
if isinstance(files, (str, text_type)):
1136
all_files = set() # specified and nested files
1137
unknown_nested_files=set()
1139
to_file = sys.stdout
1141
files_to_backup = []
1143
def recurse_directory_to_add_files(directory):
1144
# Recurse directory and add all files
1145
# so we can check if they have changed.
1146
for parent_info, file_infos in self.walkdirs(directory):
1147
for relpath, basename, kind, lstat, fileid, kind in file_infos:
1148
# Is it versioned or ignored?
1149
if self.path2id(relpath):
1150
# Add nested content for deletion.
1151
all_files.add(relpath)
1153
# Files which are not versioned
1154
# should be treated as unknown.
1155
files_to_backup.append(relpath)
1157
for filename in files:
1158
# Get file name into canonical form.
1159
abspath = self.abspath(filename)
1160
filename = self.relpath(abspath)
1161
if len(filename) > 0:
1162
all_files.add(filename)
1163
recurse_directory_to_add_files(filename)
1165
files = list(all_files)
1168
return # nothing to do
1170
# Sort needed to first handle directory content before the directory
1171
files.sort(reverse=True)
1173
# Bail out if we are going to delete files we shouldn't
1174
if not keep_files and not force:
1175
for (file_id, path, content_change, versioned, parent_id, name,
1176
kind, executable) in self.iter_changes(self.basis_tree(),
1177
include_unchanged=True, require_versioned=False,
1178
want_unversioned=True, specific_files=files):
1179
if versioned[0] == False:
1180
# The record is unknown or newly added
1181
files_to_backup.append(path[1])
1182
elif (content_change and (kind[1] is not None) and
1183
osutils.is_inside_any(files, path[1])):
1184
# Versioned and changed, but not deleted, and still
1185
# in one of the dirs to be deleted.
1186
files_to_backup.append(path[1])
1188
def backup(file_to_backup):
1189
backup_name = self.controldir._available_backup_name(file_to_backup)
1190
osutils.rename(abs_path, self.abspath(backup_name))
1191
return "removed %s (but kept a copy: %s)" % (file_to_backup,
1194
# Build inv_delta and delete files where applicable,
1195
# do this before any modifications to meta data.
1197
fid = self.path2id(f)
1200
message = "%s is not versioned." % (f,)
1203
# having removed it, it must be either ignored or unknown
1204
if self.is_ignored(f):
1208
# XXX: Really should be a more abstract reporter interface
1209
kind_ch = osutils.kind_marker(self.kind(fid))
1210
to_file.write(new_status + ' ' + f + kind_ch + '\n')
1212
inv_delta.append((f, None, fid, None))
1213
message = "removed %s" % (f,)
1216
abs_path = self.abspath(f)
1217
if osutils.lexists(abs_path):
1218
if (osutils.isdir(abs_path) and
1219
len(os.listdir(abs_path)) > 0):
1221
osutils.rmtree(abs_path)
1222
message = "deleted %s" % (f,)
1226
if f in files_to_backup:
1229
osutils.delete_any(abs_path)
1230
message = "deleted %s" % (f,)
1231
elif message is not None:
1232
# Only care if we haven't done anything yet.
1233
message = "%s does not exist." % (f,)
1235
# Print only one message (if any) per file.
1236
if message is not None:
1238
self.apply_inventory_delta(inv_delta)
1240
@needs_tree_write_lock
1241
def revert(self, filenames=None, old_tree=None, backups=True,
1242
pb=None, report_changes=False):
1243
from .conflicts import resolve
1244
if old_tree is None:
1245
basis_tree = self.basis_tree()
1246
basis_tree.lock_read()
1247
old_tree = basis_tree
1251
conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1253
if filenames is None and len(self.get_parent_ids()) > 1:
1255
last_revision = self.last_revision()
1256
if last_revision != _mod_revision.NULL_REVISION:
1257
if basis_tree is None:
1258
basis_tree = self.basis_tree()
1259
basis_tree.lock_read()
1260
parent_trees.append((last_revision, basis_tree))
1261
self.set_parent_trees(parent_trees)
1264
resolve(self, filenames, ignore_misses=True, recursive=True)
1266
if basis_tree is not None:
1271
def store_uncommitted(self):
1272
"""Store uncommitted changes from the tree in the branch."""
1273
target_tree = self.basis_tree()
1274
shelf_creator = shelf.ShelfCreator(self, target_tree)
1276
if not shelf_creator.shelve_all():
1278
self.branch.store_uncommitted(shelf_creator)
1279
shelf_creator.transform()
1281
shelf_creator.finalize()
1282
note('Uncommitted changes stored in branch "%s".', self.branch.nick)
1285
def restore_uncommitted(self):
1286
"""Restore uncommitted changes from the branch into the tree."""
1287
unshelver = self.branch.get_unshelver(self)
1288
if unshelver is None:
1291
merger = unshelver.make_merger()
1292
merger.ignore_zero = True
1294
self.branch.store_uncommitted(None)
1296
unshelver.finalize()
1298
def revision_tree(self, revision_id):
1299
"""See Tree.revision_tree.
1301
WorkingTree can supply revision_trees for the basis revision only
1302
because there is only one cached inventory in the bzr directory.
1304
raise NotImplementedError(self.revision_tree)
1306
@needs_tree_write_lock
1307
def set_root_id(self, file_id):
1308
"""Set the root id for this tree."""
1309
if not self.supports_setting_file_ids():
1310
raise SettingFileIdUnsupported()
1314
'WorkingTree.set_root_id with fileid=None')
1315
file_id = osutils.safe_file_id(file_id)
1316
self._set_root_id(file_id)
1318
def _set_root_id(self, file_id):
1319
"""Set the root id for this tree, in a format specific manner.
1321
:param file_id: The file id to assign to the root. It must not be
1322
present in the current inventory or an error will occur. It must
1323
not be None, but rather a valid file id.
1325
raise NotImplementedError(self._set_root_id)
1328
"""See Branch.unlock.
1330
WorkingTree locking just uses the Branch locking facilities.
1331
This is current because all working trees have an embedded branch
1332
within them. IF in the future, we were to make branch data shareable
1333
between multiple working trees, i.e. via shared storage, then we
1334
would probably want to lock both the local tree, and the branch.
1336
raise NotImplementedError(self.unlock)
1340
def update(self, change_reporter=None, possible_transports=None,
1341
revision=None, old_tip=_marker, show_base=False):
1342
"""Update a working tree along its branch.
1344
This will update the branch if its bound too, which means we have
1345
multiple trees involved:
1347
- The new basis tree of the master.
1348
- The old basis tree of the branch.
1349
- The old basis tree of the working tree.
1350
- The current working tree state.
1352
Pathologically, all three may be different, and non-ancestors of each
1353
other. Conceptually we want to:
1355
- Preserve the wt.basis->wt.state changes
1356
- Transform the wt.basis to the new master basis.
1357
- Apply a merge of the old branch basis to get any 'local' changes from
1359
- Restore the wt.basis->wt.state changes.
1361
There isn't a single operation at the moment to do that, so we:
1363
- Merge current state -> basis tree of the master w.r.t. the old tree
1365
- Do a 'normal' merge of the old branch basis if it is relevant.
1367
:param revision: The target revision to update to. Must be in the
1369
:param old_tip: If branch.update() has already been run, the value it
1370
returned (old tip of the branch or None). _marker is used
1373
if self.branch.get_bound_location() is not None:
1375
update_branch = (old_tip is self._marker)
1377
self.lock_tree_write()
1378
update_branch = False
1381
old_tip = self.branch.update(possible_transports)
1383
if old_tip is self._marker:
1385
return self._update_tree(old_tip, change_reporter, revision, show_base)
1389
@needs_tree_write_lock
1390
def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
1392
"""Update a tree to the master branch.
1394
:param old_tip: if supplied, the previous tip revision the branch,
1395
before it was changed to the master branch's tip.
1397
# here if old_tip is not None, it is the old tip of the branch before
1398
# it was updated from the master branch. This should become a pending
1399
# merge in the working tree to preserve the user existing work. we
1400
# cant set that until we update the working trees last revision to be
1401
# one from the new branch, because it will just get absorbed by the
1402
# parent de-duplication logic.
1404
# We MUST save it even if an error occurs, because otherwise the users
1405
# local work is unreferenced and will appear to have been lost.
1409
last_rev = self.get_parent_ids()[0]
1411
last_rev = _mod_revision.NULL_REVISION
1412
if revision is None:
1413
revision = self.branch.last_revision()
1415
old_tip = old_tip or _mod_revision.NULL_REVISION
1417
if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
1418
# the branch we are bound to was updated
1419
# merge those changes in first
1420
base_tree = self.basis_tree()
1421
other_tree = self.branch.repository.revision_tree(old_tip)
1422
nb_conflicts = merge.merge_inner(self.branch, other_tree,
1423
base_tree, this_tree=self,
1424
change_reporter=change_reporter,
1425
show_base=show_base)
1427
self.add_parent_tree((old_tip, other_tree))
1428
note(gettext('Rerun update after fixing the conflicts.'))
1431
if last_rev != _mod_revision.ensure_null(revision):
1432
# the working tree is up to date with the branch
1433
# we can merge the specified revision from master
1434
to_tree = self.branch.repository.revision_tree(revision)
1435
to_root_id = to_tree.get_root_id()
1437
basis = self.basis_tree()
1440
if (basis.get_root_id() is None or basis.get_root_id() != to_root_id):
1441
self.set_root_id(to_root_id)
1446
# determine the branch point
1447
graph = self.branch.repository.get_graph()
1448
base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
1450
base_tree = self.branch.repository.revision_tree(base_rev_id)
1452
nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
1454
change_reporter=change_reporter,
1455
show_base=show_base)
1456
self.set_last_revision(revision)
1457
# TODO - dedup parents list with things merged by pull ?
1458
# reuse the tree we've updated to to set the basis:
1459
parent_trees = [(revision, to_tree)]
1460
merges = self.get_parent_ids()[1:]
1461
# Ideally we ask the tree for the trees here, that way the working
1462
# tree can decide whether to give us the entire tree or give us a
1463
# lazy initialised tree. dirstate for instance will have the trees
1464
# in ram already, whereas a last-revision + basis-inventory tree
1465
# will not, but also does not need them when setting parents.
1466
for parent in merges:
1467
parent_trees.append(
1468
(parent, self.branch.repository.revision_tree(parent)))
1469
if not _mod_revision.is_null(old_tip):
1470
parent_trees.append(
1471
(old_tip, self.branch.repository.revision_tree(old_tip)))
1472
self.set_parent_trees(parent_trees)
1473
last_rev = parent_trees[0][0]
1476
def set_conflicts(self, arg):
1477
raise errors.UnsupportedOperation(self.set_conflicts, self)
1479
def add_conflicts(self, arg):
1480
raise errors.UnsupportedOperation(self.add_conflicts, self)
1482
def conflicts(self):
1483
raise NotImplementedError(self.conflicts)
1485
def walkdirs(self, prefix=""):
1486
"""Walk the directories of this tree.
1488
returns a generator which yields items in the form:
1489
((curren_directory_path, fileid),
1490
[(file1_path, file1_name, file1_kind, (lstat), file1_id,
1493
This API returns a generator, which is only valid during the current
1494
tree transaction - within a single lock_read or lock_write duration.
1496
If the tree is not locked, it may cause an error to be raised,
1497
depending on the tree implementation.
1499
disk_top = self.abspath(prefix)
1500
if disk_top.endswith('/'):
1501
disk_top = disk_top[:-1]
1502
top_strip_len = len(disk_top) + 1
1503
inventory_iterator = self._walkdirs(prefix)
1504
disk_iterator = osutils.walkdirs(disk_top, prefix)
1506
current_disk = next(disk_iterator)
1507
disk_finished = False
1508
except OSError as e:
1509
if not (e.errno == errno.ENOENT or
1510
(sys.platform == 'win32' and e.errno == ERROR_PATH_NOT_FOUND)):
1513
disk_finished = True
1515
current_inv = next(inventory_iterator)
1516
inv_finished = False
1517
except StopIteration:
1520
while not inv_finished or not disk_finished:
1522
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1523
cur_disk_dir_content) = current_disk
1525
((cur_disk_dir_relpath, cur_disk_dir_path_from_top),
1526
cur_disk_dir_content) = ((None, None), None)
1527
if not disk_finished:
1528
# strip out .bzr dirs
1529
if (cur_disk_dir_path_from_top[top_strip_len:] == '' and
1530
len(cur_disk_dir_content) > 0):
1531
# osutils.walkdirs can be made nicer -
1532
# yield the path-from-prefix rather than the pathjoined
1534
bzrdir_loc = bisect_left(cur_disk_dir_content,
1536
if (bzrdir_loc < len(cur_disk_dir_content)
1537
and self.controldir.is_control_filename(
1538
cur_disk_dir_content[bzrdir_loc][0])):
1539
# we dont yield the contents of, or, .bzr itself.
1540
del cur_disk_dir_content[bzrdir_loc]
1542
# everything is unknown
1545
# everything is missing
1548
direction = cmp(current_inv[0][0], cur_disk_dir_relpath)
1550
# disk is before inventory - unknown
1551
dirblock = [(relpath, basename, kind, stat, None, None) for
1552
relpath, basename, kind, stat, top_path in
1553
cur_disk_dir_content]
1554
yield (cur_disk_dir_relpath, None), dirblock
1556
current_disk = next(disk_iterator)
1557
except StopIteration:
1558
disk_finished = True
1560
# inventory is before disk - missing.
1561
dirblock = [(relpath, basename, 'unknown', None, fileid, kind)
1562
for relpath, basename, dkind, stat, fileid, kind in
1564
yield (current_inv[0][0], current_inv[0][1]), dirblock
1566
current_inv = next(inventory_iterator)
1567
except StopIteration:
1570
# versioned present directory
1571
# merge the inventory and disk data together
1573
for relpath, subiterator in itertools.groupby(sorted(
1574
current_inv[1] + cur_disk_dir_content,
1575
key=operator.itemgetter(0)), operator.itemgetter(1)):
1576
path_elements = list(subiterator)
1577
if len(path_elements) == 2:
1578
inv_row, disk_row = path_elements
1579
# versioned, present file
1580
dirblock.append((inv_row[0],
1581
inv_row[1], disk_row[2],
1582
disk_row[3], inv_row[4],
1584
elif len(path_elements[0]) == 5:
1586
dirblock.append((path_elements[0][0],
1587
path_elements[0][1], path_elements[0][2],
1588
path_elements[0][3], None, None))
1589
elif len(path_elements[0]) == 6:
1590
# versioned, absent file.
1591
dirblock.append((path_elements[0][0],
1592
path_elements[0][1], 'unknown', None,
1593
path_elements[0][4], path_elements[0][5]))
1595
raise NotImplementedError('unreachable code')
1596
yield current_inv[0], dirblock
1598
current_inv = next(inventory_iterator)
1599
except StopIteration:
1602
current_disk = next(disk_iterator)
1603
except StopIteration:
1604
disk_finished = True
1606
def _walkdirs(self, prefix=""):
1607
"""Walk the directories of this tree.
1609
:param prefix: is used as the directrory to start with.
1610
:returns: a generator which yields items in the form::
1612
((curren_directory_path, fileid),
1613
[(file1_path, file1_name, file1_kind, None, file1_id,
1616
raise NotImplementedError(self._walkdirs)
1618
@needs_tree_write_lock
1619
def auto_resolve(self):
1620
"""Automatically resolve text conflicts according to contents.
1622
Only text conflicts are auto_resolvable. Files with no conflict markers
1623
are considered 'resolved', because bzr always puts conflict markers
1624
into files that have text conflicts. The corresponding .THIS .BASE and
1625
.OTHER files are deleted, as per 'resolve'.
1627
:return: a tuple of ConflictLists: (un_resolved, resolved).
1629
un_resolved = _mod_conflicts.ConflictList()
1630
resolved = _mod_conflicts.ConflictList()
1631
conflict_re = re.compile('^(<{7}|={7}|>{7})')
1632
for conflict in self.conflicts():
1633
if (conflict.typestring != 'text conflict' or
1634
self.kind(conflict.file_id) != 'file'):
1635
un_resolved.append(conflict)
1637
my_file = open(self.id2abspath(conflict.file_id), 'rb')
1639
for line in my_file:
1640
if conflict_re.search(line):
1641
un_resolved.append(conflict)
1644
resolved.append(conflict)
1647
resolved.remove_files(self)
1648
self.set_conflicts(un_resolved)
1649
return un_resolved, resolved
1651
def _validate(self):
1652
"""Validate internal structures.
1654
This is meant mostly for the test suite. To give it a chance to detect
1655
corruption after actions have occurred. The default implementation is a
1658
:return: None. An exception should be raised if there is an error.
1662
def check_state(self):
1663
"""Check that the working state is/isn't valid."""
1664
raise NotImplementedError(self.check_state)
1666
def reset_state(self, revision_ids=None):
1667
"""Reset the state of the working tree.
1669
This does a hard-reset to a last-known-good state. This is a way to
1670
fix if something got corrupted (like the .bzr/checkout/dirstate file)
1672
raise NotImplementedError(self.reset_state)
1674
def _get_rules_searcher(self, default_searcher):
1675
"""See Tree._get_rules_searcher."""
1676
if self._rules_searcher is None:
1677
self._rules_searcher = super(WorkingTree,
1678
self)._get_rules_searcher(default_searcher)
1679
return self._rules_searcher
1681
def get_shelf_manager(self):
1682
"""Return the ShelfManager for this WorkingTree."""
1683
from .shelf import ShelfManager
1684
return ShelfManager(self, self._transport)
1687
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
1688
"""Registry for working tree formats."""
1690
def __init__(self, other_registry=None):
1691
super(WorkingTreeFormatRegistry, self).__init__(other_registry)
1692
self._default_format = None
1693
self._default_format_key = None
1695
def get_default(self):
1696
"""Return the current default format."""
1697
if (self._default_format_key is not None and
1698
self._default_format is None):
1699
self._default_format = self.get(self._default_format_key)
1700
return self._default_format
1702
def set_default(self, format):
1703
"""Set the default format."""
1704
self._default_format = format
1705
self._default_format_key = None
1707
def set_default_key(self, format_string):
1708
"""Set the default format by its format string."""
1709
self._default_format_key = format_string
1710
self._default_format = None
1713
format_registry = WorkingTreeFormatRegistry()
1716
class WorkingTreeFormat(controldir.ControlComponentFormat):
1717
"""An encapsulation of the initialization and open routines for a format.
1719
Formats provide three things:
1720
* An initialization routine,
1724
Formats are placed in an dict by their format string for reference
1725
during workingtree opening. Its not required that these be instances, they
1726
can be classes themselves with class methods - it simply depends on
1727
whether state is needed for a given format or not.
1729
Once a format is deprecated, just deprecate the initialize and open
1730
methods on the format class. Do not deprecate the object, as the
1731
object will be created every time regardless.
1734
requires_rich_root = False
1736
upgrade_recommended = False
1738
requires_normalized_unicode_filenames = False
1740
case_sensitive_filename = "FoRMaT"
1742
missing_parent_conflicts = False
1743
"""If this format supports missing parent conflicts."""
1745
supports_versioned_directories = None
1747
supports_setting_file_ids = True
1748
"""If this format allows setting the file id."""
1750
def initialize(self, controldir, revision_id=None, from_branch=None,
1751
accelerator_tree=None, hardlink=False):
1752
"""Initialize a new working tree in controldir.
1754
:param controldir: ControlDir to initialize the working tree in.
1755
:param revision_id: allows creating a working tree at a different
1756
revision than the branch is at.
1757
:param from_branch: Branch to checkout
1758
:param accelerator_tree: A tree which can be used for retrieving file
1759
contents more quickly than the revision tree, i.e. a workingtree.
1760
The revision tree will be used for cases where accelerator_tree's
1761
content is different.
1762
:param hardlink: If true, hard-link files from accelerator_tree,
1765
raise NotImplementedError(self.initialize)
1767
def __eq__(self, other):
1768
return self.__class__ is other.__class__
1770
def __ne__(self, other):
1771
return not (self == other)
1773
def get_format_description(self):
1774
"""Return the short description for this format."""
1775
raise NotImplementedError(self.get_format_description)
1777
def is_supported(self):
1778
"""Is this format supported?
1780
Supported formats can be initialized and opened.
1781
Unsupported formats may not support initialization or committing or
1782
some other features depending on the reason for not being supported.
1786
def supports_content_filtering(self):
1787
"""True if this format supports content filtering."""
1790
def supports_views(self):
1791
"""True if this format supports stored views."""
1794
def get_controldir_for_branch(self):
1795
"""Get the control directory format for creating branches.
1797
This is to support testing of working tree formats that can not exist
1798
in the same control directory as a branch.
1800
return self._matchingbzrdir
1803
format_registry.register_lazy("Bazaar Working Tree Format 4 (bzr 0.15)\n",
1804
"breezy.bzr.workingtree_4", "WorkingTreeFormat4")
1805
format_registry.register_lazy("Bazaar Working Tree Format 5 (bzr 1.11)\n",
1806
"breezy.bzr.workingtree_4", "WorkingTreeFormat5")
1807
format_registry.register_lazy("Bazaar Working Tree Format 6 (bzr 1.14)\n",
1808
"breezy.bzr.workingtree_4", "WorkingTreeFormat6")
1809
format_registry.register_lazy("Bazaar-NG Working Tree format 3",
1810
"breezy.bzr.workingtree_3", "WorkingTreeFormat3")
1811
format_registry.set_default_key("Bazaar Working Tree Format 6 (bzr 1.14)\n")