1
# Copyright (C) 2005-2011 Canonical Ltd
1
# Copyright (C) 2005, 2006 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
18
18
# perhaps show them in log -v and allow them as options to the commit command.
21
from .lazy_import import lazy_import
21
from bzrlib.lazy_import import lazy_import
22
22
lazy_import(globals(), """
23
from breezy import bugtracker
23
from bzrlib import deprecated_graph
24
from bzrlib import bugtracker
30
from bzrlib.osutils import contains_whitespace
31
from bzrlib.progress import DummyProgress
30
NULL_REVISION = b"null:"
31
CURRENT_REVISION = b"current:"
34
CURRENT_REVISION="current:"
34
37
class Revision(object):
52
55
def __init__(self, revision_id, properties=None, **args):
53
56
self.revision_id = revision_id
54
if properties is None:
57
self.properties = properties
58
self._check_properties()
57
self.properties = properties or {}
58
self._check_properties()
59
59
self.committer = None
60
60
self.parent_ids = []
61
61
self.parent_sha1s = []
69
69
if not isinstance(other, Revision):
72
self.inventory_sha1 == other.inventory_sha1
73
and self.revision_id == other.revision_id
74
and self.timestamp == other.timestamp
75
and self.message == other.message
76
and self.timezone == other.timezone
77
and self.committer == other.committer
78
and self.properties == other.properties
79
and self.parent_ids == other.parent_ids)
72
self.inventory_sha1 == other.inventory_sha1
73
and self.revision_id == other.revision_id
74
and self.timestamp == other.timestamp
75
and self.message == other.message
76
and self.timezone == other.timezone
77
and self.committer == other.committer
78
and self.properties == other.properties
79
and self.parent_ids == other.parent_ids)
81
81
def __ne__(self, other):
82
82
return not self.__eq__(other)
84
84
def _check_properties(self):
85
85
"""Verify that all revision properties are OK."""
86
for name, value in self.properties.items():
87
# GZ 2017-06-10: What sort of string are properties exactly?
88
not_text = not isinstance(name, str)
89
if not_text or osutils.contains_whitespace(name):
86
for name, value in self.properties.iteritems():
87
if not isinstance(name, basestring) or contains_whitespace(name):
90
88
raise ValueError("invalid property name %r" % name)
91
if not isinstance(value, (str, bytes)):
89
if not isinstance(value, basestring):
92
90
raise ValueError("invalid property value %r for %r" %
102
100
reversed_result = []
103
101
while current_revision is not None:
104
102
reversed_result.append(current_revision.revision_id)
105
if not len(current_revision.parent_ids):
103
if not len (current_revision.parent_ids):
106
104
reversed_result.append(None)
107
105
current_revision = None
122
@symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((1, 13, 0)))
123
def get_apparent_author(self):
124
"""Return the apparent author of this revision.
126
This method is deprecated in favour of get_apparent_authors.
128
If the revision properties contain any author names,
129
return the first. Otherwise return the committer name.
131
authors = self.get_apparent_authors()
124
137
def get_apparent_authors(self):
125
138
"""Return the apparent authors of this revision.
142
155
"""Iterate over the bugs associated with this revision."""
143
156
bug_property = self.properties.get('bugs', None)
144
157
if bug_property is None:
146
return bugtracker.decode_bug_urls(bug_property)
159
for line in bug_property.splitlines():
161
url, status = line.split(None, 2)
163
raise errors.InvalidLineInBugsProperty(line)
164
if status not in bugtracker.ALLOWED_BUG_STATUSES:
165
raise errors.InvalidBugStatus(status)
149
169
def iter_ancestors(revision_id, revision_source, only_present=False):
156
176
yield ancestor, distance
158
178
revision = revision_source.get_revision(ancestor)
159
except errors.NoSuchRevision as e:
179
except errors.NoSuchRevision, e:
160
180
if e.revision == revision_id:
178
198
found_ancestors = {}
179
199
anc_iter = enumerate(iter_ancestors(revision_id, revision_source,
181
201
for anc_order, (anc_id, anc_distance) in anc_iter:
182
202
if anc_id not in found_ancestors:
183
203
found_ancestors[anc_id] = (anc_order, anc_distance)
199
219
:return: True if the revision is reserved, False otherwise
201
return isinstance(revision_id, bytes) and revision_id.endswith(b':')
221
return isinstance(revision_id, basestring) and revision_id.endswith(':')
204
224
def check_not_reserved_id(revision_id):
210
230
def ensure_null(revision_id):
211
231
"""Ensure only NULL_REVISION is used to represent the null revision"""
212
232
if revision_id is None:
214
'NULL_REVISION should be used for the null'
215
' revision instead of None.')
233
symbol_versioning.warn('NULL_REVISION should be used for the null'
234
' revision instead of None, as of bzr 0.91.',
235
DeprecationWarning, stacklevel=2)
219
241
def is_null(revision_id):
220
242
if revision_id is None:
221
raise ValueError('NULL_REVISION should be used for the null'
222
' revision instead of None.')
223
return (revision_id == NULL_REVISION)
243
symbol_versioning.warn('NULL_REVISION should be used for the null'
244
' revision instead of None, as of bzr 0.90.',
245
DeprecationWarning, stacklevel=2)
246
return revision_id in (None, NULL_REVISION)