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  }