Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/client9/reopen/reopen.go')
-rw-r--r--vendor/github.com/client9/reopen/reopen.go254
1 files changed, 254 insertions, 0 deletions
diff --git a/vendor/github.com/client9/reopen/reopen.go b/vendor/github.com/client9/reopen/reopen.go
new file mode 100644
index 00000000..6032c308
--- /dev/null
+++ b/vendor/github.com/client9/reopen/reopen.go
@@ -0,0 +1,254 @@
+package reopen
+
+import (
+ "bufio"
+ "io"
+ "io/ioutil"
+ "os"
+ "sync"
+ "time"
+)
+
+// Reopener interface defines something that can be reopened
+type Reopener interface {
+ Reopen() error
+}
+
+// Writer is a writer that also can be reopened
+type Writer interface {
+ Reopener
+ io.Writer
+}
+
+// WriteCloser is a io.WriteCloser that can also be reopened
+type WriteCloser interface {
+ Reopener
+ io.WriteCloser
+}
+
+// FileWriter that can also be reopened
+type FileWriter struct {
+ mu sync.Mutex // ensures close / reopen / write are not called at the same time, protects f
+ f *os.File
+ mode os.FileMode
+ name string
+}
+
+// Close calls the underlyding File.Close()
+func (f *FileWriter) Close() error {
+ f.mu.Lock()
+ err := f.f.Close()
+ f.mu.Unlock()
+ return err
+}
+
+// mutex free version
+func (f *FileWriter) reopen() error {
+ if f.f != nil {
+ f.f.Close()
+ f.f = nil
+ }
+ newf, err := os.OpenFile(f.name, os.O_WRONLY|os.O_APPEND|os.O_CREATE, f.mode)
+ if err != nil {
+ f.f = nil
+ return err
+ }
+ f.f = newf
+
+ return nil
+}
+
+// Reopen the file
+func (f *FileWriter) Reopen() error {
+ f.mu.Lock()
+ err := f.reopen()
+ f.mu.Unlock()
+ return err
+}
+
+// Write implements the stander io.Writer interface
+func (f *FileWriter) Write(p []byte) (int, error) {
+ f.mu.Lock()
+ n, err := f.f.Write(p)
+ f.mu.Unlock()
+ return n, err
+}
+
+// NewFileWriter opens a file for appending and writing and can be reopened.
+// it is a ReopenWriteCloser...
+func NewFileWriter(name string) (*FileWriter, error) {
+ // Standard default mode
+ return NewFileWriterMode(name, 0666)
+}
+
+// NewFileWriterMode opens a Reopener file with a specific permission
+func NewFileWriterMode(name string, mode os.FileMode) (*FileWriter, error) {
+ writer := FileWriter{
+ f: nil,
+ name: name,
+ mode: mode,
+ }
+ err := writer.reopen()
+ if err != nil {
+ return nil, err
+ }
+ return &writer, nil
+}
+
+// BufferedFileWriter is buffer writer than can be reopned
+type BufferedFileWriter struct {
+ mu sync.Mutex
+ quitChan chan bool
+ done bool
+ origWriter *FileWriter
+ bufWriter *bufio.Writer
+}
+
+// Reopen implement Reopener
+func (bw *BufferedFileWriter) Reopen() error {
+ bw.mu.Lock()
+ bw.bufWriter.Flush()
+
+ // use non-mutex version since we are using this one
+ err := bw.origWriter.reopen()
+
+ bw.bufWriter.Reset(io.Writer(bw.origWriter))
+ bw.mu.Unlock()
+
+ return err
+}
+
+// Close flushes the internal buffer and closes the destination file
+func (bw *BufferedFileWriter) Close() error {
+ bw.quitChan <- true
+ bw.mu.Lock()
+ bw.done = true
+ bw.bufWriter.Flush()
+ bw.origWriter.f.Close()
+ bw.mu.Unlock()
+ return nil
+}
+
+// Write implements io.Writer (and reopen.Writer)
+func (bw *BufferedFileWriter) Write(p []byte) (int, error) {
+ bw.mu.Lock()
+ n, err := bw.bufWriter.Write(p)
+
+ // Special Case... if the used space in the buffer is LESS than
+ // the input, then we did a flush in the middle of the line
+ // and the full log line was not sent on its way.
+ if bw.bufWriter.Buffered() < len(p) {
+ bw.bufWriter.Flush()
+ }
+
+ bw.mu.Unlock()
+ return n, err
+}
+
+// Flush flushes the buffer.
+func (bw *BufferedFileWriter) Flush() {
+ bw.mu.Lock()
+ // could add check if bw.done already
+ // should never happen
+ bw.bufWriter.Flush()
+ bw.origWriter.f.Sync()
+ bw.mu.Unlock()
+}
+
+// flushDaemon periodically flushes the log file buffers.
+func (bw *BufferedFileWriter) flushDaemon(interval time.Duration) {
+ ticker := time.NewTicker(interval)
+ for {
+ select {
+ case <-bw.quitChan:
+ ticker.Stop()
+ return
+ case <-ticker.C:
+ bw.Flush()
+ }
+ }
+}
+
+const bufferSize = 256 * 1024
+const flushInterval = 30 * time.Second
+
+// NewBufferedFileWriter opens a buffered file that is periodically
+// flushed.
+func NewBufferedFileWriter(w *FileWriter) *BufferedFileWriter {
+ return NewBufferedFileWriterSize(w, bufferSize, flushInterval)
+}
+
+// NewBufferedFileWriterSize opens a buffered file with the given size that is periodically
+// flushed on the given interval.
+func NewBufferedFileWriterSize(w *FileWriter, size int, flush time.Duration) *BufferedFileWriter {
+ bw := BufferedFileWriter{
+ quitChan: make(chan bool, 1),
+ origWriter: w,
+ bufWriter: bufio.NewWriterSize(w, size),
+ }
+ go bw.flushDaemon(flush)
+ return &bw
+}
+
+type multiReopenWriter struct {
+ writers []Writer
+}
+
+// Reopen reopens all child Reopeners
+func (t *multiReopenWriter) Reopen() error {
+ for _, w := range t.writers {
+ err := w.Reopen()
+ if err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// Write implements standard io.Write and reopen.Write
+func (t *multiReopenWriter) Write(p []byte) (int, error) {
+ for _, w := range t.writers {
+ n, err := w.Write(p)
+ if err != nil {
+ return n, err
+ }
+ if n != len(p) {
+ return n, io.ErrShortWrite
+ }
+ }
+ return len(p), nil
+}
+
+// MultiWriter creates a writer that duplicates its writes to all the
+// provided writers, similar to the Unix tee(1) command.
+// Also allow reopen
+func MultiWriter(writers ...Writer) Writer {
+ w := make([]Writer, len(writers))
+ copy(w, writers)
+ return &multiReopenWriter{w}
+}
+
+type nopReopenWriteCloser struct {
+ io.Writer
+}
+
+func (nopReopenWriteCloser) Reopen() error {
+ return nil
+}
+
+func (nopReopenWriteCloser) Close() error {
+ return nil
+}
+
+// NopWriter turns a normal writer into a ReopenWriter
+// by doing a NOP on Reopen. See https://en.wikipedia.org/wiki/NOP
+func NopWriter(w io.Writer) WriteCloser {
+ return nopReopenWriteCloser{w}
+}
+
+// Reopenable versions of os.Stdout, os.Stderr, /dev/null (reopen does nothing)
+var (
+ Stdout = NopWriter(os.Stdout)
+ Stderr = NopWriter(os.Stderr)
+ Discard = NopWriter(ioutil.Discard)
+)