def __call__(self, signal_number, stack_frame): with self._lock: self._interrupts += 1 # Copy the interrupts count and perform the handler outside of this # lock context. The handler can take a long time and we want to make # sure that future interrupts don't wait for it. interrupts = self._interrupts if interrupts == 1: # Only do the base handler once. self._base_handler(signal_number, stack_frame) elif interrupts == 3: # If we detect mashing, fallback to gcloud's original handler. keyboard_interrupt.HandleInterrupt(signal_number, stack_frame)
gcloud_cli.Execute() except IOError as err: # We want to ignore EPIPE IOErrors. # By default, Python ignores SIGPIPE (see # http://utcc.utoronto.ca/~cks/space/blog/python/SignalExceptionSurprise). # This means that attempting to write any output to a closed pipe (e.g. in # the case of output piped to `head` or `grep -q`) will result in an # IOError, which gets reported as a gcloud crash. We don't want this # behavior, so we ignore EPIPE (it's not a real error; it's a normal thing # to occur). # Before, we restore the SIGPIPE signal handler, but that caused issues # with scripts/programs that wrapped gcloud. if err.errno != errno.EPIPE: raise except Exception as err: # pylint:disable=broad-except crash_handling.HandleGcloudCrash(err) if properties.VALUES.core.print_unhandled_tracebacks.GetBool(): # We want to see the traceback as normally handled by Python raise else: # This is the case for most non-Cloud SDK developers. They shouldn't see # the full stack trace, but just the nice "gcloud crashed" message. sys.exit(1) if __name__ == '__main__': try: main() except KeyboardInterrupt: keyboard_interrupt.HandleInterrupt()