func main() { var f *os.File var err error if len(os.Args) < 2 { fmt.Println("please supply filename(s)") os.Exit(1) } for _, fn := range os.Args[1:] { f, err = os.Open(fn) if err != nil { panic(err) } d := parser.Directive{LookingForDirectives: true} parser.SetEscapeToken(parser.DefaultEscapeToken, &d) ast, err := parser.Parse(f, &d) if err != nil { panic(err) } else { fmt.Println(ast.Dump()) } } }
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()) } }
// this replaces the FROM field in the Dockerfile to one with the previous step's unique name // it stores the parsed result Dockefile in uniqueSessionName file func (b *Builder) replaceFromField(step *Step) error { b.Conf.Logger.Noticef("Parsing and converting '%s'", step.Dockerfile) rwc, err := os.Open(path.Join(b.Conf.Workdir, step.Dockerfile)) if err != nil { return err } defer rwc.Close() d := parser.Directive{LookingForDirectives: true} parser.SetEscapeToken(parser.DefaultEscapeToken, &d) node, err := parser.Parse(rwc, &d) if err != nil { return err } for _, child := range node.Children { if child.Value == "from" { // found it. is it from anyone we know? if child.Next == nil { return errors.New("invalid Dockerfile. No valid FROM found") } imageName := child.Next.Value found, err := step.Manifest.FindStepByName(imageName) if err != nil { return err } if found != nil { child.Next.Value = b.uniqueStepName(found) } } } // did it have any effect? b.Conf.Logger.Debugf("Writing the new Dockerfile into %s", step.Dockerfile+".generated") err = ioutil.WriteFile(b.uniqueDockerfile(step), []byte(dumpDockerfile(node)), 0644) if err != nil { return err } return nil }
func TestBuildProcessLabels(t *testing.T) { dockerfile := "FROM scratch" d := parser.Directive{} parser.SetEscapeToken(parser.DefaultEscapeToken, &d) n, err := parser.Parse(strings.NewReader(dockerfile), &d) if err != nil { t.Fatalf("Error when parsing Dockerfile: %s", err) } options := &types.ImageBuildOptions{ Labels: map[string]string{ "org.e": "cli-e", "org.d": "cli-d", "org.c": "cli-c", "org.b": "cli-b", "org.a": "cli-a", }, } b := &Builder{ runConfig: &container.Config{}, options: options, directive: d, dockerfile: n, } err = b.processLabels() if err != nil { t.Fatalf("Error when processing labels: %s", err) } expected := []string{ "FROM scratch", `LABEL "org.a"='cli-a' "org.b"='cli-b' "org.c"='cli-c' "org.d"='cli-d' "org.e"='cli-e'`, } if len(b.dockerfile.Children) != 2 { t.Fatalf("Expect 2, got %d", len(b.dockerfile.Children)) } for i, v := range b.dockerfile.Children { if v.Original != expected[i] { t.Fatalf("Expect '%s' for %dth children, got, '%s'", expected[i], i, v.Original) } } }
// NewBuilder creates a new Dockerfile builder from an optional dockerfile and a Config. // If dockerfile is nil, the Dockerfile specified by Config.DockerfileName, // will be read from the Context passed to Build(). func NewBuilder(clientCtx context.Context, config *types.ImageBuildOptions, backend builder.Backend, buildContext builder.Context, dockerfile io.ReadCloser) (b *Builder, err error) { if config == nil { config = new(types.ImageBuildOptions) } if config.BuildArgs == nil { config.BuildArgs = make(map[string]string) } ctx, cancel := context.WithCancel(clientCtx) b = &Builder{ clientCtx: ctx, cancel: cancel, options: config, Stdout: os.Stdout, Stderr: os.Stderr, docker: backend, context: buildContext, runConfig: new(container.Config), tmpContainers: map[string]struct{}{}, id: stringid.GenerateNonCryptoID(), allowedBuildArgs: make(map[string]bool), directive: parser.Directive{ EscapeSeen: false, LookingForDirectives: true, }, } if icb, ok := backend.(builder.ImageCacheBuilder); ok { b.imageCache = icb.MakeImageCache(config.CacheFrom) } parser.SetEscapeToken(parser.DefaultEscapeToken, &b.directive) // Assume the default token for escape if dockerfile != nil { b.dockerfile, err = parser.Parse(dockerfile, &b.directive) if err != nil { return nil, err } } return b, nil }