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.
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.
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
20
from xml import XMLMixin
23
from cElementTree import Element, ElementTree, SubElement
25
from elementtree.ElementTree import Element, ElementTree, SubElement
27
from errors import BzrError
30
class RevisionReference:
32
Reference to a stored revision.
34
Includes the revision_id and revision_sha1.
38
def __init__(self, revision_id, revision_sha1):
39
if revision_id == None \
40
or isinstance(revision_id, basestring):
41
self.revision_id = revision_id
43
raise ValueError('bad revision_id %r' % revision_id)
45
if revision_sha1 != None:
46
if isinstance(revision_sha1, basestring) \
47
and len(revision_sha1) == 40:
48
self.revision_sha1 = revision_sha1
50
raise ValueError('bad revision_sha1 %r' % revision_sha1)
54
class Revision(XMLMixin):
55
"""Single revision on a branch.
57
Revisions may know their revision_hash, but only once they've been
58
written out. This is not stored because you cannot write the hash
59
into the file it describes.
61
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
67
List of parent revisions, each is a RevisionReference.
77
def __init__(self, **args):
78
self.__dict__.update(args)
81
def _get_precursor(self):
82
from warnings import warn
83
warn("Revision.precursor is deprecated", stacklevel=2)
85
return self.parents[0].revision_id
90
def _get_precursor_sha1(self):
91
from warnings import warn
92
warn("Revision.precursor_sha1 is deprecated", stacklevel=2)
94
return self.parents[0].revision_sha1
100
raise Exception("can't assign to precursor anymore")
103
precursor = property(_get_precursor, _fail, _fail)
104
precursor_sha1 = property(_get_precursor_sha1, _fail, _fail)
109
return "<Revision id %s>" % self.revision_id
112
def to_element(self):
113
root = Element('revision',
114
committer = self.committer,
115
timestamp = '%.9f' % self.timestamp,
116
revision_id = self.revision_id,
117
inventory_id = self.inventory_id,
118
inventory_sha1 = self.inventory_sha1,
121
root.set('timezone', str(self.timezone))
124
msg = SubElement(root, 'message')
125
msg.text = self.message
129
# first parent stored as precursor for compatability with 0.0.5 and
132
root.set('precursor', pr.revision_id)
134
root.set('precursor_sha1', pr.revision_sha1)
137
pelts = SubElement(root, 'parents')
138
pelts.tail = pelts.text = '\n'
139
for rr in self.parents:
140
assert isinstance(rr, RevisionReference)
141
p = SubElement(pelts, 'revision_ref')
143
p.set('revision_id', rr.revision_id)
145
p.set('revision_sha1', rr.revision_sha1)
150
def from_element(cls, elt):
151
return unpack_revision(elt)
153
from_element = classmethod(from_element)
157
def unpack_revision(elt):
158
"""Convert XML element into Revision object."""
159
# <changeset> is deprecated...
160
if elt.tag not in ('revision', 'changeset'):
161
raise BzrError("unexpected tag in revision file: %r" % elt)
163
rev = Revision(committer = elt.get('committer'),
164
timestamp = float(elt.get('timestamp')),
165
revision_id = elt.get('revision_id'),
166
inventory_id = elt.get('inventory_id'),
167
inventory_sha1 = elt.get('inventory_sha1')
170
precursor = elt.get('precursor')
171
precursor_sha1 = elt.get('precursor_sha1')
173
pelts = elt.find('parents')
176
# revisions written prior to 0.0.5 have a single precursor
177
# give as an attribute
178
rev_ref = RevisionReference(precursor, precursor_sha1)
179
rev.parents.append(rev_ref)
182
assert p.tag == 'revision_ref', \
183
"bad parent node tag %r" % p.tag
184
rev_ref = RevisionReference(p.get('revision_id'),
185
p.get('revision_sha1'))
186
rev.parents.append(rev_ref)
188
v = elt.get('timezone')
189
rev.timezone = v and int(v)
191
rev.message = elt.findtext('message') # text of <message>