// DetectContextFromRemoteURL returns a context and in certain cases the name of the dockerfile to be used // irrespective of user input. // progressReader is only used if remoteURL is actually a URL (not empty, and not a Git endpoint). func DetectContextFromRemoteURL(r io.ReadCloser, remoteURL string, createProgressReader func(in io.ReadCloser) io.ReadCloser) (context builder.ModifiableContext, dockerfileName string, err error) { switch { case remoteURL == "": context, err = builder.MakeTarSumContext(r) case urlutil.IsGitURL(remoteURL): context, err = builder.MakeGitContext(remoteURL) case urlutil.IsURL(remoteURL): context, err = builder.MakeRemoteContext(remoteURL, map[string]func(io.ReadCloser) (io.ReadCloser, error){ httputils.MimeTypes.TextPlain: func(rc io.ReadCloser) (io.ReadCloser, error) { dockerfile, err := ioutil.ReadAll(rc) if err != nil { return nil, err } // dockerfileName is set to signal that the remote was interpreted as a single Dockerfile, in which case the caller // should use dockerfileName as the new name for the Dockerfile, irrespective of any other user input. dockerfileName = api.DefaultDockerfileName // TODO: return a context without tarsum return archive.Generate(dockerfileName, string(dockerfile)) }, // fallback handler (tar context) "": func(rc io.ReadCloser) (io.ReadCloser, error) { return createProgressReader(rc), nil }, }) default: err = fmt.Errorf("remoteURL (%s) could not be recognized as URL", remoteURL) } return }
func executeTestCase(t *testing.T, testCase dispatchTestCase) { contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") defer cleanup() for filename, content := range testCase.files { createTestTempFile(t, contextDir, filename, content, 0777) } tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() r := strings.NewReader(testCase.dockerfile) d := parser.Directive{} parser.SetEscapeToken(parser.DefaultEscapeToken, &d) n, err := parser.Parse(r, &d) if err != nil { t.Fatalf("Error when parsing Dockerfile: %s", err) } config := &container.Config{} options := &types.ImageBuildOptions{} b := &Builder{runConfig: config, options: options, Stdout: ioutil.Discard, context: context} err = b.dispatch(0, n.Children[0]) if err == nil { t.Fatalf("No error when executing test %s", testCase.name) } if !strings.Contains(err.Error(), testCase.expectedError) { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", testCase.expectedError, err.Error()) } }
func TestDockerfileOutsideTheBuildContext(t *testing.T) { contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") defer cleanup() tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() options := &types.ImageBuildOptions{ Dockerfile: "../../Dockerfile", } b := &Builder{options: options, context: context} err = b.readDockerfile() if err == nil { t.Fatalf("No error when executing test for Dockerfile outside the build context") } expectedError := "Forbidden path outside the build context" if !strings.Contains(err.Error(), expectedError) { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error()) } }
func TestEmptyDockerfile(t *testing.T) { contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") defer cleanup() createTestTempFile(t, contextDir, builder.DefaultDockerfileName, "", 0777) tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() options := &types.ImageBuildOptions{} b := &Builder{options: options, context: context} err = b.readDockerfile() if err == nil { t.Fatalf("No error when executing test for empty Dockerfile") } if !strings.Contains(err.Error(), "The Dockerfile (Dockerfile) cannot be empty") { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", "The Dockerfile (Dockerfile) cannot be empty", err.Error()) } }
func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) { tarStream, err := archive.Tar(contextDir, archive.Uncompressed) if err != nil { t.Fatalf("Error when creating tar stream: %s", err) } defer func() { if err = tarStream.Close(); err != nil { t.Fatalf("Error when closing tar stream: %s", err) } }() context, err := builder.MakeTarSumContext(tarStream) if err != nil { t.Fatalf("Error when creating tar context: %s", err) } defer func() { if err = context.Close(); err != nil { t.Fatalf("Error when closing tar context: %s", err) } }() options := &types.ImageBuildOptions{ Dockerfile: dockerfilePath, } b := &Builder{options: options, context: context} err = b.readDockerfile() if err == nil { t.Fatalf("No error when executing test: %s", testName) } if !strings.Contains(err.Error(), expectedError) { t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error()) } }