def _CheckStatus(self, status, node): """Raises ErrExitFailure, maybe with location info attached.""" if self.exec_opts.ErrExit() and status != 0: # NOTE: Sometimes location info is duplicated, like on UsageError, or a # bad redirect. Also, pipelines can fail twice. if node.tag == command_e.SimpleCommand: reason = 'command in ' span_id = word.LeftMostSpanForWord(node.words[0]) elif node.tag == command_e.Assignment: reason = 'assignment in ' span_id = self._SpanIdForAssignment(node) elif node.tag == command_e.Subshell: reason = 'subshell invoked from ' span_id = node.spids[0] elif node.tag == command_e.Pipeline: # The whole pipeline can fail separately reason = 'pipeline invoked from ' span_id = node.spids[0] # only one spid else: # NOTE: The fallback of CurrentSpanId() fills this in. reason = '' span_id = const.NO_INTEGER raise util.ErrExitFailure( 'Exiting with status %d (%sPID %d)', status, reason, posix.getpid(), span_id=span_id, status=status)
def _CheckStatus(self, status, node, argv0=None): """ErrExitFailure with location info attached.""" if self.exec_opts.ErrExit() and status != 0: # Add context based on node type if node.tag == command_e.SimpleCommand: argv0 = argv0 or '<unknown>' raise util.ErrExitFailure( '[%d] %r command exited with status %d', posix.getpid(), argv0, status, word=node.words[0], status=status) elif node.tag == command_e.Assignment: span_id = self._SpanIdForAssignment(node) raise util.ErrExitFailure( '[%d] assignment exited with status %d', posix.getpid(), status, span_id=span_id, status=status) else: raise util.ErrExitFailure( '[%d] %r exited with status %d', posix.getpid(), node.__class__.__name__, status, status=status)
def RunCommandSub(self, node): p = self._MakeProcess(node, disable_errexit=not self.exec_opts.strict_errexit) r, w = posix.pipe() p.AddStateChange(process.StdoutToPipe(r, w)) pid = p.Start() #log('Command sub started %d', pid) self.waiter.Register(pid, p.WhenDone) chunks = [] posix.close(w) # not going to write while True: byte_str = posix.read(r, 4096) if not byte_str: break chunks.append(byte_str) posix.close(r) status = p.WaitUntilDone(self.waiter) # OSH has the concept of aborting in the middle of a WORD. We're not # waiting until the command is over! if self.exec_opts.strict_errexit: if self.exec_opts.ErrExit() and status != 0: raise util.ErrExitFailure( 'Command sub exited with status %d (%r)', status, node.__class__.__name__) else: # Set a flag so we check errexit at the same time as bash. Example: # # a=$(false) # echo foo # no matter what comes here, the flag is reset # # Set ONLY until this command node has finished executing. self.check_command_sub_status = True self.mem.last_status = status # Runtime errors test case: # $("echo foo > $@") # Why rstrip()? # https://unix.stackexchange.com/questions/17747/why-does-shell-command-substitution-gobble-up-a-trailing-newline-char return ''.join(chunks).rstrip('\n')