utils.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package docker
  2. import (
  3. "bytes"
  4. "container/list"
  5. "io"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "sync"
  10. )
  11. func Trunc(s string, maxlen int) string {
  12. if len(s) <= maxlen {
  13. return s
  14. }
  15. return s[:maxlen]
  16. }
  17. // Tar generates a tar archive from a filesystem path, and returns it as a stream.
  18. // Path must point to a directory.
  19. func Tar(path string) (io.Reader, error) {
  20. cmd := exec.Command("tar", "-C", path, "-c", ".")
  21. output, err := cmd.StdoutPipe()
  22. if err != nil {
  23. return nil, err
  24. }
  25. if err := cmd.Start(); err != nil {
  26. return nil, err
  27. }
  28. // FIXME: errors will not be passed because we don't wait for the command.
  29. // Instead, consumers will hit EOF right away.
  30. // This can be fixed by waiting for the process to exit, or for the first write
  31. // on stdout, whichever comes first.
  32. return output, nil
  33. }
  34. // Figure out the absolute path of our own binary
  35. func SelfPath() string {
  36. path, err := exec.LookPath(os.Args[0])
  37. if err != nil {
  38. panic(err)
  39. }
  40. path, err = filepath.Abs(path)
  41. if err != nil {
  42. panic(err)
  43. }
  44. return path
  45. }
  46. type nopWriteCloser struct {
  47. io.Writer
  48. }
  49. func (w *nopWriteCloser) Close() error { return nil }
  50. func NopWriteCloser(w io.Writer) io.WriteCloser {
  51. return &nopWriteCloser{w}
  52. }
  53. type bufReader struct {
  54. buf *bytes.Buffer
  55. reader io.Reader
  56. err error
  57. l sync.Mutex
  58. wait sync.Cond
  59. }
  60. func newBufReader(r io.Reader) *bufReader {
  61. reader := &bufReader{
  62. buf: &bytes.Buffer{},
  63. reader: r,
  64. }
  65. reader.wait.L = &reader.l
  66. go reader.drain()
  67. return reader
  68. }
  69. func (r *bufReader) drain() {
  70. buf := make([]byte, 1024)
  71. for {
  72. n, err := r.reader.Read(buf)
  73. if err != nil {
  74. r.err = err
  75. } else {
  76. r.buf.Write(buf[0:n])
  77. }
  78. r.l.Lock()
  79. r.wait.Signal()
  80. r.l.Unlock()
  81. if err != nil {
  82. break
  83. }
  84. }
  85. }
  86. func (r *bufReader) Read(p []byte) (n int, err error) {
  87. for {
  88. n, err = r.buf.Read(p)
  89. if n > 0 {
  90. return n, err
  91. }
  92. if r.err != nil {
  93. return 0, r.err
  94. }
  95. r.l.Lock()
  96. r.wait.Wait()
  97. r.l.Unlock()
  98. }
  99. return
  100. }
  101. func (r *bufReader) Close() error {
  102. closer, ok := r.reader.(io.ReadCloser)
  103. if !ok {
  104. return nil
  105. }
  106. return closer.Close()
  107. }
  108. type writeBroadcaster struct {
  109. writers *list.List
  110. }
  111. func (w *writeBroadcaster) AddWriter(writer io.WriteCloser) {
  112. w.writers.PushBack(writer)
  113. }
  114. func (w *writeBroadcaster) RemoveWriter(writer io.WriteCloser) {
  115. for e := w.writers.Front(); e != nil; e = e.Next() {
  116. v := e.Value.(io.Writer)
  117. if v == writer {
  118. w.writers.Remove(e)
  119. return
  120. }
  121. }
  122. }
  123. func (w *writeBroadcaster) Write(p []byte) (n int, err error) {
  124. failed := []*list.Element{}
  125. for e := w.writers.Front(); e != nil; e = e.Next() {
  126. writer := e.Value.(io.Writer)
  127. if n, err := writer.Write(p); err != nil || n != len(p) {
  128. // On error, evict the writer
  129. failed = append(failed, e)
  130. }
  131. }
  132. // We cannot remove while iterating, so it has to be done in
  133. // a separate step
  134. for _, e := range failed {
  135. w.writers.Remove(e)
  136. }
  137. return len(p), nil
  138. }
  139. func (w *writeBroadcaster) Close() error {
  140. for e := w.writers.Front(); e != nil; e = e.Next() {
  141. writer := e.Value.(io.WriteCloser)
  142. writer.Close()
  143. }
  144. return nil
  145. }
  146. func newWriteBroadcaster() *writeBroadcaster {
  147. return &writeBroadcaster{list.New()}
  148. }