launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #29916
[Merge] ~pelpsi/lpci:debug-shell-on-exception into lpci:main
Simone Pelosi has proposed merging ~pelpsi/lpci:debug-shell-on-exception into lpci:main.
Commit message:
Added new debug shell
Shell into the environment if the run fails.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~pelpsi/lpci/+git/lpcraft/+merge/441108
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~pelpsi/lpci:debug-shell-on-exception into lpci:main.
diff --git a/lpci/tests/test_main.py b/lpci/tests/test_main.py
index b67da1e..d35b58b 100644
--- a/lpci/tests/test_main.py
+++ b/lpci/tests/test_main.py
@@ -78,6 +78,30 @@ class TestMain(TestCase):
emitter.recorder.interactions[-1],
)
+ @patch("lpcraft.commands.run.RunCommand.run")
+ def test_debug_shell_mode(self, mock_run):
+ self.useFixture(MockPatch("sys.argv", ["lpcraft", "--debug-shell"]))
+ mock_run.side_effect = RuntimeError()
+
+ with RecordingEmitterFixture() as emitter:
+ ret = main()
+
+ self.assertEqual(1, ret)
+ self.assertEqual(
+ call(
+ "progress",
+ "Launching shell on build environment...",
+ permanent=True,
+ ),
+ emitter.recorder.interactions[-2],
+ )
+ self.assertEqual(
+ call(
+ "error", CraftError("lpcraft 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
diff --git a/lpcraft/main.py b/lpcraft/main.py
new file mode 100644
index 0000000..cffa6c4
--- /dev/null
+++ b/lpcraft/main.py
@@ -0,0 +1,166 @@
+<<<<<<< lpcraft/main.py
+=======
+# Copyright 2021 Canonical Ltd. This software is licensed under the
+# GNU General Public License version 3 (see the file LICENSE).
+
+"""Main entry point."""
+
+import logging
+import pathlib
+import subprocess
+import sys
+from typing import List, Optional
+
+from craft_cli import (
+ ArgumentParsingError,
+ CommandGroup,
+ CraftError,
+ Dispatcher,
+ EmitterMode,
+ GlobalArgument,
+ ProvideHelpException,
+ emit,
+)
+
+from lpcraft._version import version_description as lpcraft_version
+from lpcraft.commands.clean import CleanCommand
+from lpcraft.commands.release import ReleaseCommand
+from lpcraft.commands.run import RunCommand, RunOneCommand
+from lpcraft.commands.version import VersionCommand
+
+
+def _configure_logger(name: str) -> None:
+ """Configure a logger for use with craft-cli.
+
+ Setting up a library's logger in DEBUG level causes its content to be
+ grabbed by craft-cli's Emitter.
+ """
+ logger = logging.getLogger(name)
+ logger.setLevel(logging.DEBUG)
+
+
+def _launch_shell(*, cwd: Optional[pathlib.Path] = None) -> None:
+ """Launch a user shell for debugging environment.
+
+ :param cwd: Working directory to start user in.
+ """
+ emit.progress("Launching shell on build environment...", permanent=True)
+ with emit.pause():
+ subprocess.run(["bash"], check=False, cwd=cwd)
+
+
+_configure_logger("craft_providers")
+
+
+_basic_commands = [
+ CleanCommand,
+ RunCommand,
+ RunOneCommand,
+ VersionCommand,
+]
+_launchpad_commands = [
+ ReleaseCommand,
+]
+
+
+def main(argv: Optional[List[str]] = None) -> int:
+ """`lpcraft` runs Launchpad CI jobs."""
+ if argv is None:
+ argv = sys.argv[1:]
+ debug_shell = False
+ emit.init(EmitterMode.BRIEF, "lpcraft", f"Starting {lpcraft_version}")
+ command_groups = [
+ CommandGroup("Basic", _basic_commands),
+ CommandGroup("Launchpad", _launchpad_commands),
+ ]
+ summary = "Run Launchpad CI jobs."
+ extra_global_args = [
+ GlobalArgument(
+ "version",
+ "flag",
+ "-V",
+ "--version",
+ "Show version information and exit",
+ ),
+ GlobalArgument(
+ "debugshell",
+ "flag",
+ "-ds",
+ "--debug-shell",
+ "Shell into the environment if the build fails",
+ ),
+ ]
+
+ # dispatcher = Dispatcher(
+ # "lpcraft",
+ # command_groups,
+ # summary=summary,
+ # extra_global_args=extra_global_args,
+ # default_command=RunCommand,
+ # )
+ # global_args = dispatcher.pre_parse_args(argv)
+ # if global_args["version"]:
+ # emit.message(lpcraft_version)
+ # emit.ended_ok()
+ # return 0
+ # dispatcher.load_command(None)
+ # ret = dispatcher.run() or 0
+
+ try:
+ dispatcher = Dispatcher(
+ "lpcraft",
+ command_groups,
+ summary=summary,
+ extra_global_args=extra_global_args,
+ default_command=RunCommand,
+ )
+ global_args = dispatcher.pre_parse_args(argv)
+ if global_args["debugshell"]:
+ debug_shell = True
+ if global_args["version"]:
+ emit.message(lpcraft_version)
+ emit.ended_ok()
+ return 0
+ dispatcher.load_command(None)
+ ret = dispatcher.run() or 0
+ except ArgumentParsingError as e:
+ if debug_shell:
+ emit.progress(str(e), permanent=True)
+ _launch_shell()
+ print(e, file=sys.stderr)
+ emit.ended_ok()
+ ret = 1
+ except ProvideHelpException as e:
+ if debug_shell:
+ emit.progress(str(e), permanent=True)
+ _launch_shell()
+ print(e)
+ emit.ended_ok()
+ ret = 0
+ except CraftError as e:
+ if debug_shell:
+ emit.progress(str(e), permanent=True)
+ _launch_shell()
+ emit.error(e)
+ ret = e.retcode
+ except KeyboardInterrupt as e:
+ error = CraftError("Interrupted.")
+ error.__cause__ = e
+ if debug_shell:
+ emit.progress(str(e), permanent=True)
+ _launch_shell()
+ emit.error(error)
+ ret = 1
+ except Exception as e:
+ error = CraftError(f"lpcraft internal error: {e!r}")
+ error.__cause__ = e
+ if debug_shell:
+ emit.progress(str(e), permanent=True)
+ _launch_shell()
+ emit.error(error)
+ ret = 1
+ else:
+ emit.ended_ok()
+
+ return ret
+>>>>>>> lpcraft/main.py