github.com/OpenFlowLabs/moby@v17.12.1-ce-rc2+incompatible/pkg/tailfile/tailfile.go (about)

     1  // Package tailfile provides helper functions to read the nth lines of any
     2  // ReadSeeker.
     3  package tailfile
     4  
     5  import (
     6  	"bytes"
     7  	"errors"
     8  	"io"
     9  	"os"
    10  )
    11  
    12  const blockSize = 1024
    13  
    14  var eol = []byte("\n")
    15  
    16  // ErrNonPositiveLinesNumber is an error returned if the lines number was negative.
    17  var ErrNonPositiveLinesNumber = errors.New("The number of lines to extract from the file must be positive")
    18  
    19  //TailFile returns last n lines of reader f (could be a fil).
    20  func TailFile(f io.ReadSeeker, n int) ([][]byte, error) {
    21  	if n <= 0 {
    22  		return nil, ErrNonPositiveLinesNumber
    23  	}
    24  	size, err := f.Seek(0, os.SEEK_END)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	block := -1
    29  	var data []byte
    30  	var cnt int
    31  	for {
    32  		var b []byte
    33  		step := int64(block * blockSize)
    34  		left := size + step // how many bytes to beginning
    35  		if left < 0 {
    36  			if _, err := f.Seek(0, os.SEEK_SET); err != nil {
    37  				return nil, err
    38  			}
    39  			b = make([]byte, blockSize+left)
    40  			if _, err := f.Read(b); err != nil {
    41  				return nil, err
    42  			}
    43  			data = append(b, data...)
    44  			break
    45  		} else {
    46  			b = make([]byte, blockSize)
    47  			if _, err := f.Seek(left, os.SEEK_SET); err != nil {
    48  				return nil, err
    49  			}
    50  			if _, err := f.Read(b); err != nil {
    51  				return nil, err
    52  			}
    53  			data = append(b, data...)
    54  		}
    55  		cnt += bytes.Count(b, eol)
    56  		if cnt > n {
    57  			break
    58  		}
    59  		block--
    60  	}
    61  	lines := bytes.Split(data, eol)
    62  	if n < len(lines) {
    63  		return lines[len(lines)-n-1 : len(lines)-1], nil
    64  	}
    65  	return lines[:len(lines)-1], nil
    66  }