/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/workingtree.py

  • Committer: Jelmer Vernooij
  • Date: 2019-05-20 03:57:29 UTC
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190520035729-9rxvefxkvbbivygy
use default_user_agent function.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
 
32
32
import errno
33
33
import os
 
34
import re
34
35
import sys
35
36
 
36
37
import breezy
41
42
import stat
42
43
 
43
44
from breezy import (
44
 
    cleanup,
45
45
    conflicts as _mod_conflicts,
 
46
    controldir,
 
47
    errors,
46
48
    filters as _mod_filters,
47
49
    merge,
48
50
    revision as _mod_revision,
56
58
""")
57
59
 
58
60
from . import (
59
 
    errors,
60
 
    )
61
 
from .controldir import (
62
 
    ControlComponent,
63
 
    ControlComponentFormatRegistry,
64
 
    ControlComponentFormat,
65
 
    ControlDir,
66
 
    ControlDirFormat,
67
 
    )
68
 
from . import (
69
61
    osutils,
70
62
    )
71
63
from .i18n import gettext
72
64
from . import mutabletree
73
 
from .symbol_versioning import deprecated_method, deprecated_in
74
65
from .trace import mutter, note
75
66
 
76
67
 
 
68
ERROR_PATH_NOT_FOUND = 3    # WindowsError errno code, equivalent to ENOENT
 
69
 
 
70
 
77
71
class SettingFileIdUnsupported(errors.BzrError):
78
72
 
79
73
    _fmt = "This format does not support setting file ids."
84
78
    _fmt = "This format does not support shelving changes."
85
79
 
86
80
 
87
 
class WorkingTree(mutabletree.MutableTree, ControlComponent):
 
81
class WorkingTree(mutabletree.MutableTree, controldir.ControlComponent):
88
82
    """Working copy tree.
89
83
 
90
84
    :ivar basedir: The root of the tree on disk. This is a unicode path object
129
123
    def control_transport(self):
130
124
        return self._transport
131
125
 
132
 
    def supports_symlinks(self):
133
 
        return osutils.supports_symlinks(self.basedir)
134
 
 
135
126
    def is_control_filename(self, filename):
136
127
        """True if filename is the name of a control file in this tree.
137
128
 
162
153
        return self._format.supports_merge_modified
163
154
 
164
155
    def _supports_executable(self):
165
 
        return osutils.supports_executable(self.basedir)
 
156
        if sys.platform == 'win32':
 
157
            return False
 
158
        # FIXME: Ideally this should check the file system
 
159
        return True
166
160
 
167
161
    def break_lock(self):
168
162
        """Break a lock if one is present from another instance.
204
198
        """
205
199
        if path is None:
206
200
            path = osutils.getcwd()
207
 
        control = ControlDir.open(path, _unsupported=_unsupported)
 
201
        control = controldir.ControlDir.open(path, _unsupported=_unsupported)
208
202
        return control.open_workingtree(unsupported=_unsupported)
209
203
 
210
204
    @staticmethod
222
216
        """
223
217
        if path is None:
224
218
            path = osutils.getcwd()
225
 
        control, relpath = ControlDir.open_containing(path)
 
219
        control, relpath = controldir.ControlDir.open_containing(path)
226
220
        return control.open_workingtree(), relpath
227
221
 
228
222
    @staticmethod
300
294
        """
301
295
        return WorkingTree.open(path, _unsupported=True)
302
296
 
 
297
    @staticmethod
 
298
    def find_trees(location):
 
299
        def list_current(transport):
 
300
            return [d for d in transport.list_dir('')
 
301
                    if not controldir.is_control_filename(d)]
 
302
 
 
303
        def evaluate(controldir):
 
304
            try:
 
305
                tree = controldir.open_workingtree()
 
306
            except errors.NoWorkingTree:
 
307
                return True, None
 
308
            else:
 
309
                return True, tree
 
310
        t = transport.get_transport(location)
 
311
        iterator = controldir.ControlDir.find_controldirs(t, evaluate=evaluate,
 
312
                                                          list_current=list_current)
 
313
        return [tr for tr in iterator if tr is not None]
 
314
 
303
315
    def __repr__(self):
304
316
        return "<%s of %s>" % (self.__class__.__name__,
305
317
                               getattr(self, 'basedir', None))
368
380
        stat_value = _fstat(file_obj.fileno())
369
381
        if filtered and self.supports_content_filtering():
370
382
            filters = self._content_filter_stack(path)
371
 
            if filters:
372
 
                file_obj, size = _mod_filters.filtered_input_file(
373
 
                    file_obj, filters)
374
 
                stat_value = _mod_filters.FilteredStat(
375
 
                    stat_value, st_size=size)
 
383
            file_obj = _mod_filters.filtered_input_file(file_obj, filters)
376
384
        return (file_obj, stat_value)
377
385
 
378
386
    def get_file_text(self, path, filtered=True):
405
413
                parents.append(revision_id)
406
414
        return parents
407
415
 
 
416
    def get_root_id(self):
 
417
        """Return the id of this trees root"""
 
418
        raise NotImplementedError(self.get_root_id)
 
419
 
408
420
    def clone(self, to_controldir, revision_id=None):
409
421
        """Duplicate this working tree into to_bzr, including all state.
410
422
 
427
439
    def copy_content_into(self, tree, revision_id=None):
428
440
        """Copy the current content and user files of this tree into tree."""
429
441
        with self.lock_read():
430
 
            tree.set_root_id(self.path2id(''))
 
442
            tree.set_root_id(self.get_root_id())
431
443
            if revision_id is None:
432
444
                merge.transform_tree(tree, self)
433
445
            else:
661
673
            merger.other_rev_id = to_revision
662
674
            if _mod_revision.is_null(merger.other_rev_id):
663
675
                raise errors.NoCommits(branch)
664
 
            self.branch.fetch(branch, stop_revision=merger.other_rev_id)
 
676
            self.branch.fetch(branch, last_revision=merger.other_rev_id)
665
677
            merger.other_basis = merger.other_rev_id
666
678
            merger.other_tree = self.branch.repository.revision_tree(
667
679
                merger.other_rev_id)
717
729
    def subsume(self, other_tree):
718
730
        raise NotImplementedError(self.subsume)
719
731
 
720
 
    def _directory_is_tree_reference(self, relpath):
721
 
        raise NotImplementedError(self._directory_is_tree_reference)
 
732
    def _setup_directory_is_tree_reference(self):
 
733
        if self._branch.repository._format.supports_tree_reference:
 
734
            self._directory_is_tree_reference = \
 
735
                self._directory_may_be_tree_reference
 
736
        else:
 
737
            self._directory_is_tree_reference = \
 
738
                self._directory_is_never_tree_reference
 
739
 
 
740
    def _directory_is_never_tree_reference(self, relpath):
 
741
        return False
 
742
 
 
743
    def _directory_may_be_tree_reference(self, relpath):
 
744
        # as a special case, if a directory contains control files then
 
745
        # it's a tree reference, except that the root of the tree is not
 
746
        return relpath and osutils.isdir(self.abspath(relpath) + u"/.bzr")
 
747
        # TODO: We could ask all the control formats whether they
 
748
        # recognize this directory, but at the moment there's no cheap api
 
749
        # to do that.  Since we probably can only nest bzr checkouts and
 
750
        # they always use this name it's ok for now.  -- mbp 20060306
 
751
        #
 
752
        # FIXME: There is an unhandled case here of a subdirectory
 
753
        # containing .bzr but not a branch; that will probably blow up
 
754
        # when you try to commit it.  It might happen if there is a
 
755
        # checkout in a subdirectory.  This can be avoided by not adding
 
756
        # it.  mbp 20070306
722
757
 
723
758
    def extract(self, path, format=None):
724
759
        """Extract a subtree from this tree.
734
769
    def kind(self, relpath):
735
770
        return osutils.file_kind(self.abspath(relpath))
736
771
 
737
 
    def list_files(self, include_root=False, from_dir=None, recursive=True,
738
 
                   recurse_nested=False):
 
772
    def list_files(self, include_root=False, from_dir=None, recursive=True):
739
773
        """List all files as (path, class, kind, id, entry).
740
774
 
741
775
        Lists, but does not descend into unversioned directories.
821
855
 
822
856
    def pull(self, source, overwrite=False, stop_revision=None,
823
857
             change_reporter=None, possible_transports=None, local=False,
824
 
             show_base=False, tag_selector=None):
 
858
             show_base=False):
825
859
        with self.lock_write(), source.lock_read():
826
860
            old_revision_info = self.branch.last_revision_info()
827
861
            basis_tree = self.basis_tree()
828
862
            count = self.branch.pull(source, overwrite, stop_revision,
829
863
                                     possible_transports=possible_transports,
830
 
                                     local=local, tag_selector=tag_selector)
 
864
                                     local=local)
831
865
            new_revision_info = self.branch.last_revision_info()
832
866
            if new_revision_info != old_revision_info:
833
867
                repository = self.branch.repository
845
879
                        this_tree=self,
846
880
                        change_reporter=change_reporter,
847
881
                        show_base=show_base)
848
 
                    basis_root_id = basis_tree.path2id('')
849
 
                    new_root_id = new_basis_tree.path2id('')
 
882
                    basis_root_id = basis_tree.get_root_id()
 
883
                    new_root_id = new_basis_tree.get_root_id()
850
884
                    if new_root_id is not None and basis_root_id != new_root_id:
851
885
                        self.set_root_id(new_root_id)
852
886
                # TODO - dedup parents list with things merged by pull ?
1002
1036
    def revert(self, filenames=None, old_tree=None, backups=True,
1003
1037
               pb=None, report_changes=False):
1004
1038
        from .conflicts import resolve
1005
 
        with cleanup.ExitStack() as exit_stack:
1006
 
            exit_stack.enter_context(self.lock_tree_write())
 
1039
        with self.lock_tree_write():
1007
1040
            if old_tree is None:
1008
1041
                basis_tree = self.basis_tree()
1009
 
                exit_stack.enter_context(basis_tree.lock_read())
 
1042
                basis_tree.lock_read()
1010
1043
                old_tree = basis_tree
1011
1044
            else:
1012
1045
                basis_tree = None
1013
 
            conflicts = transform.revert(self, old_tree, filenames, backups, pb,
1014
 
                                         report_changes)
1015
 
            if filenames is None and len(self.get_parent_ids()) > 1:
1016
 
                parent_trees = []
1017
 
                last_revision = self.last_revision()
1018
 
                if last_revision != _mod_revision.NULL_REVISION:
1019
 
                    if basis_tree is None:
1020
 
                        basis_tree = self.basis_tree()
1021
 
                        exit_stack.enter_context(basis_tree.lock_read())
1022
 
                    parent_trees.append((last_revision, basis_tree))
1023
 
                self.set_parent_trees(parent_trees)
1024
 
                resolve(self)
1025
 
            else:
1026
 
                resolve(self, filenames, ignore_misses=True, recursive=True)
 
1046
            try:
 
1047
                conflicts = transform.revert(self, old_tree, filenames, backups, pb,
 
1048
                                             report_changes)
 
1049
                if filenames is None and len(self.get_parent_ids()) > 1:
 
1050
                    parent_trees = []
 
1051
                    last_revision = self.last_revision()
 
1052
                    if last_revision != _mod_revision.NULL_REVISION:
 
1053
                        if basis_tree is None:
 
1054
                            basis_tree = self.basis_tree()
 
1055
                            basis_tree.lock_read()
 
1056
                        parent_trees.append((last_revision, basis_tree))
 
1057
                    self.set_parent_trees(parent_trees)
 
1058
                    resolve(self)
 
1059
                else:
 
1060
                    resolve(self, filenames, ignore_misses=True, recursive=True)
 
1061
            finally:
 
1062
                if basis_tree is not None:
 
1063
                    basis_tree.unlock()
1027
1064
            return conflicts
1028
1065
 
1029
1066
    def store_uncommitted(self):
1171
1208
                # the working tree is up to date with the branch
1172
1209
                # we can merge the specified revision from master
1173
1210
                to_tree = self.branch.repository.revision_tree(revision)
1174
 
                to_root_id = to_tree.path2id('')
 
1211
                to_root_id = to_tree.get_root_id()
1175
1212
 
1176
1213
                basis = self.basis_tree()
1177
1214
                with basis.lock_read():
1178
 
                    if (basis.path2id('') is None or basis.path2id('') != to_root_id):
 
1215
                    if (basis.get_root_id() is None or basis.get_root_id() != to_root_id):
1179
1216
                        self.set_root_id(to_root_id)
1180
1217
                        self.flush()
1181
1218
 
1234
1271
        """
1235
1272
        raise NotImplementedError(self.walkdirs)
1236
1273
 
1237
 
    @deprecated_method(deprecated_in((3, 0, 1)))
1238
1274
    def auto_resolve(self):
1239
1275
        """Automatically resolve text conflicts according to contents.
1240
1276
 
1248
1284
        with self.lock_tree_write():
1249
1285
            un_resolved = _mod_conflicts.ConflictList()
1250
1286
            resolved = _mod_conflicts.ConflictList()
 
1287
            conflict_re = re.compile(b'^(<{7}|={7}|>{7})')
1251
1288
            for conflict in self.conflicts():
1252
 
                try:
1253
 
                    conflict.action_auto(self)
1254
 
                except NotImplementedError:
 
1289
                path = self.id2path(conflict.file_id)
 
1290
                if (conflict.typestring != 'text conflict' or
 
1291
                        self.kind(path) != 'file'):
1255
1292
                    un_resolved.append(conflict)
1256
 
                else:
1257
 
                    conflict.cleanup(self)
1258
 
                    resolved.append(conflict)
 
1293
                    continue
 
1294
                with open(self.abspath(path), 'rb') as my_file:
 
1295
                    for line in my_file:
 
1296
                        if conflict_re.search(line):
 
1297
                            un_resolved.append(conflict)
 
1298
                            break
 
1299
                    else:
 
1300
                        resolved.append(conflict)
 
1301
            resolved.remove_files(self)
1259
1302
            self.set_conflicts(un_resolved)
1260
1303
            return un_resolved, resolved
1261
1304
 
1329
1372
        with self.lock_read():
1330
1373
            return next(self.get_canonical_paths([path]))
1331
1374
 
1332
 
    def reference_parent(self, path, branch=None, possible_transports=None):
1333
 
        raise errors.UnsupportedOperation(self.reference_parent, self)
1334
 
 
1335
 
    def get_reference_info(self, path, branch=None):
1336
 
        raise errors.UnsupportedOperation(self.get_reference_info, self)
1337
 
 
1338
 
    def set_reference_info(self, tree_path, branch_location):
1339
 
        raise errors.UnsupportedOperation(self.set_reference_info, self)
1340
 
 
1341
 
 
1342
 
class WorkingTreeFormatRegistry(ControlComponentFormatRegistry):
 
1375
 
 
1376
class WorkingTreeFormatRegistry(controldir.ControlComponentFormatRegistry):
1343
1377
    """Registry for working tree formats."""
1344
1378
 
1345
1379
    def __init__(self, other_registry=None):
1368
1402
format_registry = WorkingTreeFormatRegistry()
1369
1403
 
1370
1404
 
1371
 
class WorkingTreeFormat(ControlComponentFormat):
 
1405
class WorkingTreeFormat(controldir.ControlComponentFormat):
1372
1406
    """An encapsulation of the initialization and open routines for a format.
1373
1407
 
1374
1408
    Formats provide three things: