progress.go 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. package utils
  2. import (
  3. "io"
  4. "net"
  5. "os"
  6. "syscall"
  7. "github.com/Sirupsen/logrus"
  8. "github.com/docker/docker/pkg/progress"
  9. "github.com/docker/docker/pkg/streamformatter"
  10. )
  11. // WriteDistributionProgress is a helper for writing progress from chan to JSON
  12. // stream with an optional cancel function.
  13. func WriteDistributionProgress(cancelFunc func(), outStream io.Writer, progressChan <-chan progress.Progress) {
  14. progressOutput := streamformatter.NewJSONProgressOutput(outStream, false)
  15. operationCancelled := false
  16. for prog := range progressChan {
  17. if err := progressOutput.WriteProgress(prog); err != nil && !operationCancelled {
  18. // don't log broken pipe errors as this is the normal case when a client aborts
  19. if isBrokenPipe(err) {
  20. logrus.Info("Pull session cancelled")
  21. } else {
  22. logrus.Errorf("error writing progress to client: %v", err)
  23. }
  24. cancelFunc()
  25. operationCancelled = true
  26. // Don't return, because we need to continue draining
  27. // progressChan until it's closed to avoid a deadlock.
  28. }
  29. }
  30. }
  31. func isBrokenPipe(e error) bool {
  32. if netErr, ok := e.(*net.OpError); ok {
  33. e = netErr.Err
  34. if sysErr, ok := netErr.Err.(*os.SyscallError); ok {
  35. e = sysErr.Err
  36. }
  37. }
  38. return e == syscall.EPIPE
  39. }