work on error messages

This commit is contained in:
Mike Bayer 2014-11-15 23:24:05 -05:00
parent 2f04fce871
commit 8ac4d0446e
5 changed files with 78 additions and 53 deletions

View File

@ -208,7 +208,7 @@ def heads(config, verbose=False):
script = ScriptDirectory.from_config(config)
for rev in script.get_revisions("heads"):
config.print_stdout(rev.cmd_format(verbose))
config.print_stdout(rev.cmd_format(verbose, short_head_status=False))
def branches(config):

View File

@ -12,6 +12,16 @@ class RevisionError(Exception):
pass
class RangeNotAncestorError(RevisionError):
def __init__(self, lower, upper):
self.lower = lower
self.upper = upper
super(RangeNotAncestorError, self).__init__(
"Revision %s is not an ancestor of revision %s" %
(lower or "base", upper or "base")
)
class MultipleHeads(RevisionError):
pass
@ -245,7 +255,8 @@ class RevisionMap(object):
if branch_rev:
revs = self.filter_for_lineage(revs, check_branch)
if not revs:
raise ResolutionError("No such revision '%s'" % resolved_id)
raise ResolutionError(
"No such revision or branch '%s'" % resolved_id)
elif len(revs) > 1:
raise ResolutionError(
"Multiple revisions start "
@ -440,14 +451,7 @@ class RevisionMap(object):
rev.revision for rev in self._get_descendant_nodes(lowers)
)
if not total_space:
raise RevisionError(
"Revision(s) %s is not an ancestor of revision(s) %s" % (
(", ".join(r.revision for r in lowers)
if lowers else "base"),
(", ".join(r.revision for r in uppers)
if uppers else "base")
)
)
raise RangeNotAncestorError(lower, upper)
branch_endpoints = set(
rev.revision for rev in

View File

@ -7,6 +7,8 @@ from . import compat
from . import revision
from . import migration
from contextlib import contextmanager
_sourceless_rev_file = re.compile(r'(?!__init__)(.*\.py)(c|o)?$')
_only_source_rev_file = re.compile(r'(?!__init__)(.*\.py)$')
_legacy_rev = re.compile(r'([a-f0-9]+)\.py$')
@ -85,6 +87,34 @@ class ScriptDirectory(object):
output_encoding=config.get_main_option("output_encoding", "utf-8")
)
@contextmanager
def _catch_revision_errors(
self,
ancestor=None, multiple_heads=None, start=None, end=None):
try:
yield
except revision.RangeNotAncestorError as rna:
if start is None:
start = rna.lower
if end is None:
end = rna.upper
if not ancestor:
ancestor = (
"Requested range %(start)s:%(end)s does not refer to "
"ancestor/descendant revisions along the same branch"
)
ancestor = ancestor % {"start": start, "end": end}
compat.raise_from_cause(util.CommandError(ancestor))
except revision.MultipleHeads:
if not multiple_heads:
multiple_heads = (
"Multiple head revisions are present; please "
"specify a specific target revision or specify 'heads' to "
"refer to all branch heads at once")
compat.raise_from_cause(util.CommandError(multiple_heads))
except revision.RevisionError as err:
compat.raise_from_cause(util.CommandError(err.message))
def walk_revisions(self, base="base", head="heads"):
"""Iterate through all revisions.
@ -100,14 +130,9 @@ class ScriptDirectory(object):
refer to the set of all head branches simultaneously.
"""
try:
with self._catch_revision_errors(start=base, end=head):
for rev in self.iterate_revisions(head, base):
yield rev
except revision.MultipleHeads:
raise util.CommandError(
"Revision '%s' corresponds to multiple revisions; "
"please specify 'heads' for all heads, or a specific "
"revision or branch" % head)
def get_revisions(self, id_):
"""Return the :class:`.Script` instance with the given rev identifier,
@ -133,17 +158,14 @@ class ScriptDirectory(object):
"""Convert a symbolic revision, i.e. 'head' or 'base', into
an actual revision number."""
try:
with self._catch_revision_errors(id_):
rev, branch_name = self.revision_map._resolve_revision_number(id_)
except revision.MultipleHeads:
raise util.CommandError(
"Revision %s corresponds to multiple revisions" % id_)
if not rev:
# convert () to None
return None
else:
if not rev:
# convert () to None
return None
else:
return rev[0]
return rev[0]
def iterate_revisions(self, upper, lower):
"""Iterate through script revisions, starting at the given
@ -178,14 +200,12 @@ class ScriptDirectory(object):
:meth:`.ScriptDirectory.get_heads`
"""
try:
return self.revision_map.get_current_head()
except revision.MultipleHeads:
raise util.CommandError(
with self._catch_revision_errors(multiple_heads=(
'The script directory has multiple heads (due to branching).'
'Please use get_heads(), or merge the branches using '
'alembic merge.'
)
)):
return self.revision_map.get_current_head()
def get_heads(self):
"""Return all "head" revisions as strings.
@ -210,7 +230,9 @@ class ScriptDirectory(object):
yield rev, dupe
def _upgrade_revs(self, destination, current_rev):
try:
with self._catch_revision_errors(
ancestor="Destination %(end)s is not a valid upgrade "
"target from current head(s)", end=destination):
revs = self.revision_map.iterate_revisions(
destination, current_rev, implicit_base=True)
return [
@ -220,11 +242,11 @@ class ScriptDirectory(object):
for script, new_branch
in self._flag_branch_changes(reversed(list(revs)))
]
except revision.RevisionError as err:
compat.raise_from_cause(util.CommandError(err.message))
def _downgrade_revs(self, destination, current_rev):
try:
with self._catch_revision_errors(
ancestor="Destination %(end)s is not a valid downgrade "
"target from current head(s)", end=destination):
revs = self.revision_map.iterate_revisions(
current_rev, destination)
return [
@ -233,8 +255,6 @@ class ScriptDirectory(object):
)
for script, delete_branch in self._flag_branch_changes(revs)
]
except revision.RevisionError as err:
compat.raise_from_cause(util.CommandError(err.message))
def run_env(self):
"""Run the script environment.
@ -298,13 +318,12 @@ class ScriptDirectory(object):
if head is None:
head = "head"
try:
with self._catch_revision_errors(multiple_heads=(
"Multiple heads are present; please specify the head "
"revision on which the new revision should be based, "
"or perform a merge."
)):
heads = self.revision_map.get_revisions(head)
except revision.MultipleHeads:
raise util.CommandError(
"Multiple heads are present; please specify the head "
"revision on which the new revision should be based, "
"or perform a merge.")
create_date = datetime.datetime.now()
path = self._rev_path(revid, message, create_date)
@ -430,11 +449,13 @@ class Script(revision.Revision):
" (mergepoint)" if self.is_merge_point else "",
)
def cmd_format(self, verbose):
def cmd_format(self, verbose, short_head_status=True):
if verbose:
return self.log_entry
else:
elif short_head_status:
return self._head_only()
else:
return self.revision
def _format_down_revision(self):
if not self.down_revision:

View File

@ -207,7 +207,7 @@ class NamedBranchTest(DownIterateTest):
def test_no_revision_exists(self):
assert_raises_message(
RevisionError,
"No such revision 'q'",
"No such revision or branch 'q'",
self.map.get_revision, "abranch@q"
)
@ -286,7 +286,7 @@ class MultipleBranchTest(DownIterateTest):
# db1cb1 is the descendant of b1
assert_raises_message(
RevisionError,
r"Revision\(s\) d1cb1 is not an ancestor of revision\(s\) b1",
r"Revision d1cb1 is not an ancestor of revision b1",
list,
self.map._iterate_revisions('b1', 'd1cb1')
)
@ -295,7 +295,7 @@ class MultipleBranchTest(DownIterateTest):
# nodes db2cb2 and b1 have no path to each other
assert_raises_message(
RevisionError,
r"Revision\(s\) b1 is not an ancestor of revision\(s\) d2cb2",
r"Revision b1 is not an ancestor of revision d2cb2",
list,
self.map._iterate_revisions('d2cb2', 'b1')
)
@ -303,14 +303,14 @@ class MultipleBranchTest(DownIterateTest):
def test_wrong_direction_to_base(self):
assert_raises_message(
RevisionError,
r"Revision\(s\) d1cb1 is not an ancestor of revision\(s\) base",
r"Revision d1cb1 is not an ancestor of revision base",
list,
self.map._iterate_revisions(None, 'd1cb1')
)
assert_raises_message(
RevisionError,
r"Revision\(s\) d1cb1 is not an ancestor of revision\(s\) base",
r"Revision d1cb1 is not an ancestor of revision base",
list,
self.map._iterate_revisions((), 'd1cb1')
)

View File

@ -121,8 +121,8 @@ class RevisionPathTest(TestBase):
a, b, c, d, e = self.a, self.b, self.c, self.d, self.e
assert_raises_message(
util.CommandError,
r"Revision\(s\) %s is not an ancestor "
"of revision\(s\) base" % b.revision,
r"Destination %s is not a valid downgrade "
"target from current head\(s\)" % b.revision[0:3],
self.env._downgrade_revs, b.revision[0:3], None
)
@ -131,8 +131,8 @@ class RevisionPathTest(TestBase):
assert_raises_message(
util.CommandError,
r"Revision\(s\) %s is not an ancestor "
"of revision\(s\) %s" % (c.revision, b.revision),
r"Destination %s is not a valid downgrade "
"target from current head\(s\)" % c.revision[0:4],
self.env._downgrade_revs, c.revision[0:4], b.revision
)