lib: Fix x/lib for go1.6
There are 2 changes in go1.6 that affect x/lib.
The signal package was changed wrt writing to broken pipes.
Basically we'll get a SIGPIPE when writing to a broken os.Stdout.
The fix is to detect the SIGPIPE-based failure, and handle it
appropriately in IgnoreClosedPipeError mode.
The utf8.FullRune function was also re-implemented to be faster.
As a side-effect, this also fixed some bugs with the original
implementation. The bug causes differing behavior under go1.5 vs
go1.6, but thankfully only affects a particular test case, which
isn't actually that important. The fix is to comment-out the
test case, which is updated to work for go1.6. Once we've
switched over, we'll uncomment the test case.
https://go-review.googlesource.com/#/c/16940/4/src/unicode/utf8/utf8.go@a142
Issue https://v.io/i/1165
Change-Id: Id7095ac112e465ea1eeb7823fb2b693116bab290
diff --git a/gosh/cmd.go b/gosh/cmd.go
index 25ea76a..e7b7e22 100644
--- a/gosh/cmd.go
+++ b/gosh/cmd.go
@@ -298,16 +298,15 @@
// IgnoreClosedPipeError handles this case. gosh.Pipeline sets this option to
// true, so that by default the pipeline above will succeed, but will fail on
// any other error. Note that the exec package always returns an ExitError if
-// the child process exited with a non-zero exit code; the closed pipe error is
-// only returned if the child process exited with a zero exit code, and Write on
-// the io.MultiWriter in the parent process received the closed pipe error.
+// the child process exited with a non-zero exit code, or died due to a signal;
+// io.ErrClosedPipe and os.PathError are only returned if the child process
+// exited with a zero exit code, and Write on the io.MultiWriter in the parent
+// process received the closed pipe error.
//
-// TODO(toddw): We could adopt the convention that exit code 141 indicates
-// "closed pipe", and use IgnoreClosedPipeError to also ignore that case. We
-// choose 141 because it's 128 + 13, where SIGPIPE is 13, and there is an
-// existing convention for this. By default Go programs ignore SIGPIPE, so we
-// might also want to add code to InitChildMain to exit the program with 141 if
-// it receives SIGPIPE.
+// Starting in go 1.6, by default all go programs will exit with SIGPIPE if they
+// try to write to a broken os.Stdout or os.Stderr. This is the behavior we
+// want; it means that normal go programs will behave as expected wrt
+// IgnoreClosedPipeError, and gosh.Pipeline will work by default.
var sep = strings.Repeat("-", 40)
@@ -506,8 +505,18 @@
return true
}
// Closed pipe on os.Pipe; mirrors logic in os/exec/exec_posix.go.
- if pe, ok := err.(*os.PathError); ok && pe.Op == "write" && pe.Path == "|1" && pe.Err == syscall.EPIPE {
- return true
+ if pe, ok := err.(*os.PathError); ok {
+ if pe.Op == "write" && pe.Path == "|1" && pe.Err == syscall.EPIPE {
+ return true
+ }
+ }
+ // Process exited due to a SIGPIPE signal.
+ if ee, ok := err.(*exec.ExitError); ok {
+ if ws, ok := ee.ProcessState.Sys().(syscall.WaitStatus); ok {
+ if ws.Signaled() && ws.Signal() == syscall.SIGPIPE {
+ return true
+ }
+ }
}
return false
}
diff --git a/textutil/utf8_test.go b/textutil/utf8_test.go
index 8175e62..264334d 100644
--- a/textutil/utf8_test.go
+++ b/textutil/utf8_test.go
@@ -35,7 +35,10 @@
{"\uFFFD", []rune{'\uFFFD'}, nil},
{"a\uFFFDb", []rune{'a', '\uFFFD', 'b'}, nil},
{"\x80", []rune{'\uFFFD'}, nil},
- {"\xFF", nil, []rune{'\uFFFD'}},
+ // TODO(toddw): Enable the below line when we've switched to go1.6+. It
+ // fails in go1.5 because of a bugfix that changed this behavior.
+ // https://go-review.googlesource.com/#/c/16940/4/src/unicode/utf8/utf8.go@a142
+ // {"\xFF", []rune{'\uFFFD'}, nil},
{"a\x80b", []rune{'a', '\uFFFD', 'b'}, nil},
{"a\xFFb", []rune{'a', '\uFFFD', 'b'}, nil},
// Multi-byte full runes.