mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-12 08:23:48 +02:00
Merge pull request #509 from andruby/fix-docker-build
Rename go dependencies on dotcloud/docker to docker/docker
This commit is contained in:
commit
22268eb2e6
16
Godeps/Godeps.json
generated
16
Godeps/Godeps.json
generated
@ -124,27 +124,17 @@
|
|||||||
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/dotcloud/docker/archive",
|
"ImportPath": "github.com/docker/docker/archive",
|
||||||
"Comment": "v1.2.0-576-gf68f5fd",
|
"Comment": "v1.2.0-576-gf68f5fd",
|
||||||
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/dotcloud/docker/pkg/parsers",
|
"ImportPath": "github.com/docker/docker/pkg/parsers",
|
||||||
"Comment": "v1.2.0-576-gf68f5fd",
|
"Comment": "v1.2.0-576-gf68f5fd",
|
||||||
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/dotcloud/docker/pkg/stdcopy",
|
"ImportPath": "github.com/docker/docker/pkg/stdcopy",
|
||||||
"Comment": "v1.2.0-576-gf68f5fd",
|
|
||||||
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/dotcloud/docker/pkg/term",
|
|
||||||
"Comment": "v1.2.0-576-gf68f5fd",
|
|
||||||
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/dotcloud/docker/utils",
|
|
||||||
"Comment": "v1.2.0-576-gf68f5fd",
|
"Comment": "v1.2.0-576-gf68f5fd",
|
||||||
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
"Rev": "f68f5fd521270ad9775fb0adfe7516f9e4855ba5"
|
||||||
},
|
},
|
||||||
|
1
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/MAINTAINERS
generated
vendored
1
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/MAINTAINERS
generated
vendored
@ -1 +0,0 @@
|
|||||||
Solomon Hykes <solomon@docker.com> (@shykes)
|
|
103
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/term.go
generated
vendored
103
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/term.go
generated
vendored
@ -1,103 +0,0 @@
|
|||||||
package term
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInvalidState = errors.New("Invalid terminal state")
|
|
||||||
)
|
|
||||||
|
|
||||||
type State struct {
|
|
||||||
termios Termios
|
|
||||||
}
|
|
||||||
|
|
||||||
type Winsize struct {
|
|
||||||
Height uint16
|
|
||||||
Width uint16
|
|
||||||
x uint16
|
|
||||||
y uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetWinsize(fd uintptr) (*Winsize, error) {
|
|
||||||
ws := &Winsize{}
|
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(ws)))
|
|
||||||
// Skipp errno = 0
|
|
||||||
if err == 0 {
|
|
||||||
return ws, nil
|
|
||||||
}
|
|
||||||
return ws, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetWinsize(fd uintptr, ws *Winsize) error {
|
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
|
|
||||||
// Skipp errno = 0
|
|
||||||
if err == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
||||||
func IsTerminal(fd uintptr) bool {
|
|
||||||
var termios Termios
|
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&termios)))
|
|
||||||
return err == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore restores the terminal connected to the given file descriptor to a
|
|
||||||
// previous state.
|
|
||||||
func RestoreTerminal(fd uintptr, state *State) error {
|
|
||||||
if state == nil {
|
|
||||||
return ErrInvalidState
|
|
||||||
}
|
|
||||||
_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&state.termios)))
|
|
||||||
if err != 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SaveState(fd uintptr) (*State, error) {
|
|
||||||
var oldState State
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &oldState, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DisableEcho(fd uintptr, state *State) error {
|
|
||||||
newState := state.termios
|
|
||||||
newState.Lflag &^= syscall.ECHO
|
|
||||||
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
handleInterrupt(fd, state)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetRawTerminal(fd uintptr) (*State, error) {
|
|
||||||
oldState, err := MakeRaw(fd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
handleInterrupt(fd, oldState)
|
|
||||||
return oldState, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleInterrupt(fd uintptr, state *State) {
|
|
||||||
sigchan := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(sigchan, os.Interrupt)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
_ = <-sigchan
|
|
||||||
RestoreTerminal(fd, state)
|
|
||||||
os.Exit(0)
|
|
||||||
}()
|
|
||||||
}
|
|
65
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/termios_darwin.go
generated
vendored
65
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/termios_darwin.go
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
package term
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
getTermios = syscall.TIOCGETA
|
|
||||||
setTermios = syscall.TIOCSETA
|
|
||||||
|
|
||||||
IGNBRK = syscall.IGNBRK
|
|
||||||
PARMRK = syscall.PARMRK
|
|
||||||
INLCR = syscall.INLCR
|
|
||||||
IGNCR = syscall.IGNCR
|
|
||||||
ECHONL = syscall.ECHONL
|
|
||||||
CSIZE = syscall.CSIZE
|
|
||||||
ICRNL = syscall.ICRNL
|
|
||||||
ISTRIP = syscall.ISTRIP
|
|
||||||
PARENB = syscall.PARENB
|
|
||||||
ECHO = syscall.ECHO
|
|
||||||
ICANON = syscall.ICANON
|
|
||||||
ISIG = syscall.ISIG
|
|
||||||
IXON = syscall.IXON
|
|
||||||
BRKINT = syscall.BRKINT
|
|
||||||
INPCK = syscall.INPCK
|
|
||||||
OPOST = syscall.OPOST
|
|
||||||
CS8 = syscall.CS8
|
|
||||||
IEXTEN = syscall.IEXTEN
|
|
||||||
)
|
|
||||||
|
|
||||||
type Termios struct {
|
|
||||||
Iflag uint64
|
|
||||||
Oflag uint64
|
|
||||||
Cflag uint64
|
|
||||||
Lflag uint64
|
|
||||||
Cc [20]byte
|
|
||||||
Ispeed uint64
|
|
||||||
Ospeed uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
func MakeRaw(fd uintptr) (*State, error) {
|
|
||||||
var oldState State
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newState := oldState.termios
|
|
||||||
newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)
|
|
||||||
newState.Oflag &^= OPOST
|
|
||||||
newState.Lflag &^= (ECHO | ECHONL | ICANON | ISIG | IEXTEN)
|
|
||||||
newState.Cflag &^= (CSIZE | PARENB)
|
|
||||||
newState.Cflag |= CS8
|
|
||||||
newState.Cc[syscall.VMIN] = 1
|
|
||||||
newState.Cc[syscall.VTIME] = 0
|
|
||||||
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &oldState, nil
|
|
||||||
}
|
|
65
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/termios_freebsd.go
generated
vendored
65
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/termios_freebsd.go
generated
vendored
@ -1,65 +0,0 @@
|
|||||||
package term
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
getTermios = syscall.TIOCGETA
|
|
||||||
setTermios = syscall.TIOCSETA
|
|
||||||
|
|
||||||
IGNBRK = syscall.IGNBRK
|
|
||||||
PARMRK = syscall.PARMRK
|
|
||||||
INLCR = syscall.INLCR
|
|
||||||
IGNCR = syscall.IGNCR
|
|
||||||
ECHONL = syscall.ECHONL
|
|
||||||
CSIZE = syscall.CSIZE
|
|
||||||
ICRNL = syscall.ICRNL
|
|
||||||
ISTRIP = syscall.ISTRIP
|
|
||||||
PARENB = syscall.PARENB
|
|
||||||
ECHO = syscall.ECHO
|
|
||||||
ICANON = syscall.ICANON
|
|
||||||
ISIG = syscall.ISIG
|
|
||||||
IXON = syscall.IXON
|
|
||||||
BRKINT = syscall.BRKINT
|
|
||||||
INPCK = syscall.INPCK
|
|
||||||
OPOST = syscall.OPOST
|
|
||||||
CS8 = syscall.CS8
|
|
||||||
IEXTEN = syscall.IEXTEN
|
|
||||||
)
|
|
||||||
|
|
||||||
type Termios struct {
|
|
||||||
Iflag uint32
|
|
||||||
Oflag uint32
|
|
||||||
Cflag uint32
|
|
||||||
Lflag uint32
|
|
||||||
Cc [20]byte
|
|
||||||
Ispeed uint32
|
|
||||||
Ospeed uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
func MakeRaw(fd uintptr) (*State, error) {
|
|
||||||
var oldState State
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(getTermios), uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newState := oldState.termios
|
|
||||||
newState.Iflag &^= (IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)
|
|
||||||
newState.Oflag &^= OPOST
|
|
||||||
newState.Lflag &^= (ECHO | ECHONL | ICANON | ISIG | IEXTEN)
|
|
||||||
newState.Cflag &^= (CSIZE | PARENB)
|
|
||||||
newState.Cflag |= CS8
|
|
||||||
newState.Cc[syscall.VMIN] = 1
|
|
||||||
newState.Cc[syscall.VTIME] = 0
|
|
||||||
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(setTermios), uintptr(unsafe.Pointer(&newState))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &oldState, nil
|
|
||||||
}
|
|
44
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/termios_linux.go
generated
vendored
44
Godeps/_workspace/src/github.com/dotcloud/docker/pkg/term/termios_linux.go
generated
vendored
@ -1,44 +0,0 @@
|
|||||||
package term
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
getTermios = syscall.TCGETS
|
|
||||||
setTermios = syscall.TCSETS
|
|
||||||
)
|
|
||||||
|
|
||||||
type Termios struct {
|
|
||||||
Iflag uint32
|
|
||||||
Oflag uint32
|
|
||||||
Cflag uint32
|
|
||||||
Lflag uint32
|
|
||||||
Cc [20]byte
|
|
||||||
Ispeed uint32
|
|
||||||
Ospeed uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeRaw put the terminal connected to the given file descriptor into raw
|
|
||||||
// mode and returns the previous state of the terminal so that it can be
|
|
||||||
// restored.
|
|
||||||
func MakeRaw(fd uintptr) (*State, error) {
|
|
||||||
var oldState State
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, getTermios, uintptr(unsafe.Pointer(&oldState.termios))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newState := oldState.termios
|
|
||||||
|
|
||||||
newState.Iflag &^= (syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON)
|
|
||||||
newState.Oflag &^= syscall.OPOST
|
|
||||||
newState.Lflag &^= (syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN)
|
|
||||||
newState.Cflag &^= (syscall.CSIZE | syscall.PARENB)
|
|
||||||
newState.Cflag |= syscall.CS8
|
|
||||||
|
|
||||||
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, setTermios, uintptr(unsafe.Pointer(&newState))); err != 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &oldState, nil
|
|
||||||
}
|
|
36
Godeps/_workspace/src/github.com/dotcloud/docker/utils/daemon.go
generated
vendored
36
Godeps/_workspace/src/github.com/dotcloud/docker/utils/daemon.go
generated
vendored
@ -1,36 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CreatePidFile(pidfile string) error {
|
|
||||||
if pidString, err := ioutil.ReadFile(pidfile); err == nil {
|
|
||||||
pid, err := strconv.Atoi(string(pidString))
|
|
||||||
if err == nil {
|
|
||||||
if _, err := os.Stat(fmt.Sprintf("/proc/%d/", pid)); err == nil {
|
|
||||||
return fmt.Errorf("pid file found, ensure docker is not running or delete %s", pidfile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Create(pidfile)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
_, err = fmt.Fprintf(file, "%d", os.Getpid())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func RemovePidFile(pidfile string) {
|
|
||||||
if err := os.Remove(pidfile); err != nil {
|
|
||||||
log.Printf("Error removing %s: %s", pidfile, err)
|
|
||||||
}
|
|
||||||
}
|
|
164
Godeps/_workspace/src/github.com/dotcloud/docker/utils/http.go
generated
vendored
164
Godeps/_workspace/src/github.com/dotcloud/docker/utils/http.go
generated
vendored
@ -1,164 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
// VersionInfo is used to model entities which has a version.
|
|
||||||
// It is basically a tupple with name and version.
|
|
||||||
type VersionInfo interface {
|
|
||||||
Name() string
|
|
||||||
Version() string
|
|
||||||
}
|
|
||||||
|
|
||||||
func validVersion(version VersionInfo) bool {
|
|
||||||
const stopChars = " \t\r\n/"
|
|
||||||
name := version.Name()
|
|
||||||
vers := version.Version()
|
|
||||||
if len(name) == 0 || strings.ContainsAny(name, stopChars) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if len(vers) == 0 || strings.ContainsAny(vers, stopChars) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert versions to a string and append the string to the string base.
|
|
||||||
//
|
|
||||||
// Each VersionInfo will be converted to a string in the format of
|
|
||||||
// "product/version", where the "product" is get from the Name() method, while
|
|
||||||
// version is get from the Version() method. Several pieces of verson information
|
|
||||||
// will be concatinated and separated by space.
|
|
||||||
func appendVersions(base string, versions ...VersionInfo) string {
|
|
||||||
if len(versions) == 0 {
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
|
|
||||||
verstrs := make([]string, 0, 1+len(versions))
|
|
||||||
if len(base) > 0 {
|
|
||||||
verstrs = append(verstrs, base)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range versions {
|
|
||||||
if !validVersion(v) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
verstrs = append(verstrs, v.Name()+"/"+v.Version())
|
|
||||||
}
|
|
||||||
return strings.Join(verstrs, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPRequestDecorator is used to change an instance of
|
|
||||||
// http.Request. It could be used to add more header fields,
|
|
||||||
// change body, etc.
|
|
||||||
type HTTPRequestDecorator interface {
|
|
||||||
// ChangeRequest() changes the request accordingly.
|
|
||||||
// The changed request will be returned or err will be non-nil
|
|
||||||
// if an error occur.
|
|
||||||
ChangeRequest(req *http.Request) (newReq *http.Request, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPUserAgentDecorator appends the product/version to the user agent field
|
|
||||||
// of a request.
|
|
||||||
type HTTPUserAgentDecorator struct {
|
|
||||||
versions []VersionInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPUserAgentDecorator(versions ...VersionInfo) HTTPRequestDecorator {
|
|
||||||
return &HTTPUserAgentDecorator{
|
|
||||||
versions: versions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HTTPUserAgentDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
|
|
||||||
if req == nil {
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
userAgent := appendVersions(req.UserAgent(), h.versions...)
|
|
||||||
if len(userAgent) > 0 {
|
|
||||||
req.Header.Set("User-Agent", userAgent)
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HTTPMetaHeadersDecorator struct {
|
|
||||||
Headers map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *HTTPMetaHeadersDecorator) ChangeRequest(req *http.Request) (newReq *http.Request, err error) {
|
|
||||||
if h.Headers == nil {
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
for k, v := range h.Headers {
|
|
||||||
req.Header[k] = v
|
|
||||||
}
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HTTPAuthDecorator struct {
|
|
||||||
login string
|
|
||||||
password string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPAuthDecorator(login, password string) HTTPRequestDecorator {
|
|
||||||
return &HTTPAuthDecorator{
|
|
||||||
login: login,
|
|
||||||
password: password,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *HTTPAuthDecorator) ChangeRequest(req *http.Request) (*http.Request, error) {
|
|
||||||
req.SetBasicAuth(self.login, self.password)
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPRequestFactory creates an HTTP request
|
|
||||||
// and applies a list of decorators on the request.
|
|
||||||
type HTTPRequestFactory struct {
|
|
||||||
decorators []HTTPRequestDecorator
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPRequestFactory(d ...HTTPRequestDecorator) *HTTPRequestFactory {
|
|
||||||
return &HTTPRequestFactory{
|
|
||||||
decorators: d,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *HTTPRequestFactory) AddDecorator(d ...HTTPRequestDecorator) {
|
|
||||||
self.decorators = append(self.decorators, d...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewRequest() creates a new *http.Request,
|
|
||||||
// applies all decorators in the HTTPRequestFactory on the request,
|
|
||||||
// then applies decorators provided by d on the request.
|
|
||||||
func (h *HTTPRequestFactory) NewRequest(method, urlStr string, body io.Reader, d ...HTTPRequestDecorator) (*http.Request, error) {
|
|
||||||
req, err := http.NewRequest(method, urlStr, body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// By default, a nil factory should work.
|
|
||||||
if h == nil {
|
|
||||||
return req, nil
|
|
||||||
}
|
|
||||||
for _, dec := range h.decorators {
|
|
||||||
req, err = dec.ChangeRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, dec := range d {
|
|
||||||
req, err = dec.ChangeRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Debugf("%v -- HEADERS: %v", req.URL, req.Header)
|
|
||||||
return req, err
|
|
||||||
}
|
|
169
Godeps/_workspace/src/github.com/dotcloud/docker/utils/jsonmessage.go
generated
vendored
169
Godeps/_workspace/src/github.com/dotcloud/docker/utils/jsonmessage.go
generated
vendored
@ -1,169 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/docker/docker/pkg/term"
|
|
||||||
"github.com/docker/docker/pkg/timeutils"
|
|
||||||
"github.com/docker/docker/pkg/units"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONError struct {
|
|
||||||
Code int `json:"code,omitempty"`
|
|
||||||
Message string `json:"message,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *JSONError) Error() string {
|
|
||||||
return e.Message
|
|
||||||
}
|
|
||||||
|
|
||||||
type JSONProgress struct {
|
|
||||||
terminalFd uintptr
|
|
||||||
Current int `json:"current,omitempty"`
|
|
||||||
Total int `json:"total,omitempty"`
|
|
||||||
Start int64 `json:"start,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *JSONProgress) String() string {
|
|
||||||
var (
|
|
||||||
width = 200
|
|
||||||
pbBox string
|
|
||||||
numbersBox string
|
|
||||||
timeLeftBox string
|
|
||||||
)
|
|
||||||
|
|
||||||
ws, err := term.GetWinsize(p.terminalFd)
|
|
||||||
if err == nil {
|
|
||||||
width = int(ws.Width)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Current <= 0 && p.Total <= 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
current := units.HumanSize(int64(p.Current))
|
|
||||||
if p.Total <= 0 {
|
|
||||||
return fmt.Sprintf("%8v", current)
|
|
||||||
}
|
|
||||||
total := units.HumanSize(int64(p.Total))
|
|
||||||
percentage := int(float64(p.Current)/float64(p.Total)*100) / 2
|
|
||||||
if width > 110 {
|
|
||||||
// this number can't be negetive gh#7136
|
|
||||||
numSpaces := 0
|
|
||||||
if 50-percentage > 0 {
|
|
||||||
numSpaces = 50 - percentage
|
|
||||||
}
|
|
||||||
pbBox = fmt.Sprintf("[%s>%s] ", strings.Repeat("=", percentage), strings.Repeat(" ", numSpaces))
|
|
||||||
}
|
|
||||||
numbersBox = fmt.Sprintf("%8v/%v", current, total)
|
|
||||||
|
|
||||||
if p.Current > 0 && p.Start > 0 && percentage < 50 {
|
|
||||||
fromStart := time.Now().UTC().Sub(time.Unix(int64(p.Start), 0))
|
|
||||||
perEntry := fromStart / time.Duration(p.Current)
|
|
||||||
left := time.Duration(p.Total-p.Current) * perEntry
|
|
||||||
left = (left / time.Second) * time.Second
|
|
||||||
|
|
||||||
if width > 50 {
|
|
||||||
timeLeftBox = " " + left.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pbBox + numbersBox + timeLeftBox
|
|
||||||
}
|
|
||||||
|
|
||||||
type JSONMessage struct {
|
|
||||||
Stream string `json:"stream,omitempty"`
|
|
||||||
Status string `json:"status,omitempty"`
|
|
||||||
Progress *JSONProgress `json:"progressDetail,omitempty"`
|
|
||||||
ProgressMessage string `json:"progress,omitempty"` //deprecated
|
|
||||||
ID string `json:"id,omitempty"`
|
|
||||||
From string `json:"from,omitempty"`
|
|
||||||
Time int64 `json:"time,omitempty"`
|
|
||||||
Error *JSONError `json:"errorDetail,omitempty"`
|
|
||||||
ErrorMessage string `json:"error,omitempty"` //deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
|
|
||||||
if jm.Error != nil {
|
|
||||||
if jm.Error.Code == 401 {
|
|
||||||
return fmt.Errorf("Authentication is required.")
|
|
||||||
}
|
|
||||||
return jm.Error
|
|
||||||
}
|
|
||||||
var endl string
|
|
||||||
if isTerminal && jm.Stream == "" && jm.Progress != nil {
|
|
||||||
// <ESC>[2K = erase entire current line
|
|
||||||
fmt.Fprintf(out, "%c[2K\r", 27)
|
|
||||||
endl = "\r"
|
|
||||||
} else if jm.Progress != nil { //disable progressbar in non-terminal
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if jm.Time != 0 {
|
|
||||||
fmt.Fprintf(out, "%s ", time.Unix(jm.Time, 0).Format(timeutils.RFC3339NanoFixed))
|
|
||||||
}
|
|
||||||
if jm.ID != "" {
|
|
||||||
fmt.Fprintf(out, "%s: ", jm.ID)
|
|
||||||
}
|
|
||||||
if jm.From != "" {
|
|
||||||
fmt.Fprintf(out, "(from %s) ", jm.From)
|
|
||||||
}
|
|
||||||
if jm.Progress != nil {
|
|
||||||
fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl)
|
|
||||||
} else if jm.ProgressMessage != "" { //deprecated
|
|
||||||
fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl)
|
|
||||||
} else if jm.Stream != "" {
|
|
||||||
fmt.Fprintf(out, "%s%s", jm.Stream, endl)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(out, "%s%s\n", jm.Status, endl)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool) error {
|
|
||||||
var (
|
|
||||||
dec = json.NewDecoder(in)
|
|
||||||
ids = make(map[string]int)
|
|
||||||
diff = 0
|
|
||||||
)
|
|
||||||
for {
|
|
||||||
var jm JSONMessage
|
|
||||||
if err := dec.Decode(&jm); err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if jm.Progress != nil {
|
|
||||||
jm.Progress.terminalFd = terminalFd
|
|
||||||
}
|
|
||||||
if jm.ID != "" && (jm.Progress != nil || jm.ProgressMessage != "") {
|
|
||||||
line, ok := ids[jm.ID]
|
|
||||||
if !ok {
|
|
||||||
line = len(ids)
|
|
||||||
ids[jm.ID] = line
|
|
||||||
if isTerminal {
|
|
||||||
fmt.Fprintf(out, "\n")
|
|
||||||
}
|
|
||||||
diff = 0
|
|
||||||
} else {
|
|
||||||
diff = len(ids) - line
|
|
||||||
}
|
|
||||||
if jm.ID != "" && isTerminal {
|
|
||||||
// <ESC>[{diff}A = move cursor up diff rows
|
|
||||||
fmt.Fprintf(out, "%c[%dA", 27, diff)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := jm.Display(out, isTerminal)
|
|
||||||
if jm.ID != "" && isTerminal {
|
|
||||||
// <ESC>[{diff}B = move cursor down diff rows
|
|
||||||
fmt.Fprintf(out, "%c[%dB", 27, diff)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
38
Godeps/_workspace/src/github.com/dotcloud/docker/utils/jsonmessage_test.go
generated
vendored
38
Godeps/_workspace/src/github.com/dotcloud/docker/utils/jsonmessage_test.go
generated
vendored
@ -1,38 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
|
||||||
je := JSONError{404, "Not found"}
|
|
||||||
if je.Error() != "Not found" {
|
|
||||||
t.Fatalf("Expected 'Not found' got '%s'", je.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProgress(t *testing.T) {
|
|
||||||
jp := JSONProgress{}
|
|
||||||
if jp.String() != "" {
|
|
||||||
t.Fatalf("Expected empty string, got '%s'", jp.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := " 1 B"
|
|
||||||
jp2 := JSONProgress{Current: 1}
|
|
||||||
if jp2.String() != expected {
|
|
||||||
t.Fatalf("Expected %q, got %q", expected, jp2.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
expected = "[=========================> ] 50 B/100 B"
|
|
||||||
jp3 := JSONProgress{Current: 50, Total: 100}
|
|
||||||
if jp3.String() != expected {
|
|
||||||
t.Fatalf("Expected %q, got %q", expected, jp3.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// this number can't be negetive gh#7136
|
|
||||||
expected = "[==============================================================>] 50 B/40 B"
|
|
||||||
jp4 := JSONProgress{Current: 50, Total: 40}
|
|
||||||
if jp4.String() != expected {
|
|
||||||
t.Fatalf("Expected %q, got %q", expected, jp4.String())
|
|
||||||
}
|
|
||||||
}
|
|
55
Godeps/_workspace/src/github.com/dotcloud/docker/utils/progressreader.go
generated
vendored
55
Godeps/_workspace/src/github.com/dotcloud/docker/utils/progressreader.go
generated
vendored
@ -1,55 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reader with progress bar
|
|
||||||
type progressReader struct {
|
|
||||||
reader io.ReadCloser // Stream to read from
|
|
||||||
output io.Writer // Where to send progress bar to
|
|
||||||
progress JSONProgress
|
|
||||||
lastUpdate int // How many bytes read at least update
|
|
||||||
ID string
|
|
||||||
action string
|
|
||||||
sf *StreamFormatter
|
|
||||||
newLine bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *progressReader) Read(p []byte) (n int, err error) {
|
|
||||||
read, err := r.reader.Read(p)
|
|
||||||
r.progress.Current += read
|
|
||||||
updateEvery := 1024 * 512 //512kB
|
|
||||||
if r.progress.Total > 0 {
|
|
||||||
// Update progress for every 1% read if 1% < 512kB
|
|
||||||
if increment := int(0.01 * float64(r.progress.Total)); increment < updateEvery {
|
|
||||||
updateEvery = increment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r.progress.Current-r.lastUpdate > updateEvery || err != nil {
|
|
||||||
r.output.Write(r.sf.FormatProgress(r.ID, r.action, &r.progress))
|
|
||||||
r.lastUpdate = r.progress.Current
|
|
||||||
}
|
|
||||||
// Send newline when complete
|
|
||||||
if r.newLine && err != nil && read == 0 {
|
|
||||||
r.output.Write(r.sf.FormatStatus("", ""))
|
|
||||||
}
|
|
||||||
return read, err
|
|
||||||
}
|
|
||||||
func (r *progressReader) Close() error {
|
|
||||||
r.progress.Current = r.progress.Total
|
|
||||||
r.output.Write(r.sf.FormatProgress(r.ID, r.action, &r.progress))
|
|
||||||
return r.reader.Close()
|
|
||||||
}
|
|
||||||
func ProgressReader(r io.ReadCloser, size int, output io.Writer, sf *StreamFormatter, newline bool, ID, action string) *progressReader {
|
|
||||||
return &progressReader{
|
|
||||||
reader: r,
|
|
||||||
output: NewWriteFlusher(output),
|
|
||||||
ID: ID,
|
|
||||||
action: action,
|
|
||||||
progress: JSONProgress{Total: size, Start: time.Now().UTC().Unix()},
|
|
||||||
sf: sf,
|
|
||||||
newLine: newline,
|
|
||||||
}
|
|
||||||
}
|
|
16
Godeps/_workspace/src/github.com/dotcloud/docker/utils/random.go
generated
vendored
16
Godeps/_workspace/src/github.com/dotcloud/docker/utils/random.go
generated
vendored
@ -1,16 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func RandomString() string {
|
|
||||||
id := make([]byte, 32)
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(rand.Reader, id); err != nil {
|
|
||||||
panic(err) // This shouldn't happen
|
|
||||||
}
|
|
||||||
return hex.EncodeToString(id)
|
|
||||||
}
|
|
112
Godeps/_workspace/src/github.com/dotcloud/docker/utils/streamformatter.go
generated
vendored
112
Godeps/_workspace/src/github.com/dotcloud/docker/utils/streamformatter.go
generated
vendored
@ -1,112 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type StreamFormatter struct {
|
|
||||||
json bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewStreamFormatter(json bool) *StreamFormatter {
|
|
||||||
return &StreamFormatter{json}
|
|
||||||
}
|
|
||||||
|
|
||||||
const streamNewline = "\r\n"
|
|
||||||
|
|
||||||
var streamNewlineBytes = []byte(streamNewline)
|
|
||||||
|
|
||||||
func (sf *StreamFormatter) FormatStream(str string) []byte {
|
|
||||||
if sf.json {
|
|
||||||
b, err := json.Marshal(&JSONMessage{Stream: str})
|
|
||||||
if err != nil {
|
|
||||||
return sf.FormatError(err)
|
|
||||||
}
|
|
||||||
return append(b, streamNewlineBytes...)
|
|
||||||
}
|
|
||||||
return []byte(str + "\r")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf *StreamFormatter) FormatStatus(id, format string, a ...interface{}) []byte {
|
|
||||||
str := fmt.Sprintf(format, a...)
|
|
||||||
if sf.json {
|
|
||||||
b, err := json.Marshal(&JSONMessage{ID: id, Status: str})
|
|
||||||
if err != nil {
|
|
||||||
return sf.FormatError(err)
|
|
||||||
}
|
|
||||||
return append(b, streamNewlineBytes...)
|
|
||||||
}
|
|
||||||
return []byte(str + streamNewline)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf *StreamFormatter) FormatError(err error) []byte {
|
|
||||||
if sf.json {
|
|
||||||
jsonError, ok := err.(*JSONError)
|
|
||||||
if !ok {
|
|
||||||
jsonError = &JSONError{Message: err.Error()}
|
|
||||||
}
|
|
||||||
if b, err := json.Marshal(&JSONMessage{Error: jsonError, ErrorMessage: err.Error()}); err == nil {
|
|
||||||
return append(b, streamNewlineBytes...)
|
|
||||||
}
|
|
||||||
return []byte("{\"error\":\"format error\"}" + streamNewline)
|
|
||||||
}
|
|
||||||
return []byte("Error: " + err.Error() + streamNewline)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf *StreamFormatter) FormatProgress(id, action string, progress *JSONProgress) []byte {
|
|
||||||
if progress == nil {
|
|
||||||
progress = &JSONProgress{}
|
|
||||||
}
|
|
||||||
if sf.json {
|
|
||||||
|
|
||||||
b, err := json.Marshal(&JSONMessage{
|
|
||||||
Status: action,
|
|
||||||
ProgressMessage: progress.String(),
|
|
||||||
Progress: progress,
|
|
||||||
ID: id,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
endl := "\r"
|
|
||||||
if progress.String() == "" {
|
|
||||||
endl += "\n"
|
|
||||||
}
|
|
||||||
return []byte(action + " " + progress.String() + endl)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf *StreamFormatter) Json() bool {
|
|
||||||
return sf.json
|
|
||||||
}
|
|
||||||
|
|
||||||
type StdoutFormater struct {
|
|
||||||
io.Writer
|
|
||||||
*StreamFormatter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf *StdoutFormater) Write(buf []byte) (int, error) {
|
|
||||||
formattedBuf := sf.StreamFormatter.FormatStream(string(buf))
|
|
||||||
n, err := sf.Writer.Write(formattedBuf)
|
|
||||||
if n != len(formattedBuf) {
|
|
||||||
return n, io.ErrShortWrite
|
|
||||||
}
|
|
||||||
return len(buf), err
|
|
||||||
}
|
|
||||||
|
|
||||||
type StderrFormater struct {
|
|
||||||
io.Writer
|
|
||||||
*StreamFormatter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sf *StderrFormater) Write(buf []byte) (int, error) {
|
|
||||||
formattedBuf := sf.StreamFormatter.FormatStream("\033[91m" + string(buf) + "\033[0m")
|
|
||||||
n, err := sf.Writer.Write(formattedBuf)
|
|
||||||
if n != len(formattedBuf) {
|
|
||||||
return n, io.ErrShortWrite
|
|
||||||
}
|
|
||||||
return len(buf), err
|
|
||||||
}
|
|
67
Godeps/_workspace/src/github.com/dotcloud/docker/utils/streamformatter_test.go
generated
vendored
67
Godeps/_workspace/src/github.com/dotcloud/docker/utils/streamformatter_test.go
generated
vendored
@ -1,67 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFormatStream(t *testing.T) {
|
|
||||||
sf := NewStreamFormatter(true)
|
|
||||||
res := sf.FormatStream("stream")
|
|
||||||
if string(res) != `{"stream":"stream"}`+"\r\n" {
|
|
||||||
t.Fatalf("%q", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatStatus(t *testing.T) {
|
|
||||||
sf := NewStreamFormatter(true)
|
|
||||||
res := sf.FormatStatus("ID", "%s%d", "a", 1)
|
|
||||||
if string(res) != `{"status":"a1","id":"ID"}`+"\r\n" {
|
|
||||||
t.Fatalf("%q", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatSimpleError(t *testing.T) {
|
|
||||||
sf := NewStreamFormatter(true)
|
|
||||||
res := sf.FormatError(errors.New("Error for formatter"))
|
|
||||||
if string(res) != `{"errorDetail":{"message":"Error for formatter"},"error":"Error for formatter"}`+"\r\n" {
|
|
||||||
t.Fatalf("%q", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatJSONError(t *testing.T) {
|
|
||||||
sf := NewStreamFormatter(true)
|
|
||||||
err := &JSONError{Code: 50, Message: "Json error"}
|
|
||||||
res := sf.FormatError(err)
|
|
||||||
if string(res) != `{"errorDetail":{"code":50,"message":"Json error"},"error":"Json error"}`+"\r\n" {
|
|
||||||
t.Fatalf("%q", res)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatProgress(t *testing.T) {
|
|
||||||
sf := NewStreamFormatter(true)
|
|
||||||
progress := &JSONProgress{
|
|
||||||
Current: 15,
|
|
||||||
Total: 30,
|
|
||||||
Start: 1,
|
|
||||||
}
|
|
||||||
res := sf.FormatProgress("id", "action", progress)
|
|
||||||
msg := &JSONMessage{}
|
|
||||||
if err := json.Unmarshal(res, msg); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if msg.ID != "id" {
|
|
||||||
t.Fatalf("ID must be 'id', got: %s", msg.ID)
|
|
||||||
}
|
|
||||||
if msg.Status != "action" {
|
|
||||||
t.Fatalf("Status must be 'action', got: %s", msg.Status)
|
|
||||||
}
|
|
||||||
if msg.ProgressMessage != progress.String() {
|
|
||||||
t.Fatalf("ProgressMessage must be %s, got: %s", progress.String(), msg.ProgressMessage)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(msg.Progress, progress) {
|
|
||||||
t.Fatal("Original progress not equals progress from FormatProgress")
|
|
||||||
}
|
|
||||||
}
|
|
26
Godeps/_workspace/src/github.com/dotcloud/docker/utils/timeoutconn.go
generated
vendored
26
Godeps/_workspace/src/github.com/dotcloud/docker/utils/timeoutconn.go
generated
vendored
@ -1,26 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewTimeoutConn(conn net.Conn, timeout time.Duration) net.Conn {
|
|
||||||
return &TimeoutConn{conn, timeout}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A net.Conn that sets a deadline for every Read or Write operation
|
|
||||||
type TimeoutConn struct {
|
|
||||||
net.Conn
|
|
||||||
timeout time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TimeoutConn) Read(b []byte) (int, error) {
|
|
||||||
if c.timeout > 0 {
|
|
||||||
err := c.Conn.SetReadDeadline(time.Now().Add(c.timeout))
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.Conn.Read(b)
|
|
||||||
}
|
|
33
Godeps/_workspace/src/github.com/dotcloud/docker/utils/timeoutconn_test.go
generated
vendored
33
Godeps/_workspace/src/github.com/dotcloud/docker/utils/timeoutconn_test.go
generated
vendored
@ -1,33 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTimeoutConnRead(t *testing.T) {
|
|
||||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintln(w, "hello")
|
|
||||||
}))
|
|
||||||
defer ts.Close()
|
|
||||||
conn, err := net.Dial("tcp", ts.URL[7:])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create connection to %q: %v", ts.URL, err)
|
|
||||||
}
|
|
||||||
tconn := NewTimeoutConn(conn, 1*time.Second)
|
|
||||||
|
|
||||||
if _, err = bufio.NewReader(tconn).ReadString('\n'); err == nil {
|
|
||||||
t.Fatalf("expected timeout error, got none")
|
|
||||||
}
|
|
||||||
if _, err := fmt.Fprintf(tconn, "GET / HTTP/1.0\r\n\r\n"); err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
if _, err = bufio.NewReader(tconn).ReadString('\n'); err != nil {
|
|
||||||
t.Errorf("unexpected error: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
12
Godeps/_workspace/src/github.com/dotcloud/docker/utils/tmpdir.go
generated
vendored
12
Godeps/_workspace/src/github.com/dotcloud/docker/utils/tmpdir.go
generated
vendored
@ -1,12 +0,0 @@
|
|||||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TempDir returns the default directory to use for temporary files.
|
|
||||||
func TempDir(rootdir string) (string error) {
|
|
||||||
return os.TempDir(), nil
|
|
||||||
}
|
|
18
Godeps/_workspace/src/github.com/dotcloud/docker/utils/tmpdir_unix.go
generated
vendored
18
Godeps/_workspace/src/github.com/dotcloud/docker/utils/tmpdir_unix.go
generated
vendored
@ -1,18 +0,0 @@
|
|||||||
// +build darwin dragonfly freebsd linux netbsd openbsd
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TempDir returns the default directory to use for temporary files.
|
|
||||||
func TempDir(rootDir string) (string, error) {
|
|
||||||
var tmpDir string
|
|
||||||
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
|
|
||||||
tmpDir = filepath.Join(rootDir, "tmp")
|
|
||||||
}
|
|
||||||
err := os.MkdirAll(tmpDir, 0700)
|
|
||||||
return tmpDir, err
|
|
||||||
}
|
|
593
Godeps/_workspace/src/github.com/dotcloud/docker/utils/utils.go
generated
vendored
593
Godeps/_workspace/src/github.com/dotcloud/docker/utils/utils.go
generated
vendored
@ -1,593 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/sha1"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/docker/docker/dockerversion"
|
|
||||||
"github.com/docker/docker/pkg/ioutils"
|
|
||||||
"github.com/docker/docker/pkg/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type KeyValuePair struct {
|
|
||||||
Key string
|
|
||||||
Value string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go is a basic promise implementation: it wraps calls a function in a goroutine,
|
|
||||||
// and returns a channel which will later return the function's return value.
|
|
||||||
func Go(f func() error) chan error {
|
|
||||||
ch := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
ch <- f()
|
|
||||||
}()
|
|
||||||
return ch
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request a given URL and return an io.Reader
|
|
||||||
func Download(url string) (resp *http.Response, err error) {
|
|
||||||
if resp, err = http.Get(url); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if resp.StatusCode >= 400 {
|
|
||||||
return nil, fmt.Errorf("Got HTTP status code >= 400: %s", resp.Status)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Trunc(s string, maxlen int) string {
|
|
||||||
if len(s) <= maxlen {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return s[:maxlen]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out the absolute path of our own binary (if it's still around).
|
|
||||||
func SelfPath() string {
|
|
||||||
path, err := exec.LookPath(os.Args[0])
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if execErr, ok := err.(*exec.Error); ok && os.IsNotExist(execErr.Err) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
path, err = filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
func dockerInitSha1(target string) string {
|
|
||||||
f, err := os.Open(target)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
h := sha1.New()
|
|
||||||
_, err = io.Copy(h, f)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValidDockerInitPath(target string, selfPath string) bool { // target and selfPath should be absolute (InitPath and SelfPath already do this)
|
|
||||||
if target == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if dockerversion.IAMSTATIC {
|
|
||||||
if selfPath == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if target == selfPath {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
targetFileInfo, err := os.Lstat(target)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
selfPathFileInfo, err := os.Lstat(selfPath)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return os.SameFile(targetFileInfo, selfPathFileInfo)
|
|
||||||
}
|
|
||||||
return dockerversion.INITSHA1 != "" && dockerInitSha1(target) == dockerversion.INITSHA1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out the path of our dockerinit (which may be SelfPath())
|
|
||||||
func DockerInitPath(localCopy string) string {
|
|
||||||
selfPath := SelfPath()
|
|
||||||
if isValidDockerInitPath(selfPath, selfPath) {
|
|
||||||
// if we're valid, don't bother checking anything else
|
|
||||||
return selfPath
|
|
||||||
}
|
|
||||||
var possibleInits = []string{
|
|
||||||
localCopy,
|
|
||||||
dockerversion.INITPATH,
|
|
||||||
filepath.Join(filepath.Dir(selfPath), "dockerinit"),
|
|
||||||
|
|
||||||
// FHS 3.0 Draft: "/usr/libexec includes internal binaries that are not intended to be executed directly by users or shell scripts. Applications may use a single subdirectory under /usr/libexec."
|
|
||||||
// http://www.linuxbase.org/betaspecs/fhs/fhs.html#usrlibexec
|
|
||||||
"/usr/libexec/docker/dockerinit",
|
|
||||||
"/usr/local/libexec/docker/dockerinit",
|
|
||||||
|
|
||||||
// FHS 2.3: "/usr/lib includes object files, libraries, and internal binaries that are not intended to be executed directly by users or shell scripts."
|
|
||||||
// http://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLIBLIBRARIESFORPROGRAMMINGANDPA
|
|
||||||
"/usr/lib/docker/dockerinit",
|
|
||||||
"/usr/local/lib/docker/dockerinit",
|
|
||||||
}
|
|
||||||
for _, dockerInit := range possibleInits {
|
|
||||||
if dockerInit == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
path, err := exec.LookPath(dockerInit)
|
|
||||||
if err == nil {
|
|
||||||
path, err = filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
// LookPath already validated that this file exists and is executable (following symlinks), so how could Abs fail?
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if isValidDockerInitPath(path, selfPath) {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTotalUsedFds() int {
|
|
||||||
if fds, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
|
|
||||||
log.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
|
|
||||||
} else {
|
|
||||||
return len(fds)
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// TruncateID returns a shorthand version of a string identifier for convenience.
|
|
||||||
// A collision with other shorthands is very unlikely, but possible.
|
|
||||||
// In case of a collision a lookup with TruncIndex.Get() will fail, and the caller
|
|
||||||
// will need to use a langer prefix, or the full-length Id.
|
|
||||||
func TruncateID(id string) string {
|
|
||||||
shortLen := 12
|
|
||||||
if len(id) < shortLen {
|
|
||||||
shortLen = len(id)
|
|
||||||
}
|
|
||||||
return id[:shortLen]
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateRandomID returns an unique id
|
|
||||||
func GenerateRandomID() string {
|
|
||||||
for {
|
|
||||||
id := make([]byte, 32)
|
|
||||||
if _, err := io.ReadFull(rand.Reader, id); err != nil {
|
|
||||||
panic(err) // This shouldn't happen
|
|
||||||
}
|
|
||||||
value := hex.EncodeToString(id)
|
|
||||||
// if we try to parse the truncated for as an int and we don't have
|
|
||||||
// an error then the value is all numberic and causes issues when
|
|
||||||
// used as a hostname. ref #3869
|
|
||||||
if _, err := strconv.ParseInt(TruncateID(value), 10, 64); err == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateID(id string) error {
|
|
||||||
if id == "" {
|
|
||||||
return fmt.Errorf("Id can't be empty")
|
|
||||||
}
|
|
||||||
if strings.Contains(id, ":") {
|
|
||||||
return fmt.Errorf("Invalid character in id: ':'")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Code c/c from io.Copy() modified to handle escape sequence
|
|
||||||
func CopyEscapable(dst io.Writer, src io.ReadCloser) (written int64, err error) {
|
|
||||||
buf := make([]byte, 32*1024)
|
|
||||||
for {
|
|
||||||
nr, er := src.Read(buf)
|
|
||||||
if nr > 0 {
|
|
||||||
// ---- Docker addition
|
|
||||||
// char 16 is C-p
|
|
||||||
if nr == 1 && buf[0] == 16 {
|
|
||||||
nr, er = src.Read(buf)
|
|
||||||
// char 17 is C-q
|
|
||||||
if nr == 1 && buf[0] == 17 {
|
|
||||||
if err := src.Close(); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ---- End of docker
|
|
||||||
nw, ew := dst.Write(buf[0:nr])
|
|
||||||
if nw > 0 {
|
|
||||||
written += int64(nw)
|
|
||||||
}
|
|
||||||
if ew != nil {
|
|
||||||
err = ew
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nr != nw {
|
|
||||||
err = io.ErrShortWrite
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if er == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if er != nil {
|
|
||||||
err = er
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return written, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func HashData(src io.Reader) (string, error) {
|
|
||||||
h := sha256.New()
|
|
||||||
if _, err := io.Copy(h, src); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return "sha256:" + hex.EncodeToString(h.Sum(nil)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: this is deprecated by CopyWithTar in archive.go
|
|
||||||
func CopyDirectory(source, dest string) error {
|
|
||||||
if output, err := exec.Command("cp", "-ra", source, dest).CombinedOutput(); err != nil {
|
|
||||||
return fmt.Errorf("Error copy: %s (%s)", err, output)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type WriteFlusher struct {
|
|
||||||
sync.Mutex
|
|
||||||
w io.Writer
|
|
||||||
flusher http.Flusher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wf *WriteFlusher) Write(b []byte) (n int, err error) {
|
|
||||||
wf.Lock()
|
|
||||||
defer wf.Unlock()
|
|
||||||
n, err = wf.w.Write(b)
|
|
||||||
wf.flusher.Flush()
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush the stream immediately.
|
|
||||||
func (wf *WriteFlusher) Flush() {
|
|
||||||
wf.Lock()
|
|
||||||
defer wf.Unlock()
|
|
||||||
wf.flusher.Flush()
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewWriteFlusher(w io.Writer) *WriteFlusher {
|
|
||||||
var flusher http.Flusher
|
|
||||||
if f, ok := w.(http.Flusher); ok {
|
|
||||||
flusher = f
|
|
||||||
} else {
|
|
||||||
flusher = &ioutils.NopFlusher{}
|
|
||||||
}
|
|
||||||
return &WriteFlusher{w: w, flusher: flusher}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHTTPRequestError(msg string, res *http.Response) error {
|
|
||||||
return &JSONError{
|
|
||||||
Message: msg,
|
|
||||||
Code: res.StatusCode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsURL(str string) bool {
|
|
||||||
return strings.HasPrefix(str, "http://") || strings.HasPrefix(str, "https://")
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsGIT(str string) bool {
|
|
||||||
return strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "github.com/") || strings.HasPrefix(str, "git@github.com:") || (strings.HasSuffix(str, ".git") && IsURL(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckLocalDns looks into the /etc/resolv.conf,
|
|
||||||
// it returns true if there is a local nameserver or if there is no nameserver.
|
|
||||||
func CheckLocalDns(resolvConf []byte) bool {
|
|
||||||
for _, line := range GetLines(resolvConf, []byte("#")) {
|
|
||||||
if !bytes.Contains(line, []byte("nameserver")) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, ip := range [][]byte{
|
|
||||||
[]byte("127.0.0.1"),
|
|
||||||
[]byte("127.0.1.1"),
|
|
||||||
} {
|
|
||||||
if bytes.Contains(line, ip) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLines parses input into lines and strips away comments.
|
|
||||||
func GetLines(input []byte, commentMarker []byte) [][]byte {
|
|
||||||
lines := bytes.Split(input, []byte("\n"))
|
|
||||||
var output [][]byte
|
|
||||||
for _, currentLine := range lines {
|
|
||||||
var commentIndex = bytes.Index(currentLine, commentMarker)
|
|
||||||
if commentIndex == -1 {
|
|
||||||
output = append(output, currentLine)
|
|
||||||
} else {
|
|
||||||
output = append(output, currentLine[:commentIndex])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output
|
|
||||||
}
|
|
||||||
|
|
||||||
// An StatusError reports an unsuccessful exit by a command.
|
|
||||||
type StatusError struct {
|
|
||||||
Status string
|
|
||||||
StatusCode int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *StatusError) Error() string {
|
|
||||||
return fmt.Sprintf("Status: %s, Code: %d", e.Status, e.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func quote(word string, buf *bytes.Buffer) {
|
|
||||||
// Bail out early for "simple" strings
|
|
||||||
if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
|
|
||||||
buf.WriteString(word)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString("'")
|
|
||||||
|
|
||||||
for i := 0; i < len(word); i++ {
|
|
||||||
b := word[i]
|
|
||||||
if b == '\'' {
|
|
||||||
// Replace literal ' with a close ', a \', and a open '
|
|
||||||
buf.WriteString("'\\''")
|
|
||||||
} else {
|
|
||||||
buf.WriteByte(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.WriteString("'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Take a list of strings and escape them so they will be handled right
|
|
||||||
// when passed as arguments to an program via a shell
|
|
||||||
func ShellQuoteArguments(args []string) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for i, arg := range args {
|
|
||||||
if i != 0 {
|
|
||||||
buf.WriteByte(' ')
|
|
||||||
}
|
|
||||||
quote(arg, &buf)
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
var globalTestID string
|
|
||||||
|
|
||||||
// TestDirectory creates a new temporary directory and returns its path.
|
|
||||||
// The contents of directory at path `templateDir` is copied into the
|
|
||||||
// new directory.
|
|
||||||
func TestDirectory(templateDir string) (dir string, err error) {
|
|
||||||
if globalTestID == "" {
|
|
||||||
globalTestID = RandomString()[:4]
|
|
||||||
}
|
|
||||||
prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, GetCallerName(2))
|
|
||||||
if prefix == "" {
|
|
||||||
prefix = "docker-test-"
|
|
||||||
}
|
|
||||||
dir, err = ioutil.TempDir("", prefix)
|
|
||||||
if err = os.Remove(dir); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if templateDir != "" {
|
|
||||||
if err = CopyDirectory(templateDir, dir); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCallerName introspects the call stack and returns the name of the
|
|
||||||
// function `depth` levels down in the stack.
|
|
||||||
func GetCallerName(depth int) string {
|
|
||||||
// Use the caller function name as a prefix.
|
|
||||||
// This helps trace temp directories back to their test.
|
|
||||||
pc, _, _, _ := runtime.Caller(depth + 1)
|
|
||||||
callerLongName := runtime.FuncForPC(pc).Name()
|
|
||||||
parts := strings.Split(callerLongName, ".")
|
|
||||||
callerShortName := parts[len(parts)-1]
|
|
||||||
return callerShortName
|
|
||||||
}
|
|
||||||
|
|
||||||
func CopyFile(src, dst string) (int64, error) {
|
|
||||||
if src == dst {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
sf, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer sf.Close()
|
|
||||||
if err := os.Remove(dst); err != nil && !os.IsNotExist(err) {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
df, err := os.Create(dst)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer df.Close()
|
|
||||||
return io.Copy(df, sf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplaceOrAppendValues returns the defaults with the overrides either
|
|
||||||
// replaced by env key or appended to the list
|
|
||||||
func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
|
|
||||||
cache := make(map[string]int, len(defaults))
|
|
||||||
for i, e := range defaults {
|
|
||||||
parts := strings.SplitN(e, "=", 2)
|
|
||||||
cache[parts[0]] = i
|
|
||||||
}
|
|
||||||
for _, value := range overrides {
|
|
||||||
parts := strings.SplitN(value, "=", 2)
|
|
||||||
if i, exists := cache[parts[0]]; exists {
|
|
||||||
defaults[i] = value
|
|
||||||
} else {
|
|
||||||
defaults = append(defaults, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadSymlinkedDirectory returns the target directory of a symlink.
|
|
||||||
// The target of the symbolic link may not be a file.
|
|
||||||
func ReadSymlinkedDirectory(path string) (string, error) {
|
|
||||||
var realPath string
|
|
||||||
var err error
|
|
||||||
if realPath, err = filepath.Abs(path); err != nil {
|
|
||||||
return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
|
|
||||||
}
|
|
||||||
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
|
||||||
return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
|
|
||||||
}
|
|
||||||
realPathInfo, err := os.Stat(realPath)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
|
|
||||||
}
|
|
||||||
if !realPathInfo.Mode().IsDir() {
|
|
||||||
return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
|
|
||||||
}
|
|
||||||
return realPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TreeSize walks a directory tree and returns its total size in bytes.
|
|
||||||
func TreeSize(dir string) (size int64, err error) {
|
|
||||||
data := make(map[uint64]struct{})
|
|
||||||
err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, e error) error {
|
|
||||||
// Ignore directory sizes
|
|
||||||
if fileInfo == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
s := fileInfo.Size()
|
|
||||||
if fileInfo.IsDir() || s == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check inode to handle hard links correctly
|
|
||||||
inode := fileInfo.Sys().(*syscall.Stat_t).Ino
|
|
||||||
// inode is not a uint64 on all platforms. Cast it to avoid issues.
|
|
||||||
if _, exists := data[uint64(inode)]; exists {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// inode is not a uint64 on all platforms. Cast it to avoid issues.
|
|
||||||
data[uint64(inode)] = struct{}{}
|
|
||||||
|
|
||||||
size += s
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateContextDirectory checks if all the contents of the directory
|
|
||||||
// can be read and returns an error if some files can't be read
|
|
||||||
// symlinks which point to non-existing files don't trigger an error
|
|
||||||
func ValidateContextDirectory(srcPath string, excludes []string) error {
|
|
||||||
return filepath.Walk(filepath.Join(srcPath, "."), func(filePath string, f os.FileInfo, err error) error {
|
|
||||||
// skip this directory/file if it's not in the path, it won't get added to the context
|
|
||||||
if relFilePath, err := filepath.Rel(srcPath, filePath); err != nil {
|
|
||||||
return err
|
|
||||||
} else if skip, err := Matches(relFilePath, excludes); err != nil {
|
|
||||||
return err
|
|
||||||
} else if skip {
|
|
||||||
if f.IsDir() {
|
|
||||||
return filepath.SkipDir
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if os.IsPermission(err) {
|
|
||||||
return fmt.Errorf("can't stat '%s'", filePath)
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip checking if symlinks point to non-existing files, such symlinks can be useful
|
|
||||||
// also skip named pipes, because they hanging on open
|
|
||||||
if f.Mode()&(os.ModeSymlink|os.ModeNamedPipe) != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !f.IsDir() {
|
|
||||||
currentFile, err := os.Open(filePath)
|
|
||||||
if err != nil && os.IsPermission(err) {
|
|
||||||
return fmt.Errorf("no permission to read from '%s'", filePath)
|
|
||||||
}
|
|
||||||
currentFile.Close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func StringsContainsNoCase(slice []string, s string) bool {
|
|
||||||
for _, ss := range slice {
|
|
||||||
if strings.ToLower(s) == strings.ToLower(ss) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Matches returns true if relFilePath matches any of the patterns
|
|
||||||
func Matches(relFilePath string, patterns []string) (bool, error) {
|
|
||||||
for _, exclude := range patterns {
|
|
||||||
matched, err := filepath.Match(exclude, relFilePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Error matching: %s (pattern: %s)", relFilePath, exclude)
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if matched {
|
|
||||||
if filepath.Clean(relFilePath) == "." {
|
|
||||||
log.Errorf("Can't exclude whole path, excluding pattern: %s", exclude)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
log.Debugf("Skipping excluded path: %s", relFilePath)
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
|
128
Godeps/_workspace/src/github.com/dotcloud/docker/utils/utils_test.go
generated
vendored
128
Godeps/_workspace/src/github.com/dotcloud/docker/utils/utils_test.go
generated
vendored
@ -1,128 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCheckLocalDns(t *testing.T) {
|
|
||||||
for resolv, result := range map[string]bool{`# Dynamic
|
|
||||||
nameserver 10.0.2.3
|
|
||||||
search docker.com`: false,
|
|
||||||
`# Dynamic
|
|
||||||
#nameserver 127.0.0.1
|
|
||||||
nameserver 10.0.2.3
|
|
||||||
search docker.com`: false,
|
|
||||||
`# Dynamic
|
|
||||||
nameserver 10.0.2.3 #not used 127.0.1.1
|
|
||||||
search docker.com`: false,
|
|
||||||
`# Dynamic
|
|
||||||
#nameserver 10.0.2.3
|
|
||||||
#search docker.com`: true,
|
|
||||||
`# Dynamic
|
|
||||||
nameserver 127.0.0.1
|
|
||||||
search docker.com`: true,
|
|
||||||
`# Dynamic
|
|
||||||
nameserver 127.0.1.1
|
|
||||||
search docker.com`: true,
|
|
||||||
`# Dynamic
|
|
||||||
`: true,
|
|
||||||
``: true,
|
|
||||||
} {
|
|
||||||
if CheckLocalDns([]byte(resolv)) != result {
|
|
||||||
t.Fatalf("Wrong local dns detection: {%s} should be %v", resolv, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func TestReplaceAndAppendEnvVars(t *testing.T) {
|
|
||||||
var (
|
|
||||||
d = []string{"HOME=/"}
|
|
||||||
o = []string{"HOME=/root", "TERM=xterm"}
|
|
||||||
)
|
|
||||||
|
|
||||||
env := ReplaceOrAppendEnvValues(d, o)
|
|
||||||
if len(env) != 2 {
|
|
||||||
t.Fatalf("expected len of 2 got %d", len(env))
|
|
||||||
}
|
|
||||||
if env[0] != "HOME=/root" {
|
|
||||||
t.Fatalf("expected HOME=/root got '%s'", env[0])
|
|
||||||
}
|
|
||||||
if env[1] != "TERM=xterm" {
|
|
||||||
t.Fatalf("expected TERM=xterm got '%s'", env[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reading a symlink to a directory must return the directory
|
|
||||||
func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
|
|
||||||
t.Errorf("failed to create directory: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
|
|
||||||
t.Errorf("failed to create symlink: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var path string
|
|
||||||
if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
|
|
||||||
t.Fatalf("failed to read symlink to directory: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if path != "/tmp/testReadSymlinkToExistingDirectory" {
|
|
||||||
t.Fatalf("symlink returned unexpected directory: %s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
|
|
||||||
t.Errorf("failed to remove temporary directory: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.Remove("/tmp/dirLinkTest"); err != nil {
|
|
||||||
t.Errorf("failed to remove symlink: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reading a non-existing symlink must fail
|
|
||||||
func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
|
|
||||||
var path string
|
|
||||||
var err error
|
|
||||||
if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
|
|
||||||
t.Fatalf("error expected for non-existing symlink")
|
|
||||||
}
|
|
||||||
|
|
||||||
if path != "" {
|
|
||||||
t.Fatalf("expected empty path, but '%s' was returned", path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reading a symlink to a file must fail
|
|
||||||
func TestReadSymlinkedDirectoryToFile(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var file *os.File
|
|
||||||
|
|
||||||
if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
|
|
||||||
t.Fatalf("failed to create file: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file.Close()
|
|
||||||
|
|
||||||
if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
|
|
||||||
t.Errorf("failed to create symlink: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var path string
|
|
||||||
if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
|
|
||||||
t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if path != "" {
|
|
||||||
t.Fatalf("path should've been empty: %s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
|
|
||||||
t.Errorf("failed to remove file: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.Remove("/tmp/fileLinkTest"); err != nil {
|
|
||||||
t.Errorf("failed to remove symlink: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,9 +13,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/pkg/stdcopy"
|
"github.com/docker/docker/pkg/stdcopy"
|
||||||
"github.com/dotcloud/docker/pkg/term"
|
"github.com/docker/docker/pkg/term"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dotcloud/docker/archive"
|
"github.com/docker/docker/archive"
|
||||||
"github.com/dotcloud/docker/pkg/parsers"
|
"github.com/docker/docker/pkg/parsers"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Images struct {
|
type Images struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user