github.com/drud/ddev@v1.21.5-alpha1.0.20230226034409-94fcc4b94453/pkg/util/capture.go (about) 1 package util 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/drud/ddev/pkg/output" 7 "io" 8 "os" 9 ) 10 11 // CaptureUserOut captures output written to UserOut to a string. 12 // Capturing starts when it is called. It returns an anonymous function that 13 // when called, will return a string containing the output during capture, and 14 // revert once again to the original value of os.StdOut. 15 func CaptureUserOut() func() string { 16 old := output.UserOut.Out // keep backup of the real stdout 17 r, w, _ := os.Pipe() 18 output.UserOut.Out = w 19 20 return func() string { 21 outC := make(chan string) 22 // copy the output in a separate goroutine so printing can't block indefinitely 23 go func() { 24 var buf bytes.Buffer 25 _, err := io.Copy(&buf, r) 26 CheckErr(err) 27 outC <- buf.String() 28 }() 29 30 // back to normal state 31 CheckClose(w) 32 output.UserOut.Out = old // restoring the real stdout 33 34 out := <-outC 35 return out 36 } 37 } 38 39 // CaptureStdOut captures Stdout to a string. Capturing starts when it is called. It returns an anonymous function that when called, will return a string 40 // containing the output during capture, and revert once again to the original value of os.StdOut. 41 func CaptureStdOut() func() string { 42 old := os.Stdout // keep backup of the real stdout 43 r, w, _ := os.Pipe() 44 os.Stdout = w 45 46 return func() string { 47 outC := make(chan string) 48 // copy the output in a separate goroutine so printing can't block indefinitely 49 go func() { 50 var buf bytes.Buffer 51 _, err := io.Copy(&buf, r) 52 CheckErr(err) 53 outC <- buf.String() 54 }() 55 56 // back to normal state 57 CheckClose(w) 58 os.Stdout = old // restoring the real stdout 59 out := <-outC 60 return out 61 } 62 } 63 64 // CaptureOutputToFile captures Stdout to a string. Capturing starts when it is called. It returns an anonymous function that when called, will return a string 65 // containing the output during capture, and revert once again to the original value of os.StdOut. 66 func CaptureOutputToFile() (func() string, error) { 67 oldStdout := os.Stdout // keep backup of the real stdout 68 oldStderr := os.Stderr 69 f, err := os.CreateTemp("", "CaptureOutputToFile") 70 if err != nil { 71 return nil, err 72 } 73 os.Stdout = f 74 os.Stderr = f 75 76 return func() string { 77 _ = f.Close() 78 os.Stdout = oldStdout // restoring the real stdout 79 os.Stderr = oldStderr 80 out, err := os.ReadFile(f.Name()) 81 if err != nil { 82 out = []byte(fmt.Sprintf("failed to read file: %v", err)) 83 } 84 defer func() { 85 _ = os.RemoveAll(f.Name()) 86 }() 87 return string(out) 88 }, nil 89 }