From 9d3e4b9cd4dbe973b48aa7a774240edcea4bd1e2 Mon Sep 17 00:00:00 2001
From: Doug Hellmann <doug@doughellmann.com>
Date: Fri, 1 Nov 2024 14:57:59 -0400
Subject: [PATCH 1/2] do not show full traceback by default

Change the behavior of the main program to show
only the summary of an exception and not the full
traceback, by default. Add a `--debug` flag to
expose the traceback information for debugging, if
needed.
---
 src/fromager/__main__.py | 21 +++++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/src/fromager/__main__.py b/src/fromager/__main__.py
index c92af2d8..d545793b 100644
--- a/src/fromager/__main__.py
+++ b/src/fromager/__main__.py
@@ -18,6 +18,7 @@
 
 TERSE_LOG_FMT = "%(message)s"
 VERBOSE_LOG_FMT = "%(levelname)s:%(name)s:%(lineno)d: %(message)s"
+_DEBUG = False
 
 try:
     external_commands.detect_network_isolation()
@@ -37,6 +38,12 @@
     is_flag=True,
     help="report more detail to the console",
 )
+@click.option(
+    "--debug",
+    default=False,
+    is_flag=True,
+    help="report full tracebacks to the console",
+)
 @click.option(
     "--log-file",
     type=clickext.ClickPath(),
@@ -131,6 +138,7 @@
 def main(
     ctx: click.Context,
     verbose: bool,
+    debug: bool,
     log_file: pathlib.Path,
     error_log_file: pathlib.Path,
     sdists_repo: pathlib.Path,
@@ -146,6 +154,10 @@ def main(
     jobs: int | None,
     network_isolation: bool,
 ) -> None:
+    # Save the debug flag so invoke_main() can use it.
+    global _DEBUG
+    _DEBUG = debug
+
     # Set the overall logger level to debug and allow the handlers to filter
     # messages at their own level.
     logging.getLogger().setLevel(logging.DEBUG)
@@ -226,8 +238,13 @@ def invoke_main() -> None:
     try:
         main(auto_envvar_prefix="FROMAGER")
     except Exception as err:
-        logger.exception(err)
-        raise
+        logger.debug(
+            err,
+            exc_info=True,
+        )  # log the full traceback details to the debug log file, if any
+        logger.error(f"ERROR: {err}")
+        if _DEBUG:
+            raise
 
 
 if __name__ == "__main__":

From 14c4f9122ce3d6025c0eafabdcc8a490c7816343 Mon Sep 17 00:00:00 2001
From: Doug Hellmann <doug@doughellmann.com>
Date: Fri, 1 Nov 2024 14:58:58 -0400
Subject: [PATCH 2/2] improve the formatting of resolution errors

Use ValueError exceptions to provide a nicer
message for the resolver when it fails.
---
 src/fromager/resolver.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/fromager/resolver.py b/src/fromager/resolver.py
index bab57028..8a39f1e9 100644
--- a/src/fromager/resolver.py
+++ b/src/fromager/resolver.py
@@ -93,7 +93,10 @@ def resolve_from_provider(
 ) -> tuple[str, Version]:
     reporter: resolvelib.BaseReporter = resolvelib.BaseReporter()
     rslvr: resolvelib.Resolver = resolvelib.Resolver(provider, reporter)
-    result = rslvr.resolve([req])
+    try:
+        result = rslvr.resolve([req])
+    except resolvelib.resolvers.exceptions.ResolutionImpossible as err:
+        raise ValueError(f"Unable to resolve {req}") from err
     # resolvelib actually just returns one candidate per requirement.
     # result.mapping is map from an identifier to its resolved candidate
     candidate: Candidate