~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revision.py

  • Committer: Alexander Belchenko
  • Date: 2006-10-14 08:51:07 UTC
  • mto: (2080.1.1 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 2081.
  • Revision ID: bialix@ukr.net-20061014085107-8dff865674eed30a
win32 installer: make short info page instead of full GPL license text

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 Canonical
2
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
18
18
# perhaps show them in log -v and allow them as options to the commit command.
19
19
 
20
20
 
21
 
from bzrlib import (
22
 
    errors,
23
 
    symbol_versioning,
24
 
    )
25
 
from bzrlib.deprecated_graph import (
26
 
    all_descendants,
27
 
    Graph,
28
 
    node_distances,
29
 
    select_farthest,
30
 
    )
 
21
import bzrlib.errors as errors
 
22
from bzrlib.graph import node_distances, select_farthest, all_descendants, Graph
31
23
from bzrlib.osutils import contains_whitespace
32
24
from bzrlib.progress import DummyProgress
33
25
from bzrlib.symbol_versioning import (deprecated_function,
 
26
        zero_eight,
34
27
        )
35
28
 
36
29
NULL_REVISION="null:"
37
 
CURRENT_REVISION="current:"
38
30
 
39
31
 
40
32
class Revision(object):
114
106
    def get_summary(self):
115
107
        """Get the first line of the log message for this revision.
116
108
        """
117
 
        return self.message.lstrip().split('\n', 1)[0]
118
 
 
119
 
    def get_apparent_author(self):
120
 
        """Return the apparent author of this revision.
121
 
 
122
 
        If the revision properties contain the author name,
123
 
        return it. Otherwise return the committer name.
124
 
        """
125
 
        return self.properties.get('author', self.committer)
126
 
 
127
 
 
128
 
@deprecated_function(symbol_versioning.one_zero)
 
109
        return self.message.split('\n', 1)[0]
 
110
 
 
111
 
129
112
def is_ancestor(revision_id, candidate_id, branch):
130
113
    """Return true if candidate_id is an ancestor of revision_id.
131
114
 
134
117
    
135
118
    revisions_source is an object supporting a get_revision operation that
136
119
    behaves like Branch's.
137
 
 
138
 
    This function is deprecated, it is better for callers to directly use
139
 
    Graph.is_ancestor() (just watch out that the parameter order is switched)
140
120
    """
141
 
    return branch.repository.get_graph().is_ancestor(candidate_id, revision_id)
 
121
    return (candidate_id in branch.repository.get_ancestry(revision_id))
142
122
 
143
123
 
144
124
def iter_ancestors(revision_id, revision_source, only_present=False):
233
213
    return root, ancestors, descendants
234
214
 
235
215
 
236
 
@deprecated_function(symbol_versioning.one_three)
237
216
def combined_graph(revision_a, revision_b, revision_source):
238
217
    """Produce a combined ancestry graph.
239
218
    Return graph root, ancestors map, descendants map, set of common nodes"""
257
236
    return root, ancestors, descendants, common
258
237
 
259
238
 
260
 
@deprecated_function(symbol_versioning.one_three)
261
239
def common_ancestor(revision_a, revision_b, revision_source, 
262
240
                    pb=DummyProgress()):
263
241
    if None in (revision_a, revision_b):
272
250
            pb.update('Picking ancestor', 1, 3)
273
251
            graph = revision_source.get_revision_graph_with_ghosts(
274
252
                [revision_a, revision_b])
275
 
            # Shortcut the case where one of the tips is already included in
276
 
            # the other graphs ancestry.
277
 
            ancestry_a = graph.get_ancestry(revision_a, topo_sorted=False)
278
 
            if revision_b in ancestry_a:
279
 
                return revision_b
280
 
            ancestry_b = graph.get_ancestry(revision_b, topo_sorted=False)
281
 
            if revision_a in ancestry_b:
282
 
                return revision_a
283
253
            # convert to a NULL_REVISION based graph.
284
254
            ancestors = graph.get_ancestors()
285
255
            descendants = graph.get_descendants()
286
 
            common = set(ancestry_a)
287
 
            common.intersection_update(ancestry_b)
 
256
            common = set(graph.get_ancestry(revision_a)).intersection(
 
257
                     set(graph.get_ancestry(revision_b)))
288
258
            descendants[NULL_REVISION] = {}
289
259
            ancestors[NULL_REVISION] = []
290
260
            for root in graph.roots:
322
292
 
323
293
class MultipleRevisionSources(object):
324
294
    """Proxy that looks in multiple branches for revisions."""
325
 
 
326
 
    @symbol_versioning.deprecated_method(symbol_versioning.one_three)
327
295
    def __init__(self, *args):
328
296
        object.__init__(self)
329
297
        assert len(args) != 0
442
410
            source.unlock()
443
411
 
444
412
 
445
 
def is_reserved_id(revision_id):
446
 
    """Determine whether a revision id is reserved
 
413
@deprecated_function(zero_eight)
 
414
def get_intervening_revisions(ancestor_id, rev_id, rev_source,
 
415
                              revision_history=None):
 
416
    """Find the longest line of descent from maybe_ancestor to revision.
 
417
    Revision history is followed where possible.
447
418
 
448
 
    :return: True if the revision is is reserved, False otherwise
 
419
    If ancestor_id == rev_id, list will be empty.
 
420
    Otherwise, rev_id will be the last entry.  ancestor_id will never appear.
 
421
    If ancestor_id is not an ancestor, NotAncestor will be thrown
449
422
    """
450
 
    return isinstance(revision_id, basestring) and revision_id.endswith(':')
451
 
 
452
 
 
453
 
def check_not_reserved_id(revision_id):
454
 
    """Raise ReservedId if the supplied revision_id is reserved"""
455
 
    if is_reserved_id(revision_id):
456
 
        raise errors.ReservedId(revision_id)
457
 
 
458
 
 
459
 
def ensure_null(revision_id):
460
 
    """Ensure only NULL_REVISION is used to represent the null revision"""
461
 
    if revision_id is None:
462
 
        symbol_versioning.warn('NULL_REVISION should be used for the null'
463
 
            ' revision instead of None, as of bzr 0.91.',
464
 
            DeprecationWarning, stacklevel=2)
465
 
        return NULL_REVISION
466
 
    else:
467
 
        return revision_id
468
 
 
469
 
 
470
 
def is_null(revision_id):
471
 
    if revision_id is None:
472
 
        symbol_versioning.warn('NULL_REVISION should be used for the null'
473
 
            ' revision instead of None, as of bzr 0.90.',
474
 
            DeprecationWarning, stacklevel=2)
475
 
    return revision_id in (None, NULL_REVISION)
 
423
    root, ancestors, descendants = revision_graph(rev_id, rev_source)
 
424
    if len(descendants) == 0:
 
425
        raise errors.NoSuchRevision(rev_source, rev_id)
 
426
    if ancestor_id not in descendants:
 
427
        rev_source.get_revision(ancestor_id)
 
428
        raise errors.NotAncestor(rev_id, ancestor_id)
 
429
    root_descendants = all_descendants(descendants, ancestor_id)
 
430
    root_descendants.add(ancestor_id)
 
431
    if rev_id not in root_descendants:
 
432
        raise errors.NotAncestor(rev_id, ancestor_id)
 
433
    distances = node_distances(descendants, ancestors, ancestor_id,
 
434
                               root_descendants=root_descendants)
 
435
 
 
436
    def best_ancestor(rev_id):
 
437
        best = None
 
438
        for anc_id in ancestors[rev_id]:
 
439
            try:
 
440
                distance = distances[anc_id]
 
441
            except KeyError:
 
442
                continue
 
443
            if revision_history is not None and anc_id in revision_history:
 
444
                return anc_id
 
445
            elif best is None or distance > best[1]:
 
446
                best = (anc_id, distance)
 
447
        return best[0]
 
448
 
 
449
    next = rev_id
 
450
    path = []
 
451
    while next != ancestor_id:
 
452
        path.append(next)
 
453
        next = best_ancestor(next)
 
454
    path.reverse()
 
455
    return path