|
@@ -18,6 +18,7 @@
|
|
import os
|
|
import os
|
|
import re
|
|
import re
|
|
import shutil
|
|
import shutil
|
|
|
|
+from subprocess import CalledProcessError
|
|
import textwrap
|
|
import textwrap
|
|
from typing import Optional
|
|
from typing import Optional
|
|
|
|
|
|
@@ -26,6 +27,7 @@
|
|
|
|
|
|
|
|
|
|
__all__ = (
|
|
__all__ = (
|
|
|
|
+ 'VerboseProcessError',
|
|
'add_visual_margin',
|
|
'add_visual_margin',
|
|
'get_info_usernet_hostfwd_port',
|
|
'get_info_usernet_hostfwd_port',
|
|
'kvm_available',
|
|
'kvm_available',
|
|
@@ -121,3 +123,40 @@ def _wrap(line: str) -> str:
|
|
os.linesep.join(_wrap(line) for line in content.splitlines()),
|
|
os.linesep.join(_wrap(line) for line in content.splitlines()),
|
|
_bar(None, top=False),
|
|
_bar(None, top=False),
|
|
))
|
|
))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class VerboseProcessError(CalledProcessError):
|
|
|
|
+ """
|
|
|
|
+ The same as CalledProcessError, but more verbose.
|
|
|
|
+
|
|
|
|
+ This is useful for debugging failed calls during test executions.
|
|
|
|
+ The return code, signal (if any), and terminal output will be displayed
|
|
|
|
+ on unhandled exceptions.
|
|
|
|
+ """
|
|
|
|
+ def summary(self) -> str:
|
|
|
|
+ """Return the normal CalledProcessError str() output."""
|
|
|
|
+ return super().__str__()
|
|
|
|
+
|
|
|
|
+ def __str__(self) -> str:
|
|
|
|
+ lmargin = ' '
|
|
|
|
+ width = -len(lmargin)
|
|
|
|
+ sections = []
|
|
|
|
+
|
|
|
|
+ # Does self.stdout contain both stdout and stderr?
|
|
|
|
+ has_combined_output = self.stderr is None
|
|
|
|
+
|
|
|
|
+ name = 'output' if has_combined_output else 'stdout'
|
|
|
|
+ if self.stdout:
|
|
|
|
+ sections.append(add_visual_margin(self.stdout, width, name))
|
|
|
|
+ else:
|
|
|
|
+ sections.append(f"{name}: N/A")
|
|
|
|
+
|
|
|
|
+ if self.stderr:
|
|
|
|
+ sections.append(add_visual_margin(self.stderr, width, 'stderr'))
|
|
|
|
+ elif not has_combined_output:
|
|
|
|
+ sections.append("stderr: N/A")
|
|
|
|
+
|
|
|
|
+ return os.linesep.join((
|
|
|
|
+ self.summary(),
|
|
|
|
+ textwrap.indent(os.linesep.join(sections), prefix=lmargin),
|
|
|
|
+ ))
|