Refactor utility `MkBuildContext` to the more generic `archive.Generate`

This facilitates refactoring commands.go.

Docker-DCO-1.1-Signed-off-by: Solomon Hykes <solomon@docker.com> (github: shykes)
This commit is contained in:
Solomon Hykes 2014-02-12 15:10:41 -08:00
Родитель a7ecc3ea11
Коммит 9b56da78e0
4 изменённых файлов: 76 добавлений и 41 удалений

59
archive/wrap.go Normal file
Просмотреть файл

@ -0,0 +1,59 @@
package archive
import (
"archive/tar"
"bytes"
"io/ioutil"
)
// Generate generates a new archive from the content provided
// as input.
//
// `files` is a sequence of path/content pairs. A new file is
// added to the archive for each pair.
// If the last pair is incomplete, the file is created with an
// empty content. For example:
//
// Generate("foo.txt", "hello world", "emptyfile")
//
// The above call will return an archive with 2 files:
// * ./foo.txt with content "hello world"
// * ./empty with empty content
//
// FIXME: stream content instead of buffering
// FIXME: specify permissions and other archive metadata
func Generate(input ...string) (Archive, error) {
files := parseStringPairs(input...)
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
for _, file := range files {
name, content := file[0], file[1]
hdr := &tar.Header{
Name: name,
Size: int64(len(content)),
}
if err := tw.WriteHeader(hdr); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(content)); err != nil {
return nil, err
}
}
if err := tw.Close(); err != nil {
return nil, err
}
return ioutil.NopCloser(buf), nil
}
func parseStringPairs(input ...string) (output [][2]string) {
output = make([][2]string, 0, len(input)/2+1)
for i := 0; i < len(input); i += 2 {
var pair [2]string
pair[0] = input[i]
if i+1 < len(input) {
pair[1] = input[i+1]
}
output = append(output, pair)
}
return
}

Просмотреть файл

@ -1,7 +1,6 @@
package docker
import (
"archive/tar"
"bufio"
"bytes"
"encoding/base64"
@ -136,31 +135,6 @@ func (cli *DockerCli) CmdInsert(args ...string) error {
return cli.stream("POST", "/images/"+cmd.Arg(0)+"/insert?"+v.Encode(), nil, cli.out, nil)
}
// mkBuildContext returns an archive of an empty context with the contents
// of `dockerfile` at the path ./Dockerfile
func MkBuildContext(dockerfile string, files [][2]string) (archive.Archive, error) {
buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)
files = append(files, [2]string{"Dockerfile", dockerfile})
for _, file := range files {
name, content := file[0], file[1]
hdr := &tar.Header{
Name: name,
Size: int64(len(content)),
}
if err := tw.WriteHeader(hdr); err != nil {
return nil, err
}
if _, err := tw.Write([]byte(content)); err != nil {
return nil, err
}
}
if err := tw.Close(); err != nil {
return nil, err
}
return ioutil.NopCloser(buf), nil
}
func (cli *DockerCli) CmdBuild(args ...string) error {
cmd := cli.Subcmd("build", "[OPTIONS] PATH | URL | -", "Build a new container image from the source code at PATH")
tag := cmd.String([]string{"t", "-tag"}, "", "Repository name (and optionally a tag) to be applied to the resulting image in case of success")
@ -188,7 +162,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
if err != nil {
return err
}
context, err = MkBuildContext(string(dockerfile), nil)
context, err = archive.Generate("Dockerfile", string(dockerfile))
} else if utils.IsURL(cmd.Arg(0)) || utils.IsGIT(cmd.Arg(0)) {
isRemote = true
} else {

Просмотреть файл

@ -14,16 +14,6 @@ import (
"testing"
)
// mkTestContext generates a build context from the contents of the provided dockerfile.
// This context is suitable for use as an argument to BuildFile.Build()
func mkTestContext(dockerfile string, files [][2]string, t *testing.T) archive.Archive {
context, err := docker.MkBuildContext(dockerfile, files)
if err != nil {
t.Fatal(err)
}
return context
}
// A testContextTemplate describes a build context and how to test it
type testContextTemplate struct {
// Contents of the Dockerfile
@ -34,6 +24,18 @@ type testContextTemplate struct {
remoteFiles [][2]string
}
func (context testContextTemplate) Archive(dockerfile string, t *testing.T) archive.Archive {
input := []string{"Dockerfile", dockerfile}
for _, pair := range context.files {
input = append(input, pair[0], pair[1])
}
a, err := archive.Generate(input...)
if err != nil {
t.Fatal(err)
}
return a
}
// A table of all the contexts to build and test.
// A new docker runtime will be created and torn down for each context.
var testContexts = []testContextTemplate{
@ -381,7 +383,7 @@ func buildImage(context testContextTemplate, t *testing.T, eng *engine.Engine, u
dockerfile := constructDockerfile(context.dockerfile, ip, port)
buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, useCache, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil)
id, err := buildfile.Build(mkTestContext(dockerfile, context.files, t))
id, err := buildfile.Build(context.Archive(dockerfile, t))
if err != nil {
return nil, err
}
@ -785,7 +787,7 @@ func TestForbiddenContextPath(t *testing.T) {
dockerfile := constructDockerfile(context.dockerfile, ip, port)
buildfile := docker.NewBuildFile(srv, ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil)
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
_, err = buildfile.Build(context.Archive(dockerfile, t))
if err == nil {
t.Log("Error should not be nil")
@ -831,7 +833,7 @@ func TestBuildADDFileNotFound(t *testing.T) {
dockerfile := constructDockerfile(context.dockerfile, ip, port)
buildfile := docker.NewBuildFile(mkServerFromEngine(eng, t), ioutil.Discard, ioutil.Discard, false, true, false, ioutil.Discard, utils.NewStreamFormatter(false), nil, nil)
_, err = buildfile.Build(mkTestContext(dockerfile, context.files, t))
_, err = buildfile.Build(context.Archive(dockerfile, t))
if err == nil {
t.Log("Error should not be nil")

Просмотреть файл

@ -476,7 +476,7 @@ func (srv *Server) Build(job *engine.Job) engine.Status {
if err != nil {
return job.Error(err)
}
c, err := MkBuildContext(string(dockerFile), nil)
c, err := archive.Generate("Dockerfile", string(dockerFile))
if err != nil {
return job.Error(err)
}