github.com/dacamp/packer@v0.10.2/provisioner/shell/unix_reader.go (about) 1 package shell 2 3 import ( 4 "bufio" 5 "io" 6 "sync" 7 ) 8 9 // UnixReader is a Reader implementation that automatically converts 10 // Windows line endings to Unix line endings. 11 type UnixReader struct { 12 Reader io.Reader 13 14 buf []byte 15 once sync.Once 16 scanner *bufio.Scanner 17 } 18 19 func (r *UnixReader) Read(p []byte) (n int, err error) { 20 // Create the buffered reader once 21 r.once.Do(func() { 22 r.scanner = bufio.NewScanner(r.Reader) 23 r.scanner.Split(scanUnixLine) 24 }) 25 26 // If we have no data in our buffer, scan to the next token 27 if len(r.buf) == 0 { 28 if !r.scanner.Scan() { 29 err = r.scanner.Err() 30 if err == nil { 31 err = io.EOF 32 } 33 34 return 0, err 35 } 36 37 r.buf = r.scanner.Bytes() 38 } 39 40 // Write out as much data as we can to the buffer, storing the rest 41 // for the next read. 42 n = len(p) 43 if n > len(r.buf) { 44 n = len(r.buf) 45 } 46 copy(p, r.buf) 47 r.buf = r.buf[n:] 48 49 return 50 } 51 52 // scanUnixLine is a bufio.Scanner SplitFunc. It tokenizes on lines, but 53 // only returns unix-style lines. So even if the line is "one\r\n", the 54 // token returned will be "one\n". 55 func scanUnixLine(data []byte, atEOF bool) (advance int, token []byte, err error) { 56 advance, token, err = bufio.ScanLines(data, atEOF) 57 if advance == 0 { 58 // If we reached the end of a line without a newline, then 59 // just return as it is. Otherwise the Scanner will keep trying 60 // to scan, blocking forever. 61 return 62 } 63 64 return advance, append(token, '\n'), err 65 }