/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.3 by John Arbash Meinel
Add (c) Canonical to files that Aaron has approved
1
# Copyright (C) 2005 Aaron Bentley, Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.14.3 by Aaron Bentley
Copied conflict lister in
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.14.3 by Aaron Bentley
Copied conflict lister in
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.14.3 by Aaron Bentley
Copied conflict lister in
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
16
1185.16.11 by Martin Pool
todo
17
# TODO: Move this into builtins
18
19
# TODO: 'bzr resolve' should accept a directory name and work from that 
20
# point down
21
1185.16.33 by Martin Pool
- move 'conflict' and 'resolved' from shipped plugin to regular builtins
22
import os
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
23
24
from bzrlib.lazy_import import lazy_import
25
lazy_import(globals(), """
1185.16.33 by Martin Pool
- move 'conflict' and 'resolved' from shipped plugin to regular builtins
26
import errno
27
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
28
from bzrlib import (
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
29
    builtins,
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
30
    commands,
31
    errors,
32
    osutils,
33
    rio,
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
34
    trace,
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
35
    )
36
""")
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
37
from bzrlib.option import Option
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
38
39
40
CONFLICT_SUFFIXES = ('.THIS', '.BASE', '.OTHER')
41
1185.14.3 by Aaron Bentley
Copied conflict lister in
42
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
43
class cmd_conflicts(commands.Command):
1185.14.3 by Aaron Bentley
Copied conflict lister in
44
    """List files with conflicts.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
45
46
    Merge will do its best to combine the changes in two branches, but there
47
    are some kinds of problems only a human can fix.  When it encounters those,
48
    it will mark a conflict.  A conflict means that you need to fix something,
49
    before you should commit.
50
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
51
    Conflicts normally are listed as short, human-readable messages.  If --text
52
    is supplied, the pathnames of files with text conflicts are listed,
53
    instead.  (This is useful for editing all files with text conflicts.)
54
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
55
    Use bzr resolve when you have fixed a problem.
56
57
    See also bzr resolve.
1185.14.3 by Aaron Bentley
Copied conflict lister in
58
    """
2598.1.1 by Martin Pool
Add test for and documentation of option style, fix up existing options to comply
59
    takes_options = [
60
            Option('text',
61
                   help='List paths of files with text conflicts.'),
62
        ]
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
63
64
    def run(self, text=False):
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
65
        from bzrlib.workingtree import WorkingTree
1534.10.9 by Aaron Bentley
Switched display functions to conflict_lines
66
        wt = WorkingTree.open_containing(u'.')[0]
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
67
        for conflict in wt.conflicts():
1551.9.8 by Aaron Bentley
Add --text parameter to conflicts
68
            if text:
69
                if conflict.typestring != 'text conflict':
70
                    continue
71
                self.outf.write(conflict.path + '\n')
72
            else:
73
                self.outf.write(str(conflict) + '\n')
1185.14.3 by Aaron Bentley
Copied conflict lister in
74
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
75
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
76
class cmd_resolve(commands.Command):
1185.14.3 by Aaron Bentley
Copied conflict lister in
77
    """Mark a conflict as resolved.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
78
79
    Merge will do its best to combine the changes in two branches, but there
80
    are some kinds of problems only a human can fix.  When it encounters those,
81
    it will mark a conflict.  A conflict means that you need to fix something,
82
    before you should commit.
83
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
84
    Once you have fixed a problem, use "bzr resolve" to automatically mark
85
    text conflicts as fixed, resolve FILE to mark a specific conflict as
86
    resolved, or "bzr resolve --all" to mark all conflicts as resolved.
1551.2.18 by Aaron Bentley
Updated docs to clarify conflict handling
87
88
    See also bzr conflicts.
1185.14.3 by Aaron Bentley
Copied conflict lister in
89
    """
1185.33.24 by Martin Pool
Add alias 'resolved'
90
    aliases = ['resolved']
1185.14.3 by Aaron Bentley
Copied conflict lister in
91
    takes_args = ['file*']
2598.1.2 by Martin Pool
Also check that option help ends in a period, and fix those that don't
92
    takes_options = [
93
            Option('all', help='Resolve all conflicts in this tree.'),
94
            ]
1185.14.3 by Aaron Bentley
Copied conflict lister in
95
    def run(self, file_list=None, all=False):
1534.10.6 by Aaron Bentley
Conflict serialization working for WorkingTree3
96
        from bzrlib.workingtree import WorkingTree
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
97
        if all:
98
            if file_list:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
99
                raise errors.BzrCommandError("If --all is specified,"
100
                                             " no FILE may be provided")
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
101
            tree = WorkingTree.open_containing('.')[0]
102
            resolve(tree)
1185.14.3 by Aaron Bentley
Copied conflict lister in
103
        else:
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
104
            tree, file_list = builtins.tree_files(file_list)
1652.1.3 by Martin Pool
Improved bzr resolve command line handling
105
            if file_list is None:
2120.7.3 by Aaron Bentley
Update resolve command to automatically mark conflicts as resolved
106
                un_resolved, resolved = tree.auto_resolve()
107
                if len(un_resolved) > 0:
108
                    trace.note('%d conflict(s) auto-resolved.', len(resolved))
109
                    trace.note('Remaining conflicts:')
110
                    for conflict in un_resolved:
111
                        trace.note(conflict)
112
                    return 1
113
                else:
114
                    trace.note('All conflicts resolved.')
115
                    return 0
116
            else:
2120.7.4 by Aaron Bentley
Fix normal resolve
117
                resolve(tree, file_list)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
118
119
3017.2.1 by Aaron Bentley
Revert now resolves conflicts recursively (#102739)
120
def resolve(tree, paths=None, ignore_misses=False, recursive=False):
1997.1.3 by Robert Collins
All WorkingTree methods which write to the tree, but not to the branch
121
    tree.lock_tree_write()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
122
    try:
1534.10.23 by Aaron Bentley
Removed conflicts_to_stanzas and stanzas_to_conflicts
123
        tree_conflicts = tree.conflicts()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
124
        if paths is None:
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
125
            new_conflicts = ConflictList()
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
126
            selected_conflicts = tree_conflicts
127
        else:
128
            new_conflicts, selected_conflicts = \
3017.2.1 by Aaron Bentley
Revert now resolves conflicts recursively (#102739)
129
                tree_conflicts.select_conflicts(tree, paths, ignore_misses,
130
                    recursive)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
131
        try:
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
132
            tree.set_conflicts(new_conflicts)
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
133
        except errors.UnsupportedOperation:
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
134
            pass
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
135
        selected_conflicts.remove_files(tree)
1534.10.10 by Aaron Bentley
Resolve uses the new stuff.
136
    finally:
137
        tree.unlock()
138
139
1185.35.1 by Aaron Bentley
Implemented conflicts.restore
140
def restore(filename):
141
    """\
142
    Restore a conflicted file to the state it was in before merging.
143
    Only text restoration supported at present.
144
    """
145
    conflicted = False
146
    try:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
147
        osutils.rename(filename + ".THIS", filename)
1185.35.1 by Aaron Bentley
Implemented conflicts.restore
148
        conflicted = True
149
    except OSError, e:
150
        if e.errno != errno.ENOENT:
151
            raise
152
    try:
153
        os.unlink(filename + ".BASE")
154
        conflicted = True
155
    except OSError, e:
156
        if e.errno != errno.ENOENT:
157
            raise
158
    try:
159
        os.unlink(filename + ".OTHER")
160
        conflicted = True
161
    except OSError, e:
162
        if e.errno != errno.ENOENT:
163
            raise
164
    if not conflicted:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
165
        raise errors.NotConflicted(filename)
1534.10.4 by Aaron Bentley
Implemented conflict serialization
166
167
1534.10.22 by Aaron Bentley
Got ConflictList implemented
168
class ConflictList(object):
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
169
    """List of conflicts.
170
171
    Typically obtained from WorkingTree.conflicts()
172
1534.10.22 by Aaron Bentley
Got ConflictList implemented
173
    Can be instantiated from stanzas or from Conflict subclasses.
174
    """
175
176
    def __init__(self, conflicts=None):
177
        object.__init__(self)
178
        if conflicts is None:
179
            self.__list = []
180
        else:
181
            self.__list = conflicts
182
1652.1.1 by Martin Pool
Fix 'bzr resolve' run from subdirectory
183
    def is_empty(self):
184
        return len(self.__list) == 0
185
1534.10.22 by Aaron Bentley
Got ConflictList implemented
186
    def __len__(self):
187
        return len(self.__list)
188
189
    def __iter__(self):
190
        return iter(self.__list)
191
192
    def __getitem__(self, key):
193
        return self.__list[key]
194
195
    def append(self, conflict):
196
        return self.__list.append(conflict)
197
198
    def __eq__(self, other_list):
199
        return list(self) == list(other_list)
200
201
    def __ne__(self, other_list):
202
        return not (self == other_list)
203
204
    def __repr__(self):
205
        return "ConflictList(%r)" % self.__list
206
207
    @staticmethod
208
    def from_stanzas(stanzas):
209
        """Produce a new ConflictList from an iterable of stanzas"""
210
        conflicts = ConflictList()
211
        for stanza in stanzas:
212
            conflicts.append(Conflict.factory(**stanza.as_dict()))
213
        return conflicts
214
215
    def to_stanzas(self):
216
        """Generator of stanzas"""
217
        for conflict in self:
218
            yield conflict.as_stanza()
219
            
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
220
    def to_strings(self):
221
        """Generate strings for the provided conflicts"""
222
        for conflict in self:
223
            yield str(conflict)
224
225
    def remove_files(self, tree):
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
226
        """Remove the THIS, BASE and OTHER files for listed conflicts"""
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
227
        for conflict in self:
228
            if not conflict.has_files:
229
                continue
230
            for suffix in CONFLICT_SUFFIXES:
231
                try:
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
232
                    osutils.delete_any(tree.abspath(conflict.path+suffix))
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
233
                except OSError, e:
234
                    if e.errno != errno.ENOENT:
235
                        raise
1534.10.21 by Aaron Bentley
Moved and renamed conflict functions
236
1551.15.58 by Aaron Bentley
Status honours selected paths for conflicts (#127606)
237
    def select_conflicts(self, tree, paths, ignore_misses=False,
238
                         recurse=False):
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
239
        """Select the conflicts associated with paths in a tree.
240
        
241
        File-ids are also used for this.
1551.7.10 by Aaron Bentley
Remerge doesn't clear unrelated conflicts
242
        :return: a pair of ConflictLists: (not_selected, selected)
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
243
        """
244
        path_set = set(paths)
245
        ids = {}
246
        selected_paths = set()
247
        new_conflicts = ConflictList()
248
        selected_conflicts = ConflictList()
249
        for path in paths:
250
            file_id = tree.path2id(path)
251
            if file_id is not None:
252
                ids[file_id] = path
253
254
        for conflict in self:
255
            selected = False
256
            for key in ('path', 'conflict_path'):
257
                cpath = getattr(conflict, key, None)
258
                if cpath is None:
259
                    continue
260
                if cpath in path_set:
261
                    selected = True
262
                    selected_paths.add(cpath)
1551.15.58 by Aaron Bentley
Status honours selected paths for conflicts (#127606)
263
                if recurse:
264
                    if osutils.is_inside_any(path_set, cpath):
265
                        selected = True
266
                        selected_paths.add(cpath)
267
1534.10.25 by Aaron Bentley
Move select_conflicts into ConflictList
268
            for key in ('file_id', 'conflict_file_id'):
269
                cfile_id = getattr(conflict, key, None)
270
                if cfile_id is None:
271
                    continue
272
                try:
273
                    cpath = ids[cfile_id]
274
                except KeyError:
275
                    continue
276
                selected = True
277
                selected_paths.add(cpath)
278
            if selected:
279
                selected_conflicts.append(conflict)
280
            else:
281
                new_conflicts.append(conflict)
282
        if ignore_misses is not True:
283
            for path in [p for p in paths if p not in selected_paths]:
284
                if not os.path.exists(tree.abspath(path)):
285
                    print "%s does not exist" % path
286
                else:
287
                    print "%s is not conflicted" % path
288
        return new_conflicts, selected_conflicts
289
290
 
1534.10.18 by Aaron Bentley
Defined all new Conflict types
291
class Conflict(object):
292
    """Base class for all types of conflict"""
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
293
294
    has_files = False
295
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
296
    def __init__(self, path, file_id=None):
1534.10.18 by Aaron Bentley
Defined all new Conflict types
297
        self.path = path
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
298
        # warn turned off, because the factory blindly transfers the Stanza
299
        # values to __init__ and Stanza is purely a Unicode api.
300
        self.file_id = osutils.safe_file_id(file_id, warn=False)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
301
302
    def as_stanza(self):
1996.3.33 by John Arbash Meinel
make bzrlib/conflicts.py lazy
303
        s = rio.Stanza(type=self.typestring, path=self.path)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
304
        if self.file_id is not None:
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
305
            # Stanza requires Unicode apis
306
            s.add('file_id', self.file_id.decode('utf8'))
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
307
        return s
308
1534.10.22 by Aaron Bentley
Got ConflictList implemented
309
    def _cmp_list(self):
310
        return [type(self), self.path, self.file_id]
311
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
312
    def __cmp__(self, other):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
313
        if getattr(other, "_cmp_list", None) is None:
314
            return -1
315
        return cmp(self._cmp_list(), other._cmp_list())
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
316
1551.7.11 by Aaron Bentley
Add WorkingTree.add_conflicts
317
    def __hash__(self):
318
        return hash((type(self), self.path, self.file_id))
319
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
320
    def __eq__(self, other):
321
        return self.__cmp__(other) == 0
322
323
    def __ne__(self, other):
324
        return not self.__eq__(other)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
325
1534.10.20 by Aaron Bentley
Got all tests passing
326
    def __str__(self):
327
        return self.format % self.__dict__
328
1534.10.22 by Aaron Bentley
Got ConflictList implemented
329
    def __repr__(self):
330
        rdict = dict(self.__dict__)
331
        rdict['class'] = self.__class__.__name__
332
        return self.rformat % rdict
333
1534.10.18 by Aaron Bentley
Defined all new Conflict types
334
    @staticmethod
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
335
    def factory(type, **kwargs):
1534.10.18 by Aaron Bentley
Defined all new Conflict types
336
        global ctype
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
337
        return ctype[type](**kwargs)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
338
1666.1.4 by Robert Collins
* 'Metadir' is now the default disk format. This improves behaviour in
339
    @staticmethod
340
    def sort_key(conflict):
341
        if conflict.path is not None:
342
            return conflict.path, conflict.typestring
343
        elif getattr(conflict, "conflict_path", None) is not None:
344
            return conflict.conflict_path, conflict.typestring
345
        else:
346
            return None, conflict.typestring
347
1534.10.18 by Aaron Bentley
Defined all new Conflict types
348
349
class PathConflict(Conflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
350
    """A conflict was encountered merging file paths"""
351
1534.10.18 by Aaron Bentley
Defined all new Conflict types
352
    typestring = 'path conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
353
1534.10.20 by Aaron Bentley
Got all tests passing
354
    format = 'Path conflict: %(path)s / %(conflict_path)s'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
355
356
    rformat = '%(class)s(%(path)r, %(conflict_path)r, %(file_id)r)'
1534.10.20 by Aaron Bentley
Got all tests passing
357
    def __init__(self, path, conflict_path=None, file_id=None):
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
358
        Conflict.__init__(self, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
359
        self.conflict_path = conflict_path
360
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
361
    def as_stanza(self):
362
        s = Conflict.as_stanza(self)
1534.10.20 by Aaron Bentley
Got all tests passing
363
        if self.conflict_path is not None:
364
            s.add('conflict_path', self.conflict_path)
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
365
        return s
366
1534.10.20 by Aaron Bentley
Got all tests passing
367
368
class ContentsConflict(PathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
369
    """The files are of different types, or not present"""
370
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
371
    has_files = True
372
1534.10.20 by Aaron Bentley
Got all tests passing
373
    typestring = 'contents conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
374
1534.10.20 by Aaron Bentley
Got all tests passing
375
    format = 'Contents conflict in %(path)s'
376
377
378
class TextConflict(PathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
379
    """The merge algorithm could not resolve all differences encountered."""
380
1534.10.24 by Aaron Bentley
Eliminated conflicts_to_strings, made remove_files a ConflictList member
381
    has_files = True
382
1534.10.20 by Aaron Bentley
Got all tests passing
383
    typestring = 'text conflict'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
384
1534.10.20 by Aaron Bentley
Got all tests passing
385
    format = 'Text conflict in %(path)s'
386
387
1534.10.18 by Aaron Bentley
Defined all new Conflict types
388
class HandledConflict(Conflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
389
    """A path problem that has been provisionally resolved.
390
    This is intended to be a base class.
391
    """
392
393
    rformat = "%(class)s(%(action)r, %(path)r, %(file_id)r)"
394
    
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
395
    def __init__(self, action, path, file_id=None):
396
        Conflict.__init__(self, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
397
        self.action = action
398
1534.10.22 by Aaron Bentley
Got ConflictList implemented
399
    def _cmp_list(self):
400
        return Conflict._cmp_list(self) + [self.action]
401
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
402
    def as_stanza(self):
403
        s = Conflict.as_stanza(self)
404
        s.add('action', self.action)
405
        return s
406
1534.10.20 by Aaron Bentley
Got all tests passing
407
1534.10.18 by Aaron Bentley
Defined all new Conflict types
408
class HandledPathConflict(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
409
    """A provisionally-resolved path problem involving two paths.
410
    This is intended to be a base class.
411
    """
412
413
    rformat = "%(class)s(%(action)r, %(path)r, %(conflict_path)r,"\
414
        " %(file_id)r, %(conflict_file_id)r)"
415
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
416
    def __init__(self, action, path, conflict_path, file_id=None,
1534.10.18 by Aaron Bentley
Defined all new Conflict types
417
                 conflict_file_id=None):
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
418
        HandledConflict.__init__(self, action, path, file_id)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
419
        self.conflict_path = conflict_path 
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
420
        # warn turned off, because the factory blindly transfers the Stanza
421
        # values to __init__.
422
        self.conflict_file_id = osutils.safe_file_id(conflict_file_id,
423
                                                     warn=False)
1534.10.18 by Aaron Bentley
Defined all new Conflict types
424
        
1534.10.22 by Aaron Bentley
Got ConflictList implemented
425
    def _cmp_list(self):
426
        return HandledConflict._cmp_list(self) + [self.conflict_path, 
427
                                                  self.conflict_file_id]
428
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
429
    def as_stanza(self):
430
        s = HandledConflict.as_stanza(self)
431
        s.add('conflict_path', self.conflict_path)
432
        if self.conflict_file_id is not None:
2309.4.13 by John Arbash Meinel
Conflicts go through Stanza so the need to be aware of utf8 versus unicode file ids.
433
            s.add('conflict_file_id', self.conflict_file_id.decode('utf8'))
1534.10.19 by Aaron Bentley
Stanza conversion, cooking
434
            
435
        return s
1534.10.20 by Aaron Bentley
Got all tests passing
436
437
1534.10.18 by Aaron Bentley
Defined all new Conflict types
438
class DuplicateID(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
439
    """Two files want the same file_id."""
440
1534.10.18 by Aaron Bentley
Defined all new Conflict types
441
    typestring = 'duplicate id'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
442
1534.10.20 by Aaron Bentley
Got all tests passing
443
    format = 'Conflict adding id to %(conflict_path)s.  %(action)s %(path)s.'
444
1534.10.18 by Aaron Bentley
Defined all new Conflict types
445
446
class DuplicateEntry(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
447
    """Two directory entries want to have the same name."""
448
1534.10.18 by Aaron Bentley
Defined all new Conflict types
449
    typestring = 'duplicate'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
450
1534.10.20 by Aaron Bentley
Got all tests passing
451
    format = 'Conflict adding file %(conflict_path)s.  %(action)s %(path)s.'
452
1534.10.18 by Aaron Bentley
Defined all new Conflict types
453
454
class ParentLoop(HandledPathConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
455
    """An attempt to create an infinitely-looping directory structure.
456
    This is rare, but can be produced like so:
457
458
    tree A:
459
      mv foo/bar
460
    tree B:
461
      mv bar/foo
462
    merge A and B
463
    """
464
1534.10.18 by Aaron Bentley
Defined all new Conflict types
465
    typestring = 'parent loop'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
466
1534.10.20 by Aaron Bentley
Got all tests passing
467
    format = 'Conflict moving %(conflict_path)s into %(path)s.  %(action)s.'
468
1534.10.18 by Aaron Bentley
Defined all new Conflict types
469
470
class UnversionedParent(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
471
    """An attempt to version an file whose parent directory is not versioned.
472
    Typically, the result of a merge where one tree unversioned the directory
473
    and the other added a versioned file to it.
474
    """
475
1534.10.18 by Aaron Bentley
Defined all new Conflict types
476
    typestring = 'unversioned parent'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
477
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
478
    format = 'Conflict because %(path)s is not versioned, but has versioned'\
479
             ' children.  %(action)s.'
1534.10.20 by Aaron Bentley
Got all tests passing
480
1534.10.18 by Aaron Bentley
Defined all new Conflict types
481
482
class MissingParent(HandledConflict):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
483
    """An attempt to add files to a directory that is not present.
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
484
    Typically, the result of a merge where THIS deleted the directory and
485
    the OTHER added a file to it.
486
    See also: DeletingParent (same situation, reversed THIS and OTHER)
1534.10.22 by Aaron Bentley
Got ConflictList implemented
487
    """
488
1534.10.18 by Aaron Bentley
Defined all new Conflict types
489
    typestring = 'missing parent'
1534.10.22 by Aaron Bentley
Got ConflictList implemented
490
1534.10.20 by Aaron Bentley
Got all tests passing
491
    format = 'Conflict adding files to %(path)s.  %(action)s.'
492
493
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
494
class DeletingParent(HandledConflict):
495
    """An attempt to add files to a directory that is not present.
496
    Typically, the result of a merge where one OTHER deleted the directory and
497
    the THIS added a file to it.
498
    """
499
500
    typestring = 'deleting parent'
501
1551.8.23 by Aaron Bentley
Tweaked conflict message to be more understandable
502
    format = "Conflict: can't delete %(path)s because it is not empty.  "\
503
             "%(action)s."
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
504
1534.10.18 by Aaron Bentley
Defined all new Conflict types
505
506
ctype = {}
1534.10.20 by Aaron Bentley
Got all tests passing
507
508
1534.10.18 by Aaron Bentley
Defined all new Conflict types
509
def register_types(*conflict_types):
510
    """Register a Conflict subclass for serialization purposes"""
511
    global ctype
512
    for conflict_type in conflict_types:
513
        ctype[conflict_type.typestring] = conflict_type
514
1534.10.20 by Aaron Bentley
Got all tests passing
515
1534.10.18 by Aaron Bentley
Defined all new Conflict types
516
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
1551.8.22 by Aaron Bentley
Improve message when OTHER deletes an in-use tree
517
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
518
               DeletingParent,)