github.com/daniellockard/packer@v0.7.6-0.20141210173435-5a9390934716/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  }