Merge branch 'flynn-stop-at-eof'
This commit is contained in:
commit
e43dce6dc1
16
tail.go
16
tail.go
|
@ -4,6 +4,7 @@ package tail
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -156,6 +157,14 @@ func (tail *Tail) Stop() error {
|
||||||
return tail.Wait()
|
return tail.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StopAtEOF stops tailing as soon as the end of the file is reached.
|
||||||
|
func (tail *Tail) StopAtEOF() error {
|
||||||
|
tail.Kill(errStopAtEOF)
|
||||||
|
return tail.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
var errStopAtEOF = errors.New("tail: stop at eof")
|
||||||
|
|
||||||
func (tail *Tail) close() {
|
func (tail *Tail) close() {
|
||||||
close(tail.Lines)
|
close(tail.Lines)
|
||||||
tail.colseFile()
|
tail.colseFile()
|
||||||
|
@ -236,6 +245,7 @@ func (tail *Tail) tailFileSync() {
|
||||||
|
|
||||||
var offset int64 = 0
|
var offset int64 = 0
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Read line by line.
|
// Read line by line.
|
||||||
for {
|
for {
|
||||||
// do not seek in named pipes
|
// do not seek in named pipes
|
||||||
|
@ -265,8 +275,7 @@ func (tail *Tail) tailFileSync() {
|
||||||
case <-tail.Dying():
|
case <-tail.Dying():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = tail.seekEnd()
|
if err := tail.seekEnd(); err != nil {
|
||||||
if err != nil {
|
|
||||||
tail.Kill(err)
|
tail.Kill(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -307,6 +316,9 @@ func (tail *Tail) tailFileSync() {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-tail.Dying():
|
case <-tail.Dying():
|
||||||
|
if tail.Err() == errStopAtEOF {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
19
tail_test.go
19
tail_test.go
|
@ -55,6 +55,25 @@ func TestStop(t *testing.T) {
|
||||||
tail.Cleanup()
|
tail.Cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStopAtEOF(_t *testing.T) {
|
||||||
|
t := NewTailTest("maxlinesize", _t)
|
||||||
|
t.CreateFile("test.txt", "hello\nthere\nworld\n")
|
||||||
|
tail := t.StartTail("test.txt", Config{Follow: true, Location: nil})
|
||||||
|
|
||||||
|
// read "hello"
|
||||||
|
<-tail.Lines
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
<-time.After(100 * time.Millisecond)
|
||||||
|
t.VerifyTailOutput(tail, []string{"there", "world"})
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
tail.StopAtEOF()
|
||||||
|
<-done
|
||||||
|
tail.Cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
func MaxLineSizeT(_t *testing.T, follow bool, fileContent string, expected []string) {
|
func MaxLineSizeT(_t *testing.T, follow bool, fileContent string, expected []string) {
|
||||||
t := NewTailTest("maxlinesize", _t)
|
t := NewTailTest("maxlinesize", _t)
|
||||||
t.CreateFile("test.txt", fileContent)
|
t.CreateFile("test.txt", fileContent)
|
||||||
|
|
|
@ -23,12 +23,6 @@ func (fc *FileChanges) NotifyDeleted() {
|
||||||
sendOnlyIfEmpty(fc.Deleted)
|
sendOnlyIfEmpty(fc.Deleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fc *FileChanges) Close() {
|
|
||||||
close(fc.Modified)
|
|
||||||
close(fc.Truncated)
|
|
||||||
close(fc.Deleted)
|
|
||||||
}
|
|
||||||
|
|
||||||
// sendOnlyIfEmpty sends on a bool channel only if the channel has no
|
// sendOnlyIfEmpty sends on a bool channel only if the channel has no
|
||||||
// backlog to be read by other goroutines. This concurrency pattern
|
// backlog to be read by other goroutines. This concurrency pattern
|
||||||
// can be used to notify other goroutines if and only if they are
|
// can be used to notify other goroutines if and only if they are
|
||||||
|
|
|
@ -66,7 +66,6 @@ func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChange
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer RemoveWatch(fw.Filename)
|
defer RemoveWatch(fw.Filename)
|
||||||
defer changes.Close()
|
|
||||||
|
|
||||||
events := Events(fw.Filename)
|
events := Events(fw.Filename)
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,6 @@ func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChange
|
||||||
fw.Size = pos
|
fw.Size = pos
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer changes.Close()
|
|
||||||
|
|
||||||
prevSize := fw.Size
|
prevSize := fw.Size
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
|
Loading…
Reference in New Issue