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