~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/revision.py

  • Committer: aaron.bentley at utoronto
  • Date: 2005-08-19 12:06:01 UTC
  • mto: (1092.1.41) (1185.3.4) (974.1.47)
  • mto: This revision was merged to the branch mainline in revision 1110.
  • Revision ID: aaron.bentley@utoronto.ca-20050819120601-58525b75283a9c1c
Initial greedy fetch work

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
 
 
19
 
 
20
 
from xml import XMLMixin
21
 
 
22
 
try:
23
 
    from cElementTree import Element, ElementTree, SubElement
24
 
except ImportError:
25
 
    from elementtree.ElementTree import Element, ElementTree, SubElement
26
 
 
27
 
from errors import BzrError
28
 
 
29
 
 
30
 
class RevisionReference:
 
18
import bzrlib.errors
 
19
 
 
20
 
 
21
class RevisionReference(object):
31
22
    """
32
23
    Reference to a stored revision.
33
24
 
35
26
    """
36
27
    revision_id = None
37
28
    revision_sha1 = None
38
 
    def __init__(self, revision_id, revision_sha1):
 
29
    def __init__(self, revision_id, revision_sha1=None):
39
30
        if revision_id == None \
40
31
           or isinstance(revision_id, basestring):
41
32
            self.revision_id = revision_id
51
42
                
52
43
 
53
44
 
54
 
class Revision(XMLMixin):
 
45
class Revision(object):
55
46
    """Single revision on a branch.
56
47
 
57
48
    Revisions may know their revision_hash, but only once they've been
59
50
    into the file it describes.
60
51
 
61
52
    After bzr 0.0.5 revisions are allowed to have multiple parents.
62
 
    To support old clients this is written out in a slightly redundant
63
 
    form: the first parent as the predecessor.  This will eventually
64
 
    be dropped.
65
53
 
66
54
    parents
67
55
        List of parent revisions, each is a RevisionReference.
78
66
        self.__dict__.update(args)
79
67
        self.parents = []
80
68
 
81
 
    def _get_precursor(self):
82
 
        from warnings import warn
83
 
        warn("Revision.precursor is deprecated", stacklevel=2)
84
 
        if self.parents:
85
 
            return self.parents[0].revision_id
86
 
        else:
87
 
            return None
88
 
 
89
 
 
90
 
    def _get_precursor_sha1(self):
91
 
        from warnings import warn
92
 
        warn("Revision.precursor_sha1 is deprecated", stacklevel=2)
93
 
        if self.parents:
94
 
            return self.parents[0].revision_sha1
95
 
        else:
96
 
            return None    
97
 
 
98
 
 
99
 
    def _fail(self):
100
 
        raise Exception("can't assign to precursor anymore")
101
 
 
102
 
 
103
 
    precursor = property(_get_precursor, _fail, _fail)
104
 
    precursor_sha1 = property(_get_precursor_sha1, _fail, _fail)
105
 
 
106
 
 
107
69
 
108
70
    def __repr__(self):
109
71
        return "<Revision id %s>" % self.revision_id
110
72
 
111
73
        
112
74
    def to_element(self):
 
75
        from bzrlib.xml import Element, SubElement
 
76
        
113
77
        root = Element('revision',
114
78
                       committer = self.committer,
115
79
                       timestamp = '%.9f' % self.timestamp,
126
90
        msg.tail = '\n'
127
91
 
128
92
        if self.parents:
129
 
            # first parent stored as precursor for compatability with 0.0.5 and
130
 
            # earlier
131
 
            pr = self.parents[0]
132
 
            assert pr.revision_id
133
 
            root.set('precursor', pr.revision_id)
134
 
            if pr.revision_sha1:
135
 
                root.set('precursor_sha1', pr.revision_sha1)
136
 
                
137
 
        if self.parents:
138
93
            pelts = SubElement(root, 'parents')
139
94
            pelts.tail = pelts.text = '\n'
140
95
            for rr in self.parents:
160
115
    """Convert XML element into Revision object."""
161
116
    # <changeset> is deprecated...
162
117
    if elt.tag not in ('revision', 'changeset'):
163
 
        raise BzrError("unexpected tag in revision file: %r" % elt)
 
118
        raise bzrlib.errors.BzrError("unexpected tag in revision file: %r" % elt)
164
119
 
165
120
    rev = Revision(committer = elt.get('committer'),
166
121
                   timestamp = float(elt.get('timestamp')),
174
129
 
175
130
    pelts = elt.find('parents')
176
131
 
177
 
    if precursor:
178
 
        # revisions written prior to 0.0.5 have a single precursor
179
 
        # give as an attribute
180
 
        rev_ref = RevisionReference(precursor, precursor_sha1)
181
 
        rev.parents.append(rev_ref)
182
 
    elif pelts:
 
132
    if pelts:
183
133
        for p in pelts:
184
134
            assert p.tag == 'revision_ref', \
185
135
                   "bad parent node tag %r" % p.tag
187
137
                                        p.get('revision_sha1'))
188
138
            rev.parents.append(rev_ref)
189
139
 
 
140
        if precursor:
 
141
            # must be consistent
 
142
            prec_parent = rev.parents[0].revision_id
 
143
            assert prec_parent == precursor
 
144
    elif precursor:
 
145
        # revisions written prior to 0.0.5 have a single precursor
 
146
        # give as an attribute
 
147
        rev_ref = RevisionReference(precursor, precursor_sha1)
 
148
        rev.parents.append(rev_ref)
 
149
 
190
150
    v = elt.get('timezone')
191
151
    rev.timezone = v and int(v)
192
152
 
193
153
    rev.message = elt.findtext('message') # text of <message>
194
154
    return rev
 
155
 
 
156
 
 
157
 
 
158
REVISION_ID_RE = None
 
159
 
 
160
def validate_revision_id(rid):
 
161
    """Check rid is syntactically valid for a revision id."""
 
162
    global REVISION_ID_RE
 
163
    if not REVISION_ID_RE:
 
164
        import re
 
165
        REVISION_ID_RE = re.compile('[\w.-]+@[\w.-]+--?\d+--?[0-9a-f]+\Z')
 
166
 
 
167
    if not REVISION_ID_RE.match(rid):
 
168
        raise ValueError("malformed revision-id %r" % rid)
 
169
 
 
170
def is_ancestor(revision_id, candidate_id, revision_source):
 
171
    """Return true if candidate_id is an ancestor of revision_id.
 
172
    A false negative will be returned if any intermediate descendent of
 
173
    candidate_id is not present in any of the revision_sources.
 
174
    
 
175
    revisions_source is an object supporting a get_revision operation that
 
176
    behaves like Branch's.
 
177
    """
 
178
 
 
179
    ancestors = (revision_id,)
 
180
    while len(ancestors) > 0:
 
181
        new_ancestors = []
 
182
        for ancestor in ancestors:
 
183
            if ancestor == candidate_id:
 
184
                return True
 
185
            try:
 
186
                revision = revision_source.get_revision(ancestor)
 
187
            except bzrlib.errors.NoSuchRevision, e:
 
188
                if e.revision == revision_id:
 
189
                    raise 
 
190
                else:
 
191
                    continue
 
192
            new_ancestors.extend([p.revision_id for p in revision.parents])
 
193
        ancestors = new_ancestors
 
194
 
 
195
 
 
196
class MultipleRevisionSources(object):
 
197
    def __init__(self, *args):
 
198
        object.__init__(self)
 
199
        assert len(args) != 0
 
200
        self._revision_sources = args
 
201
 
 
202
    def get_revision(self, revision_id):
 
203
        for source in self._revision_sources:
 
204
            try:
 
205
                return source.get_revision(revision_id)
 
206
            except bzrlib.errors.NoSuchRevision, e:
 
207
                pass
 
208
        raise e