Skip to content
This repository was archived by the owner on Mar 18, 2024. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions dockerclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import (
"strings"
"sync/atomic"
"time"

"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/term"
)

const (
Expand Down Expand Up @@ -525,21 +528,22 @@ func (client *DockerClient) Version() (*Version, error) {
return version, nil
}

func (client *DockerClient) PullImage(name string, auth *AuthConfig) error {
func (client *DockerClient) PullImage(name string, auth *AuthConfig, out ...io.Writer) (err error) {
v := url.Values{}
v.Set("fromImage", name)
uri := fmt.Sprintf("/%s/images/create?%s", APIVersion, v.Encode())
req, err := http.NewRequest("POST", client.URL.String()+uri, nil)
req, _ := http.NewRequest("POST", client.URL.String()+uri, nil)
if auth != nil {
encoded_auth, err := auth.encode()
if err != nil {
return err
}
req.Header.Add("X-Registry-Auth", encoded_auth)
}
resp, err := client.HTTPClient.Do(req)
var resp *http.Response
resp, err = client.HTTPClient.Do(req)
if err != nil {
return err
return
}

defer resp.Body.Close()
Expand All @@ -554,16 +558,39 @@ func (client *DockerClient) PullImage(name string, auth *AuthConfig) error {
return fmt.Errorf("%s", string(data))
}

errorReader := io.Reader(resp.Body)
var cliOut io.Writer
if len(out) > 0 {
cliOut = out[0]
}
if cliOut != nil {
pipeReader, pipeWriter := io.Pipe()
streamErrChan := make(chan error)
defer func() {
pipeWriter.Close()
if err == nil {
err = <-streamErrChan
}
}()
errorReader = io.TeeReader(resp.Body, pipeWriter)
go func() {
fd, isTerminalIn := term.GetFdInfo(cliOut)
streamErrChan <- jsonmessage.DisplayJSONMessagesStream(pipeReader, cliOut, fd, isTerminalIn)
}()
}
var finalObj map[string]interface{}
for decoder := json.NewDecoder(resp.Body); err == nil; err = decoder.Decode(&finalObj) {
for decoder := json.NewDecoder(errorReader); err == nil; err = decoder.Decode(&finalObj) {
}
if err != io.EOF {
return err
return
} else {
err = nil
}
if err, ok := finalObj["error"]; ok {
return fmt.Errorf("%v", err)
if errObj, ok := finalObj["error"]; ok {
err = fmt.Errorf("%v", errObj)
return
}
return nil
return
}

func (client *DockerClient) InspectImage(id string) (*ImageInfo, error) {
Expand Down
19 changes: 15 additions & 4 deletions dockerclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"reflect"
"strings"
"testing"
Expand All @@ -31,6 +32,16 @@ func testDockerClient(t *testing.T) *DockerClient {
return client
}

func ExampleDockerClient_PullImage() {
docker, err := NewDockerClient("unix:///var/run/docker.sock", nil)
if err != nil {
panic(err)
}
if err := docker.PullImage("busybox", nil, os.Stdout); err != nil {
panic(err)
}
}

func TestInfo(t *testing.T) {
client := testDockerClient(t)
info, err := client.Info()
Expand Down Expand Up @@ -70,14 +81,14 @@ func TestWait(t *testing.T) {

func TestPullImage(t *testing.T) {
client := testDockerClient(t)
err := client.PullImage("busybox", nil)
err := client.PullImage("busybox", nil) // old clients do not break on the API change
if err != nil {
t.Fatal("unable to pull busybox")
t.Fatal("unable to pull busybox: %v", err)
}

err = client.PullImage("haproxy", nil)
err = client.PullImage("haproxy", nil, os.Stderr) // io.Writer is optional
if err != nil {
t.Fatal("unable to pull haproxy")
t.Fatal("unable to pull haproxy: %v", err)
}

err = client.PullImage("wrongimg", nil)
Expand Down
2 changes: 1 addition & 1 deletion interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type Client interface {
StopAllMonitorStats()
TagImage(nameOrID string, repo string, tag string, force bool) error
Version() (*Version, error)
PullImage(name string, auth *AuthConfig) error
PullImage(name string, auth *AuthConfig, out ...io.Writer) error
LoadImage(reader io.Reader) error
RemoveContainer(id string, force, volumes bool) error
ListImages(all bool) ([]*Image, error)
Expand Down
4 changes: 2 additions & 2 deletions mockclient/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ func (client *MockClient) Version() (*dockerclient.Version, error) {
return args.Get(0).(*dockerclient.Version), args.Error(1)
}

func (client *MockClient) PullImage(name string, auth *dockerclient.AuthConfig) error {
args := client.Mock.Called(name, auth)
func (client *MockClient) PullImage(name string, auth *dockerclient.AuthConfig, out ...io.Writer) error {
args := client.Mock.Called(name, auth, out...)
return args.Error(0)
}

Expand Down
2 changes: 1 addition & 1 deletion nopclient/nop.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (client *NopClient) Version() (*dockerclient.Version, error) {
return nil, ErrNoEngine
}

func (client *NopClient) PullImage(name string, auth *dockerclient.AuthConfig) error {
func (client *NopClient) PullImage(name string, auth *dockerclient.AuthConfig, out ...io.Writer) error {
return ErrNoEngine
}

Expand Down