1
# Copyright (C) 2005-2011 Canonical Ltd
1
# Copyright (C) 2005-2010 Canonical Ltd
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
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
19
17
# TODO: Some kind of command-line display of revision properties:
20
18
# perhaps show them in log -v and allow them as options to the commit command.
23
from .lazy_import import lazy_import
21
from bzrlib.lazy_import import lazy_import
24
22
lazy_import(globals(), """
25
from breezy import bugtracker
23
from bzrlib import deprecated_graph
24
from bzrlib import bugtracker
30
from bzrlib.osutils import contains_whitespace
35
NULL_REVISION = b"null:"
36
CURRENT_REVISION = b"current:"
33
CURRENT_REVISION="current:"
39
36
class Revision(object):
74
71
if not isinstance(other, Revision):
77
self.inventory_sha1 == other.inventory_sha1
78
and self.revision_id == other.revision_id
79
and self.timestamp == other.timestamp
80
and self.message == other.message
81
and self.timezone == other.timezone
82
and self.committer == other.committer
83
and self.properties == other.properties
84
and self.parent_ids == other.parent_ids)
74
self.inventory_sha1 == other.inventory_sha1
75
and self.revision_id == other.revision_id
76
and self.timestamp == other.timestamp
77
and self.message == other.message
78
and self.timezone == other.timezone
79
and self.committer == other.committer
80
and self.properties == other.properties
81
and self.parent_ids == other.parent_ids)
86
83
def __ne__(self, other):
87
84
return not self.__eq__(other)
89
86
def _check_properties(self):
90
87
"""Verify that all revision properties are OK."""
91
for name, value in self.properties.items():
92
# GZ 2017-06-10: What sort of string are properties exactly?
93
not_text = not isinstance(name, (text_type, str))
94
if not_text or osutils.contains_whitespace(name):
88
for name, value in self.properties.iteritems():
89
if not isinstance(name, basestring) or contains_whitespace(name):
95
90
raise ValueError("invalid property name %r" % name)
96
if not isinstance(value, (text_type, bytes)):
91
if not isinstance(value, basestring):
97
92
raise ValueError("invalid property value %r for %r" %
107
102
reversed_result = []
108
103
while current_revision is not None:
109
104
reversed_result.append(current_revision.revision_id)
110
if not len(current_revision.parent_ids):
105
if not len (current_revision.parent_ids):
111
106
reversed_result.append(None)
112
107
current_revision = None
124
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((1, 13, 0)))
125
def get_apparent_author(self):
126
"""Return the apparent author of this revision.
128
This method is deprecated in favour of get_apparent_authors.
130
If the revision properties contain any author names,
131
return the first. Otherwise return the committer name.
133
authors = self.get_apparent_authors()
129
139
def get_apparent_authors(self):
130
140
"""Return the apparent authors of this revision.
147
157
"""Iterate over the bugs associated with this revision."""
148
158
bug_property = self.properties.get('bugs', None)
149
159
if bug_property is None:
151
return bugtracker.decode_bug_urls(bug_property)
161
for line in bug_property.splitlines():
163
url, status = line.split(None, 2)
165
raise errors.InvalidLineInBugsProperty(line)
166
if status not in bugtracker.ALLOWED_BUG_STATUSES:
167
raise errors.InvalidBugStatus(status)
154
171
def iter_ancestors(revision_id, revision_source, only_present=False):
161
178
yield ancestor, distance
163
180
revision = revision_source.get_revision(ancestor)
164
except errors.NoSuchRevision as e:
181
except errors.NoSuchRevision, e:
165
182
if e.revision == revision_id:
183
200
found_ancestors = {}
184
201
anc_iter = enumerate(iter_ancestors(revision_id, revision_source,
186
203
for anc_order, (anc_id, anc_distance) in anc_iter:
187
204
if anc_id not in found_ancestors:
188
205
found_ancestors[anc_id] = (anc_order, anc_distance)
204
221
:return: True if the revision is reserved, False otherwise
206
return isinstance(revision_id, bytes) and revision_id.endswith(b':')
223
return isinstance(revision_id, basestring) and revision_id.endswith(':')
209
226
def check_not_reserved_id(revision_id):
215
232
def ensure_null(revision_id):
216
233
"""Ensure only NULL_REVISION is used to represent the null revision"""
217
234
if revision_id is None:
219
'NULL_REVISION should be used for the null'
220
' revision instead of None.')
235
symbol_versioning.warn('NULL_REVISION should be used for the null'
236
' revision instead of None, as of bzr 0.91.',
237
DeprecationWarning, stacklevel=2)
224
243
def is_null(revision_id):
225
244
if revision_id is None:
226
raise ValueError('NULL_REVISION should be used for the null'
227
' revision instead of None.')
228
return (revision_id == NULL_REVISION)
245
symbol_versioning.warn('NULL_REVISION should be used for the null'
246
' revision instead of None, as of bzr 0.90.',
247
DeprecationWarning, stacklevel=2)
248
return revision_id in (None, NULL_REVISION)