~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revision.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# (C) 2005 Canonical
2
 
 
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
# perhaps show them in log -v and allow them as options to the commit command.
19
19
 
20
20
 
21
 
import bzrlib.errors
22
21
import bzrlib.errors as errors
23
22
from bzrlib.graph import node_distances, select_farthest, all_descendants, Graph
24
23
from bzrlib.osutils import contains_whitespace
25
24
from bzrlib.progress import DummyProgress
26
 
from bzrlib.symbol_versioning import *
 
25
from bzrlib.symbol_versioning import (deprecated_function,
 
26
        zero_eight,
 
27
        )
27
28
 
28
29
NULL_REVISION="null:"
 
30
CURRENT_REVISION="current:"
 
31
 
29
32
 
30
33
class Revision(object):
31
34
    """Single revision on a branch.
74
77
        return not self.__eq__(other)
75
78
 
76
79
    def _check_properties(self):
77
 
        """Verify that all revision properties are OK.
78
 
        """
 
80
        """Verify that all revision properties are OK."""
79
81
        for name, value in self.properties.iteritems():
80
82
            if not isinstance(name, basestring) or contains_whitespace(name):
81
83
                raise ValueError("invalid property name %r" % name)
117
119
    revisions_source is an object supporting a get_revision operation that
118
120
    behaves like Branch's.
119
121
    """
120
 
    return candidate_id in branch.repository.get_ancestry(revision_id)
 
122
    return (candidate_id in branch.repository.get_ancestry(revision_id))
121
123
 
122
124
 
123
125
def iter_ancestors(revision_id, revision_source, only_present=False):
130
132
                yield ancestor, distance
131
133
            try:
132
134
                revision = revision_source.get_revision(ancestor)
133
 
            except bzrlib.errors.NoSuchRevision, e:
 
135
            except errors.NoSuchRevision, e:
134
136
                if e.revision == revision_id:
135
137
                    raise 
136
138
                else:
153
155
    anc_iter = enumerate(iter_ancestors(revision_id, revision_source,
154
156
                         only_present=True))
155
157
    for anc_order, (anc_id, anc_distance) in anc_iter:
156
 
        if not found_ancestors.has_key(anc_id):
 
158
        if anc_id not in found_ancestors:
157
159
            found_ancestors[anc_id] = (anc_order, anc_distance)
158
160
    return found_ancestors
159
161
    
220
222
    root_b, ancestors_b, descendants_b = revision_graph(
221
223
        revision_b, revision_source)
222
224
    if root != root_b:
223
 
        raise bzrlib.errors.NoCommonRoot(revision_a, revision_b)
 
225
        raise errors.NoCommonRoot(revision_a, revision_b)
224
226
    common = set()
225
227
    for node, node_anc in ancestors_b.iteritems():
226
228
        if node in ancestors:
239
241
                    pb=DummyProgress()):
240
242
    if None in (revision_a, revision_b):
241
243
        return None
 
244
    if NULL_REVISION in (revision_a, revision_b):
 
245
        return NULL_REVISION
242
246
    # trivial optimisation
243
247
    if revision_a == revision_b:
244
248
        return revision_a
247
251
            pb.update('Picking ancestor', 1, 3)
248
252
            graph = revision_source.get_revision_graph_with_ghosts(
249
253
                [revision_a, revision_b])
 
254
            # Shortcut the case where one of the tips is already included in
 
255
            # the other graphs ancestry.
 
256
            ancestry_a = graph.get_ancestry(revision_a)
 
257
            if revision_b in ancestry_a:
 
258
                return revision_b
 
259
            ancestry_b = graph.get_ancestry(revision_b)
 
260
            if revision_a in ancestry_b:
 
261
                return revision_a
250
262
            # convert to a NULL_REVISION based graph.
251
263
            ancestors = graph.get_ancestors()
252
264
            descendants = graph.get_descendants()
253
 
            common = set(graph.get_ancestry(revision_a)).intersection(
254
 
                     set(graph.get_ancestry(revision_b)))
 
265
            common = set(ancestry_a)
 
266
            common.intersection_update(ancestry_b)
255
267
            descendants[NULL_REVISION] = {}
256
268
            ancestors[NULL_REVISION] = []
257
269
            for root in graph.roots:
273
285
                
274
286
            root = NULL_REVISION
275
287
            common.add(NULL_REVISION)
276
 
        except bzrlib.errors.NoCommonRoot:
277
 
            raise bzrlib.errors.NoCommonAncestor(revision_a, revision_b)
 
288
        except errors.NoCommonRoot:
 
289
            raise errors.NoCommonAncestor(revision_a, revision_b)
278
290
            
279
291
        pb.update('Picking ancestor', 2, 3)
280
292
        distances = node_distances (descendants, ancestors, root)
281
293
        pb.update('Picking ancestor', 3, 2)
282
294
        farthest = select_farthest(distances, common)
283
295
        if farthest is None or farthest == NULL_REVISION:
284
 
            raise bzrlib.errors.NoCommonAncestor(revision_a, revision_b)
 
296
            raise errors.NoCommonAncestor(revision_a, revision_b)
285
297
    finally:
286
298
        pb.clear()
287
299
    return farthest
306
318
        for source in self._revision_sources:
307
319
            try:
308
320
                return source.get_revision(revision_id)
309
 
            except bzrlib.errors.NoSuchRevision, e:
 
321
            except errors.NoSuchRevision, e:
310
322
                pass
311
323
        raise e
312
324
 
419
431
    """
420
432
    root, ancestors, descendants = revision_graph(rev_id, rev_source)
421
433
    if len(descendants) == 0:
422
 
        raise NoSuchRevision(rev_source, rev_id)
 
434
        raise errors.NoSuchRevision(rev_source, rev_id)
423
435
    if ancestor_id not in descendants:
424
436
        rev_source.get_revision(ancestor_id)
425
 
        raise bzrlib.errors.NotAncestor(rev_id, ancestor_id)
 
437
        raise errors.NotAncestor(rev_id, ancestor_id)
426
438
    root_descendants = all_descendants(descendants, ancestor_id)
427
439
    root_descendants.add(ancestor_id)
428
440
    if rev_id not in root_descendants:
429
 
        raise bzrlib.errors.NotAncestor(rev_id, ancestor_id)
 
441
        raise errors.NotAncestor(rev_id, ancestor_id)
430
442
    distances = node_distances(descendants, ancestors, ancestor_id,
431
443
                               root_descendants=root_descendants)
432
444
 
450
462
        next = best_ancestor(next)
451
463
    path.reverse()
452
464
    return path
 
465
 
 
466
 
 
467
def is_reserved_id(revision_id):
 
468
    """Determine whether a revision id is reserved
 
469
 
 
470
    :return: True if the revision is is reserved, False otherwise
 
471
    """
 
472
    return isinstance(revision_id, basestring) and revision_id.endswith(':')
 
473
 
 
474
 
 
475
def check_not_reserved_id(revision_id):
 
476
    """Raise ReservedId if the supplied revision_id is reserved"""
 
477
    if is_reserved_id(revision_id):
 
478
        raise errors.ReservedId(revision_id)