/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: Gustav Hartvigsson
  • Date: 2021-01-09 21:36:27 UTC
  • Revision ID: gustav.hartvigsson@gmail.com-20210109213627-h1xwcutzy9m7a99b
Added 'Case Preserving Working Tree Use Cases' from Canonical Wiki

* Addod a page from the Canonical Bazaar wiki
  with information on the scmeatics of case
  perserving filesystems an a case insensitive
  filesystem works.
  
  * Needs re-work, but this will do as it is the
    same inforamoton as what was on the linked
    page in the currint documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
WorkingTree.open(dir).
28
28
"""
29
29
 
30
 
from __future__ import absolute_import
31
 
 
 
30
import contextlib
32
31
import errno
33
32
import os
34
33
import sys
41
40
import stat
42
41
 
43
42
from breezy import (
44
 
    cleanup,
45
43
    conflicts as _mod_conflicts,
46
44
    filters as _mod_filters,
47
45
    merge,
711
709
 
712
710
    def get_symlink_target(self, path):
713
711
        abspath = self.abspath(path)
714
 
        target = osutils.readlink(abspath)
715
 
        return target
 
712
        try:
 
713
            return osutils.readlink(abspath)
 
714
        except OSError as e:
 
715
            if getattr(e, 'errno', None) == errno.ENOENT:
 
716
                raise errors.NoSuchFile(path)
 
717
            raise
716
718
 
717
719
    def subsume(self, other_tree):
718
720
        raise NotImplementedError(self.subsume)
1002
1004
    def revert(self, filenames=None, old_tree=None, backups=True,
1003
1005
               pb=None, report_changes=False):
1004
1006
        from .conflicts import resolve
1005
 
        with cleanup.ExitStack() as exit_stack:
 
1007
        with contextlib.ExitStack() as exit_stack:
1006
1008
            exit_stack.enter_context(self.lock_tree_write())
1007
1009
            if old_tree is None:
1008
1010
                basis_tree = self.basis_tree()
1051
1053
            if file_id is None:
1052
1054
                raise ValueError(
1053
1055
                    'WorkingTree.set_root_id with fileid=None')
1054
 
            file_id = osutils.safe_file_id(file_id)
1055
1056
            self._set_root_id(file_id)
1056
1057
 
1057
1058
    def _set_root_id(self, file_id):
1074
1075
        """
1075
1076
        raise NotImplementedError(self.unlock)
1076
1077
 
1077
 
    _marker = object()
1078
 
 
1079
1078
    def update(self, change_reporter=None, possible_transports=None,
1080
 
               revision=None, old_tip=_marker, show_base=False):
 
1079
               revision=None, old_tip=None, show_base=False):
1081
1080
        """Update a working tree along its branch.
1082
1081
 
1083
1082
        This will update the branch if its bound too, which means we have
1109
1108
            returned (old tip of the branch or None). _marker is used
1110
1109
            otherwise.
1111
1110
        """
1112
 
        if self.branch.get_bound_location() is not None:
1113
 
            self.lock_write()
1114
 
            update_branch = (old_tip is self._marker)
1115
 
        else:
1116
 
            self.lock_tree_write()
1117
 
            update_branch = False
1118
 
        try:
1119
 
            if update_branch:
1120
 
                old_tip = self.branch.update(possible_transports)
1121
 
            else:
1122
 
                if old_tip is self._marker:
1123
 
                    old_tip = None
1124
 
            return self._update_tree(old_tip, change_reporter, revision, show_base)
1125
 
        finally:
1126
 
            self.unlock()
1127
 
 
1128
 
    def _update_tree(self, old_tip=None, change_reporter=None, revision=None,
1129
 
                     show_base=False):
1130
 
        """Update a tree to the master branch.
1131
 
 
1132
 
        :param old_tip: if supplied, the previous tip revision the branch,
1133
 
            before it was changed to the master branch's tip.
1134
 
        """
1135
 
        # here if old_tip is not None, it is the old tip of the branch before
1136
 
        # it was updated from the master branch. This should become a pending
1137
 
        # merge in the working tree to preserve the user existing work.  we
1138
 
        # cant set that until we update the working trees last revision to be
1139
 
        # one from the new branch, because it will just get absorbed by the
1140
 
        # parent de-duplication logic.
1141
 
        #
1142
 
        # We MUST save it even if an error occurs, because otherwise the users
1143
 
        # local work is unreferenced and will appear to have been lost.
1144
 
        #
1145
 
        with self.lock_tree_write():
1146
 
            nb_conflicts = 0
1147
 
            try:
1148
 
                last_rev = self.get_parent_ids()[0]
1149
 
            except IndexError:
1150
 
                last_rev = _mod_revision.NULL_REVISION
1151
 
            if revision is None:
1152
 
                revision = self.branch.last_revision()
1153
 
 
1154
 
            old_tip = old_tip or _mod_revision.NULL_REVISION
1155
 
 
1156
 
            if not _mod_revision.is_null(old_tip) and old_tip != last_rev:
1157
 
                # the branch we are bound to was updated
1158
 
                # merge those changes in first
1159
 
                base_tree = self.basis_tree()
1160
 
                other_tree = self.branch.repository.revision_tree(old_tip)
1161
 
                nb_conflicts = merge.merge_inner(self.branch, other_tree,
1162
 
                                                 base_tree, this_tree=self,
1163
 
                                                 change_reporter=change_reporter,
1164
 
                                                 show_base=show_base)
1165
 
                if nb_conflicts:
1166
 
                    self.add_parent_tree((old_tip, other_tree))
1167
 
                    note(gettext('Rerun update after fixing the conflicts.'))
1168
 
                    return nb_conflicts
1169
 
 
1170
 
            if last_rev != _mod_revision.ensure_null(revision):
1171
 
                # the working tree is up to date with the branch
1172
 
                # we can merge the specified revision from master
1173
 
                to_tree = self.branch.repository.revision_tree(revision)
1174
 
                to_root_id = to_tree.path2id('')
1175
 
 
1176
 
                basis = self.basis_tree()
1177
 
                with basis.lock_read():
1178
 
                    if (basis.path2id('') is None or basis.path2id('') != to_root_id):
1179
 
                        self.set_root_id(to_root_id)
1180
 
                        self.flush()
1181
 
 
1182
 
                # determine the branch point
1183
 
                graph = self.branch.repository.get_graph()
1184
 
                base_rev_id = graph.find_unique_lca(self.branch.last_revision(),
1185
 
                                                    last_rev)
1186
 
                base_tree = self.branch.repository.revision_tree(base_rev_id)
1187
 
 
1188
 
                nb_conflicts = merge.merge_inner(self.branch, to_tree, base_tree,
1189
 
                                                 this_tree=self,
1190
 
                                                 change_reporter=change_reporter,
1191
 
                                                 show_base=show_base)
1192
 
                self.set_last_revision(revision)
1193
 
                # TODO - dedup parents list with things merged by pull ?
1194
 
                # reuse the tree we've updated to to set the basis:
1195
 
                parent_trees = [(revision, to_tree)]
1196
 
                merges = self.get_parent_ids()[1:]
1197
 
                # Ideally we ask the tree for the trees here, that way the working
1198
 
                # tree can decide whether to give us the entire tree or give us a
1199
 
                # lazy initialised tree. dirstate for instance will have the trees
1200
 
                # in ram already, whereas a last-revision + basis-inventory tree
1201
 
                # will not, but also does not need them when setting parents.
1202
 
                for parent in merges:
1203
 
                    parent_trees.append(
1204
 
                        (parent, self.branch.repository.revision_tree(parent)))
1205
 
                if not _mod_revision.is_null(old_tip):
1206
 
                    parent_trees.append(
1207
 
                        (old_tip, self.branch.repository.revision_tree(old_tip)))
1208
 
                self.set_parent_trees(parent_trees)
1209
 
                last_rev = parent_trees[0][0]
1210
 
            return nb_conflicts
 
1111
        raise NotImplementedError(self.update)
1211
1112
 
1212
1113
    def set_conflicts(self, arg):
1213
1114
        raise errors.UnsupportedOperation(self.set_conflicts, self)
1222
1123
        """Walk the directories of this tree.
1223
1124
 
1224
1125
        returns a generator which yields items in the form:
1225
 
                ((curren_directory_path, fileid),
1226
 
                 [(file1_path, file1_name, file1_kind, (lstat), file1_id,
 
1126
                (current_directory_path,
 
1127
                 [(file1_path, file1_name, file1_kind, (lstat),
1227
1128
                   file1_kind), ... ])
1228
1129
 
1229
1130
        This API returns a generator, which is only valid during the current
1243
1144
        into files that have text conflicts.  The corresponding .THIS .BASE and
1244
1145
        .OTHER files are deleted, as per 'resolve'.
1245
1146
 
1246
 
        :return: a tuple of ConflictLists: (un_resolved, resolved).
 
1147
        :return: a tuple of lists: (un_resolved, resolved).
1247
1148
        """
1248
1149
        with self.lock_tree_write():
1249
 
            un_resolved = _mod_conflicts.ConflictList()
1250
 
            resolved = _mod_conflicts.ConflictList()
 
1150
            un_resolved = []
 
1151
            resolved = []
1251
1152
            for conflict in self.conflicts():
1252
1153
                try:
1253
1154
                    conflict.action_auto(self)