main: Fix exitcode logging

Fixed a couple of bugs in ExitEvent logging:
- log exitcode 130 on KeyboardInterrupt
- log exitcode 1 on unhandled Exception
- log errorevent with specific reason for exit

Before this CL an exitcode of 0 would be logged, and it would be
difficult to determine the cause of non-zero exit codes

Bug: b/287105597
Change-Id: I2d34f180581f9fbd77a1c78c966ebed065223af6
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/377834
Tested-by: Jason Chang <jasonnc@google.com>
Reviewed-by: Josip Sokcevic <sokcevic@google.com>
diff --git a/main.py b/main.py
index 6dcb66f..90aba14 100755
--- a/main.py
+++ b/main.py
@@ -25,6 +25,7 @@
 import optparse
 import os
 import shlex
+import signal
 import sys
 import textwrap
 import time
@@ -95,6 +96,7 @@
             file=sys.stderr,
         )
 
+KEYBOARD_INTERRUPT_EXIT = 128 + signal.SIGINT
 
 global_options = optparse.OptionParser(
     usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]",
@@ -374,7 +376,11 @@
         git_trace2_event_log.StartEvent()
         git_trace2_event_log.CommandEvent(name="repo", subcommands=[name])
 
-        try:
+        def execute_command_helper():
+            """
+            Execute the subcommand.
+            """
+            nonlocal result
             cmd.CommonValidateOptions(copts, cargs)
             cmd.ValidateOptions(copts, cargs)
 
@@ -409,6 +415,23 @@
                     if hasattr(copts, "manifest_branch"):
                         child_argv.extend(["--manifest-branch", spec.revision])
                     result = self._Run(name, gopts, child_argv) or result
+
+        def execute_command():
+            """
+            Execute the command and log uncaught exceptions.
+            """
+            try:
+                execute_command_helper()
+            except (KeyboardInterrupt, SystemExit, Exception) as e:
+                ok = isinstance(e, SystemExit) and not e.code
+                if not ok:
+                    exception_name = type(e).__name__
+                    git_trace2_event_log.ErrorEvent(
+                        f"RepoExitError:{exception_name}")
+                raise
+
+        try:
+            execute_command()
         except (
             DownloadError,
             ManifestInvalidRevisionError,
@@ -448,6 +471,12 @@
             if e.code:
                 result = e.code
             raise
+        except KeyboardInterrupt:
+            result = KEYBOARD_INTERRUPT_EXIT
+            raise
+        except Exception:
+            result = 1
+            raise
         finally:
             finish = time.time()
             elapsed = finish - start
@@ -813,7 +842,7 @@
         result = repo._Run(name, gopts, argv) or 0
     except KeyboardInterrupt:
         print("aborted by user", file=sys.stderr)
-        result = 1
+        result = KEYBOARD_INTERRUPT_EXIT
     except ManifestParseError as mpe:
         print("fatal: %s" % mpe, file=sys.stderr)
         result = 1