launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #29918
[Merge] ~pelpsi/lpci:launch-debug-shell-on-exception into lpci:main
Simone Pelosi has proposed merging ~pelpsi/lpci:launch-debug-shell-on-exception into lpci:main.
Commit message:
Added new debug shell
Launch debug shell on exception
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pelpsi/lpci/+git/lpcraft/+merge/441174
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pelpsi/lpci:launch-debug-shell-on-exception into lpci:main.
diff --git a/lpci/main.py b/lpci/main.py
index c84126d..3cb9222 100644
--- a/lpci/main.py
+++ b/lpci/main.py
@@ -4,6 +4,8 @@
"""Main entry point."""
import logging
+import pathlib
+import subprocess
import sys
from typing import List, Optional
@@ -35,6 +37,22 @@ def _configure_logger(name: str) -> None:
logger.setLevel(logging.DEBUG)
+def _launch_shell(
+ *, cwd: Optional[pathlib.Path] = None, error: Exception
+) -> None:
+ """Launch a user shell for debugging environment.
+
+ :param cwd: Working directory to start user in.
+ """
+ emit.progress(
+ "Launching debug shell on build environment...", permanent=True
+ )
+
+ emit.error(error)
+
+ subprocess.run(["bash"], check=False, cwd=cwd)
+
+
_configure_logger("craft_providers")
@@ -54,6 +72,7 @@ def main(argv: Optional[List[str]] = None) -> int:
if argv is None:
argv = sys.argv[1:]
+ debug_shell = False
emit.init(EmitterMode.BRIEF, "lpci", f"Starting {lpci_version}")
command_groups = [
CommandGroup("Basic", _basic_commands),
@@ -67,7 +86,14 @@ def main(argv: Optional[List[str]] = None) -> int:
"-V",
"--version",
"Show version information and exit",
- )
+ ),
+ GlobalArgument(
+ "debugshell",
+ "flag",
+ "-ds",
+ "--debug-shell",
+ "Shell into the environment if the run fails",
+ ),
]
# dispatcher = Dispatcher(
@@ -94,6 +120,8 @@ def main(argv: Optional[List[str]] = None) -> int:
default_command=RunCommand,
)
global_args = dispatcher.pre_parse_args(argv)
+ if global_args["debugshell"]:
+ debug_shell = True
if global_args["version"]:
emit.message(lpci_version)
emit.ended_ok()
@@ -109,7 +137,10 @@ def main(argv: Optional[List[str]] = None) -> int:
emit.ended_ok()
ret = 0
except CraftError as e:
- emit.error(e)
+ if debug_shell:
+ _launch_shell(error=e)
+ else:
+ emit.error(e)
ret = e.retcode
except KeyboardInterrupt as e:
error = CraftError("Interrupted.")
@@ -119,7 +150,10 @@ def main(argv: Optional[List[str]] = None) -> int:
except Exception as e:
error = CraftError(f"lpci internal error: {e!r}")
error.__cause__ = e
- emit.error(error)
+ if debug_shell:
+ _launch_shell(error=error)
+ else:
+ emit.error(error)
ret = 1
else:
emit.ended_ok()
diff --git a/lpci/tests/test_main.py b/lpci/tests/test_main.py
index b67da1e..025cc06 100644
--- a/lpci/tests/test_main.py
+++ b/lpci/tests/test_main.py
@@ -78,6 +78,52 @@ class TestMain(TestCase):
emitter.recorder.interactions[-1],
)
+ @patch("lpci.commands.run.RunCommand.run")
+ def test_debug_shell_mode_exception(self, mock_run):
+ self.useFixture(MockPatch("sys.argv", ["lpci", "--debug-shell"]))
+ mock_run.side_effect = RuntimeError()
+
+ with RecordingEmitterFixture() as emitter:
+ ret = main()
+
+ self.assertEqual(1, ret)
+ self.assertEqual(
+ call(
+ "progress",
+ "Launching debug shell on build environment...",
+ permanent=True,
+ ),
+ emitter.recorder.interactions[-2],
+ )
+ self.assertEqual(
+ call("error", CraftError("lpci internal error: RuntimeError()")),
+ emitter.recorder.interactions[-1],
+ )
+
+ @patch("lpci.commands.run.RunCommand.run")
+ def test_debug_shell_mode_craft_exception(self, mock_run):
+ self.useFixture(MockPatch("sys.argv", ["lpci", "--debug-shell"]))
+ mock_run.side_effect = CraftError(
+ "lpci internal error: RuntimeError()"
+ )
+
+ with RecordingEmitterFixture() as emitter:
+ ret = main()
+
+ self.assertEqual(1, ret)
+ self.assertEqual(
+ call(
+ "progress",
+ "Launching debug shell on build environment...",
+ permanent=True,
+ ),
+ emitter.recorder.interactions[-2],
+ )
+ self.assertEqual(
+ call("error", CraftError("lpci internal error: RuntimeError()")),
+ emitter.recorder.interactions[-1],
+ )
+
def test_quiet_mode(self):
# temporary test until cli API is set and a more meaningful test is
# possible