Merge ~pelpsi/lpci:launch-debug-shell-on-exception into lpci:main

Proposed by Simone Pelosi
Status: Merged
Approved by: Simone Pelosi
Approved revision: 5d43d6fb42436bf2c1ab750c77f00ea1d5279656
Merge reported by: Simone Pelosi
Merged at revision: 077250731711cc71404e2812b2dbdf3c294c2a2a
Proposed branch: ~pelpsi/lpci:launch-debug-shell-on-exception
Merge into: lpci:main
Diff against target: 186 lines (+97/-3)
4 files modified
NEWS.rst (+5/-0)
docs/cli-interface.rst (+9/-0)
lpci/main.py (+37/-3)
lpci/tests/test_main.py (+46/-0)
Reviewer Review Type Date Requested Status
Clinton Fung Approve
Colin Watson (community) Approve
Review via email: mp+441174@code.launchpad.net

Commit message

Added new debug shell

Launch debug shell on exception

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) wrote :

Looks good, thanks!

review: Approve
Revision history for this message
Clinton Fung (clinton-fung) wrote :

It would be good to update the docs with details of how to use this feature.

review: Approve
Revision history for this message
Simone Pelosi (pelpsi) wrote :

> It would be good to update the docs with details of how to use this feature.
Sure, thank you! I add the missing documentation and then I merge it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/NEWS.rst b/NEWS.rst
2index 0981660..f13f694 100644
3--- a/NEWS.rst
4+++ b/NEWS.rst
5@@ -2,6 +2,11 @@
6 Version history
7 ===============
8
9+0.1.1 (unreleased)
10+==================
11+
12+- Add a ``--debug-shell`` flag.
13+
14 0.1.0 (unreleased)
15 ==================
16
17diff --git a/docs/cli-interface.rst b/docs/cli-interface.rst
18index 5bee54b..1d6243f 100644
19--- a/docs/cli-interface.rst
20+++ b/docs/cli-interface.rst
21@@ -7,6 +7,15 @@ options.
22
23 Please run ``lpci --help`` to see all commands.
24
25+lpci global arguments
26+~~~~~~~~~~~~~~~~~~~~~~~
27+
28+- ``--debug-shell``, shell into the environment if the run fails, e.g.
29+ ``lpci run --debug-shell``
30+ ``lpci run-one --debug-shell``
31+ ``lpci release --debug-shell``
32+
33+
34 lpci run
35 --------
36
37diff --git a/lpci/main.py b/lpci/main.py
38index c84126d..3cb9222 100644
39--- a/lpci/main.py
40+++ b/lpci/main.py
41@@ -4,6 +4,8 @@
42 """Main entry point."""
43
44 import logging
45+import pathlib
46+import subprocess
47 import sys
48 from typing import List, Optional
49
50@@ -35,6 +37,22 @@ def _configure_logger(name: str) -> None:
51 logger.setLevel(logging.DEBUG)
52
53
54+def _launch_shell(
55+ *, cwd: Optional[pathlib.Path] = None, error: Exception
56+) -> None:
57+ """Launch a user shell for debugging environment.
58+
59+ :param cwd: Working directory to start user in.
60+ """
61+ emit.progress(
62+ "Launching debug shell on build environment...", permanent=True
63+ )
64+
65+ emit.error(error)
66+
67+ subprocess.run(["bash"], check=False, cwd=cwd)
68+
69+
70 _configure_logger("craft_providers")
71
72
73@@ -54,6 +72,7 @@ def main(argv: Optional[List[str]] = None) -> int:
74 if argv is None:
75 argv = sys.argv[1:]
76
77+ debug_shell = False
78 emit.init(EmitterMode.BRIEF, "lpci", f"Starting {lpci_version}")
79 command_groups = [
80 CommandGroup("Basic", _basic_commands),
81@@ -67,7 +86,14 @@ def main(argv: Optional[List[str]] = None) -> int:
82 "-V",
83 "--version",
84 "Show version information and exit",
85- )
86+ ),
87+ GlobalArgument(
88+ "debugshell",
89+ "flag",
90+ "-ds",
91+ "--debug-shell",
92+ "Shell into the environment if the run fails",
93+ ),
94 ]
95
96 # dispatcher = Dispatcher(
97@@ -94,6 +120,8 @@ def main(argv: Optional[List[str]] = None) -> int:
98 default_command=RunCommand,
99 )
100 global_args = dispatcher.pre_parse_args(argv)
101+ if global_args["debugshell"]:
102+ debug_shell = True
103 if global_args["version"]:
104 emit.message(lpci_version)
105 emit.ended_ok()
106@@ -109,7 +137,10 @@ def main(argv: Optional[List[str]] = None) -> int:
107 emit.ended_ok()
108 ret = 0
109 except CraftError as e:
110- emit.error(e)
111+ if debug_shell:
112+ _launch_shell(error=e)
113+ else:
114+ emit.error(e)
115 ret = e.retcode
116 except KeyboardInterrupt as e:
117 error = CraftError("Interrupted.")
118@@ -119,7 +150,10 @@ def main(argv: Optional[List[str]] = None) -> int:
119 except Exception as e:
120 error = CraftError(f"lpci internal error: {e!r}")
121 error.__cause__ = e
122- emit.error(error)
123+ if debug_shell:
124+ _launch_shell(error=error)
125+ else:
126+ emit.error(error)
127 ret = 1
128 else:
129 emit.ended_ok()
130diff --git a/lpci/tests/test_main.py b/lpci/tests/test_main.py
131index b67da1e..025cc06 100644
132--- a/lpci/tests/test_main.py
133+++ b/lpci/tests/test_main.py
134@@ -78,6 +78,52 @@ class TestMain(TestCase):
135 emitter.recorder.interactions[-1],
136 )
137
138+ @patch("lpci.commands.run.RunCommand.run")
139+ def test_debug_shell_mode_exception(self, mock_run):
140+ self.useFixture(MockPatch("sys.argv", ["lpci", "--debug-shell"]))
141+ mock_run.side_effect = RuntimeError()
142+
143+ with RecordingEmitterFixture() as emitter:
144+ ret = main()
145+
146+ self.assertEqual(1, ret)
147+ self.assertEqual(
148+ call(
149+ "progress",
150+ "Launching debug shell on build environment...",
151+ permanent=True,
152+ ),
153+ emitter.recorder.interactions[-2],
154+ )
155+ self.assertEqual(
156+ call("error", CraftError("lpci internal error: RuntimeError()")),
157+ emitter.recorder.interactions[-1],
158+ )
159+
160+ @patch("lpci.commands.run.RunCommand.run")
161+ def test_debug_shell_mode_craft_exception(self, mock_run):
162+ self.useFixture(MockPatch("sys.argv", ["lpci", "--debug-shell"]))
163+ mock_run.side_effect = CraftError(
164+ "lpci internal error: RuntimeError()"
165+ )
166+
167+ with RecordingEmitterFixture() as emitter:
168+ ret = main()
169+
170+ self.assertEqual(1, ret)
171+ self.assertEqual(
172+ call(
173+ "progress",
174+ "Launching debug shell on build environment...",
175+ permanent=True,
176+ ),
177+ emitter.recorder.interactions[-2],
178+ )
179+ self.assertEqual(
180+ call("error", CraftError("lpci internal error: RuntimeError()")),
181+ emitter.recorder.interactions[-1],
182+ )
183+
184 def test_quiet_mode(self):
185 # temporary test until cli API is set and a more meaningful test is
186 # possible

Subscribers

People subscribed via source and target branches