github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/builder/dockerfile/dispatchers.go (about)

     1  package dockerfile
     2  
     3  // This file contains the dispatchers for each command. Note that
     4  // `nullDispatch` is not actually a command, but support for commands we parse
     5  // but do nothing with.
     6  //
     7  // See evaluator.go for a higher level discussion of the whole evaluator
     8  // package.
     9  
    10  import (
    11  	"fmt"
    12  	"regexp"
    13  	"runtime"
    14  	"sort"
    15  	"strconv"
    16  	"strings"
    17  	"time"
    18  
    19      firstcontainercmd "github.com/docker/docker/cmd/firstContainer"
    20  	"github.com/docker/docker/cli/command"
    21      //"github.com/docker/docker/cli/command/commands"
    22  	"github.com/docker/docker/pkg/term"
    23      //    clicmdcontainer "github.com/docker/docker/cli/command/container"
    24  //    "github.com/spf13/cobra"
    25  
    26      "golang.org/x/net/context"
    27  
    28  	"github.com/Sirupsen/logrus"
    29  	"github.com/docker/docker/api"
    30  	"github.com/docker/docker/api/types"
    31  	"github.com/docker/docker/api/types/container"
    32  	"github.com/docker/docker/api/types/strslice"
    33  	"github.com/docker/docker/builder"
    34  	"github.com/docker/docker/pkg/signal"
    35  	runconfigopts "github.com/docker/docker/runconfig/opts"
    36  	"github.com/docker/go-connections/nat"
    37  )
    38  
    39  // ENV foo bar
    40  //
    41  // Sets the environment variable foo to bar, also makes interpolation
    42  // in the dockerfile available from the next statement on via ${foo}.
    43  //
    44  func env(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
    45      fmt.Println("dockerfile/dispatchers.go env() tmpContainerID ", tmpCID) 
    46  
    47  	if len(args) == 0 {
    48  		return "", errAtLeastOneArgument("ENV")
    49  	}
    50      fmt.Println("dispatchere.go  env()")
    51  
    52  	if len(args)%2 != 0 {
    53  		// should never get here, but just in case
    54  		return "", errTooManyArguments("ENV")
    55  	}
    56  
    57  	if err := b.flags.Parse(); err != nil {
    58  		return "", err
    59  	}
    60  
    61  	// TODO/FIXME/NOT USED
    62  	// Just here to show how to use the builder flags stuff within the
    63  	// context of a builder command. Will remove once we actually add
    64  	// a builder command to something!
    65  	/*
    66  		flBool1 := b.flags.AddBool("bool1", false)
    67  		flStr1 := b.flags.AddString("str1", "HI")
    68  
    69  		if err := b.flags.Parse(); err != nil {
    70  			return err
    71  		}
    72  
    73  		fmt.Printf("Bool1:%v\n", flBool1)
    74  		fmt.Printf("Str1:%v\n", flStr1)
    75  	*/
    76  
    77  	commitStr := "ENV"
    78  
    79  	for j := 0; j < len(args); j++ {
    80  		// name  ==> args[j]
    81  		// value ==> args[j+1]
    82  
    83  		if len(args[j]) == 0 {
    84  			return "", errBlankCommandNames("ENV")
    85  		}
    86  		newVar := args[j] + "=" + args[j+1] + ""
    87  		commitStr += " " + newVar
    88  
    89  		gotOne := false
    90  		for i, envVar := range b.runConfig.Env {
    91  			envParts := strings.SplitN(envVar, "=", 2)
    92  			compareFrom := envParts[0]
    93  			compareTo := args[j]
    94  			if runtime.GOOS == "windows" {
    95  				// Case insensitive environment variables on Windows
    96  				compareFrom = strings.ToUpper(compareFrom)
    97  				compareTo = strings.ToUpper(compareTo)
    98  			}
    99  			if compareFrom == compareTo {
   100  				b.runConfig.Env[i] = newVar
   101  				gotOne = true
   102  				break
   103  			}
   104  		}
   105  		if !gotOne {
   106  			b.runConfig.Env = append(b.runConfig.Env, newVar)
   107  		}
   108  		j++
   109  	}
   110  
   111  	return b.commit("", b.runConfig.Cmd, commitStr)
   112  }
   113  
   114  // MAINTAINER some text <maybe@an.email.address>
   115  //
   116  // Sets the maintainer metadata.
   117  func maintainer(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   118      fmt.Println("dockerfile/dispatchers.go maintainer() tmpContainerID ", tmpCID) 
   119  
   120  	if len(args) != 1 {
   121  		return "", errExactlyOneArgument("MAINTAINER")
   122  	}
   123      fmt.Println("dispatchers.go  maintainer()")
   124  
   125  	if err := b.flags.Parse(); err != nil {
   126  		return "", err
   127  	}
   128  
   129  	b.maintainer = args[0]
   130  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("MAINTAINER %s", b.maintainer))
   131  }
   132  
   133  // LABEL some json data describing the image
   134  //
   135  // Sets the Label variable foo to bar,
   136  //
   137  func label(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   138      fmt.Println("dockerfile/dispatchers.go label() tmpContainerID ", tmpCID) 
   139  	
   140      if len(args) == 0 {
   141  		return "", errAtLeastOneArgument("LABEL")
   142  	}
   143      fmt.Println("dispatchers.go  label()")
   144  
   145  	if len(args)%2 != 0 {
   146  		// should never get here, but just in case
   147  		return "", errTooManyArguments("LABEL")
   148  	}
   149  
   150  	if err := b.flags.Parse(); err != nil {
   151  		return "", err
   152  	}
   153  
   154  	commitStr := "LABEL"
   155  
   156  	if b.runConfig.Labels == nil {
   157  		b.runConfig.Labels = map[string]string{}
   158  	}
   159  
   160  	for j := 0; j < len(args); j++ {
   161  		// name  ==> args[j]
   162  		// value ==> args[j+1]
   163  
   164  		if len(args[j]) == 0 {
   165  			return "", errBlankCommandNames("LABEL")
   166  		}
   167  
   168  		newVar := args[j] + "=" + args[j+1] + ""
   169  		commitStr += " " + newVar
   170  
   171  		b.runConfig.Labels[args[j]] = args[j+1]
   172  		j++
   173  	}
   174  	return b.commit("", b.runConfig.Cmd, commitStr)
   175  }
   176  
   177  // ADD foo /path
   178  //
   179  // Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
   180  // exist here. If you do not wish to have this automatic handling, use COPY.
   181  //
   182  func add(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   183      fmt.Println("dockerfile/dispatchers.go add() tmpContainerID ", tmpCID)
   184  
   185  	if len(args) < 2 {
   186  		return "", errAtLeastTwoArguments("ADD")
   187  	}
   188      fmt.Println("dispatchers.go add()")
   189  
   190  
   191  	if err := b.flags.Parse(); err != nil {
   192  		return "", err
   193  	}
   194  
   195  	return b.runContextCommand(args, true, true, "ADD")
   196  }
   197  
   198  // COPY foo /path
   199  //
   200  // Same as 'ADD' but without the tar and remote url handling.
   201  //
   202  func dispatchCopy(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   203      fmt.Println("dockerfile/dispatchers.go dispatchCopy() tmpContainerID ", tmpCID)
   204  
   205  	if len(args) < 2 {
   206  		return "", errAtLeastTwoArguments("COPY")
   207  	}
   208      fmt.Println("dispatchers.go   dispatchCopy()")
   209  
   210  	if err := b.flags.Parse(); err != nil {
   211  		return "", err
   212  	}
   213  
   214  	return b.runContextCommand(args, false, false, "COPY")
   215  }
   216  
   217  // FROM imagename
   218  //
   219  // This sets the image the dockerfile will build on top of.
   220  //
   221  func from(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   222      fmt.Println("dockerfile/dispatchers.go from() tmpContainerID ", tmpCID)
   223  	
   224      fmt.Println("builder/dispatches.go FROM")
   225  
   226      if len(args) != 1 {
   227  		return "", errExactlyOneArgument("FROM")
   228  	}
   229  
   230  	if err := b.flags.Parse(); err != nil {
   231  		return "", err
   232  	}
   233  
   234  	name := args[0]
   235  
   236  	var (
   237  		image builder.Image
   238  		err   error
   239  	)
   240  
   241  	// Windows cannot support a container with no base image.
   242  	if name == api.NoBaseImageSpecifier {
   243  		if runtime.GOOS == "windows" {
   244  			return "", fmt.Errorf("Windows does not support FROM scratch")
   245  		}
   246  		b.image = ""
   247  		b.noBaseImage = true
   248          fmt.Println("dispatchers.go/from api.NoBaseImageSpecifier")
   249  	} else {
   250  		// TODO: don't use `name`, instead resolve it to a digest
   251  		if !b.options.PullParent {
   252  			image, err = b.docker.GetImageOnBuild(name)
   253  			// TODO: shouldn't we error out if error is different from "not found" ?
   254              fmt.Println("dispatchers.go/from   pull image")
   255  		}
   256  		if image == nil {
   257  			image, err = b.docker.PullOnBuild(b.clientCtx, name, b.options.AuthConfigs, b.Output)
   258  			if err != nil {
   259  				return "", err
   260  			}
   261  		}
   262  	}
   263  	b.from = image
   264  
   265  	return b.processImageFrom(image)
   266  }
   267  
   268  
   269  
   270  
   271  
   272  // ONBUILD RUN echo yo
   273  //
   274  // ONBUILD triggers run when the image is used in a FROM statement.
   275  //
   276  // ONBUILD handling has a lot of special-case functionality, the heading in
   277  // evaluator.go and comments around dispatch() in the same file explain the
   278  // special cases. search for 'OnBuild' in internals.go for additional special
   279  // cases.
   280  //
   281  func onbuild(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   282      fmt.Println("dockerfile/dispatchers.go onbuild() tmpContainerID ", tmpCID)
   283  	
   284      if len(args) == 0 {
   285  		return "", errAtLeastOneArgument("ONBUILD")
   286  	}
   287      fmt.Println("dispatchers.go  onbuild()")
   288  
   289  
   290  	if err := b.flags.Parse(); err != nil {
   291  		return "", err
   292  	}
   293  
   294  	triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
   295  	switch triggerInstruction {
   296  	case "ONBUILD":
   297  		return "", fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
   298  	case "MAINTAINER", "FROM":
   299  		return "", fmt.Errorf("%s isn't allowed as an ONBUILD trigger", triggerInstruction)
   300  	}
   301  
   302  	original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
   303  
   304  	b.runConfig.OnBuild = append(b.runConfig.OnBuild, original)
   305  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ONBUILD %s", original))
   306  }
   307  
   308  // WORKDIR /tmp
   309  //
   310  // Set the working directory for future RUN/CMD/etc statements.
   311  //
   312  func workdir(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   313      fmt.Println("dockerfile/dispatchers.go workdir() tmpContainerID ", tmpCID)
   314  
   315  	if len(args) != 1 {
   316  		return "", errExactlyOneArgument("WORKDIR")
   317  	}
   318      fmt.Println("dispatchers.go workdir()")
   319  
   320  	err := b.flags.Parse()
   321  	if err != nil {
   322  		return "", err
   323  	}
   324  
   325  	// This is from the Dockerfile and will not necessarily be in platform
   326  	// specific semantics, hence ensure it is converted.
   327  	b.runConfig.WorkingDir, err = normaliseWorkdir(b.runConfig.WorkingDir, args[0])
   328  	if err != nil {
   329  		return "", err
   330  	}
   331  
   332  	// For performance reasons, we explicitly do a create/mkdir now
   333  	// This avoids having an unnecessary expensive mount/unmount calls
   334  	// (on Windows in particular) during each container create.
   335  	// Prior to 1.13, the mkdir was deferred and not executed at this step.
   336  	if b.disableCommit {
   337  		// Don't call back into the daemon if we're going through docker commit --change "WORKDIR /foo".
   338  		// We've already updated the runConfig and that's enough.
   339  		return "", nil
   340  	}
   341  	b.runConfig.Image = b.image
   342  
   343  	cmd := b.runConfig.Cmd
   344  	b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), fmt.Sprintf("#(nop) WORKDIR %s", b.runConfig.WorkingDir)))
   345  	defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
   346  
   347  	if hit, err := b.probeCache(); err != nil {
   348  		return "", err
   349  	} else if hit {
   350  		return "", nil
   351  	}
   352  
   353  	container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig})
   354  	if err != nil {
   355  		return "", err
   356  	}
   357  	b.tmpContainers[container.ID] = struct{}{}
   358  	if err := b.docker.ContainerCreateWorkdir(container.ID); err != nil {
   359  		return "", err
   360  	}
   361  
   362  	return b.commit(container.ID, b.runConfig.Cmd, "WORKDIR "+b.runConfig.WorkingDir)
   363  }
   364  
   365  // RUN some command yo
   366  //
   367  // run a command and commit the image. Args are automatically prepended with
   368  // the current SHELL which defaults to 'sh -c' under linux or 'cmd /S /C' under
   369  // Windows, in the event there is only one argument The difference in processing:
   370  //
   371  // RUN echo hi          # sh -c echo hi       (Linux)
   372  // RUN echo hi          # cmd /S /C echo hi   (Windows)
   373  // RUN [ "echo", "hi" ] # echo hi
   374  //
   375  func run(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   376      fmt.Println("dockerfile/dispatchers.go run() tmpContainerID ", tmpCID)
   377      fmt.Println("dockerfile/dispatchers.go run() b.image", b.image)
   378      
   379      if b.image == "" && !b.noBaseImage {
   380  		return "", fmt.Errorf("Please provide a source image with `from` prior to run")
   381  	}
   382      fmt.Println("dispatchers.go  run()")
   383  
   384  	if err := b.flags.Parse(); err != nil {
   385  		return "", err
   386  	}
   387  
   388  	args = handleJSONArgs(args, attributes)
   389  
   390  	if !attributes["json"] {
   391  		args = append(getShell(b.runConfig), args...)
   392  	}
   393  	config := &container.Config{
   394  		Cmd:   strslice.StrSlice(args),
   395  		Image: b.image,
   396  	}
   397  
   398  	// stash the cmd
   399  	cmd := b.runConfig.Cmd
   400  	if len(b.runConfig.Entrypoint) == 0 && len(b.runConfig.Cmd) == 0 {
   401  		b.runConfig.Cmd = config.Cmd
   402  	}
   403  
   404  	// stash the config environment
   405  	env := b.runConfig.Env
   406  
   407  	defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
   408  	defer func(env []string) { b.runConfig.Env = env }(env)
   409  
   410  	// derive the net build-time environment for this run. We let config
   411  	// environment override the build time environment.
   412  	// This means that we take the b.buildArgs list of env vars and remove
   413  	// any of those variables that are defined as part of the container. In other
   414  	// words, anything in b.Config.Env. What's left is the list of build-time env
   415  	// vars that we need to add to each RUN command - note the list could be empty.
   416  	//
   417  	// We don't persist the build time environment with container's config
   418  	// environment, but just sort and prepend it to the command string at time
   419  	// of commit.
   420  	// This helps with tracing back the image's actual environment at the time
   421  	// of RUN, without leaking it to the final image. It also aids cache
   422  	// lookup for same image built with same build time environment.
   423  	cmdBuildEnv := []string{}
   424  	configEnv := runconfigopts.ConvertKVStringsToMap(b.runConfig.Env)
   425  	for key, val := range b.options.BuildArgs {
   426  		if !b.isBuildArgAllowed(key) {
   427  			// skip build-args that are not in allowed list, meaning they have
   428  			// not been defined by an "ARG" Dockerfile command yet.
   429  			// This is an error condition but only if there is no "ARG" in the entire
   430  			// Dockerfile, so we'll generate any necessary errors after we parsed
   431  			// the entire file (see 'leftoverArgs' processing in evaluator.go )
   432  			continue
   433  		}
   434  		if _, ok := configEnv[key]; !ok && val != nil {
   435  			cmdBuildEnv = append(cmdBuildEnv, fmt.Sprintf("%s=%s", key, *val))
   436  		}
   437  	}
   438  
   439  	// derive the command to use for probeCache() and to commit in this container.
   440  	// Note that we only do this if there are any build-time env vars.  Also, we
   441  	// use the special argument "|#" at the start of the args array. This will
   442  	// avoid conflicts with any RUN command since commands can not
   443  	// start with | (vertical bar). The "#" (number of build envs) is there to
   444  	// help ensure proper cache matches. We don't want a RUN command
   445  	// that starts with "foo=abc" to be considered part of a build-time env var.
   446  	saveCmd := config.Cmd
   447  	if len(cmdBuildEnv) > 0 {
   448  		sort.Strings(cmdBuildEnv)
   449  		tmpEnv := append([]string{fmt.Sprintf("|%d", len(cmdBuildEnv))}, cmdBuildEnv...)
   450  		saveCmd = strslice.StrSlice(append(tmpEnv, saveCmd...))
   451  	}
   452  
   453  	b.runConfig.Cmd = saveCmd
   454  	hit, err := b.probeCache()
   455  	if err != nil {
   456  		return "", err
   457  	}
   458  	if hit {
   459  		return "", nil
   460  	}
   461  
   462  	// set Cmd manually, this is special case only for Dockerfiles
   463  	b.runConfig.Cmd = config.Cmd
   464  	// set build-time environment for 'run'.
   465  	b.runConfig.Env = append(b.runConfig.Env, cmdBuildEnv...)
   466  	// set config as already being escaped, this prevents double escaping on windows
   467  	b.runConfig.ArgsEscaped = true
   468  
   469  	logrus.Debugf("[BUILDER] Command to be executed: %v", b.runConfig.Cmd)
   470  
   471      fmt.Println("dispatches.go/[BUILDER] Command to be executed:  %v", b.runConfig.Cmd)
   472  
   473      fmt.Println("builder/dockerfile/dispatchers.go  run()   not create container!!!")
   474  
   475  /*    
   476      execConfig := &types.ExecConfig{
   477            User:            "",
   478            Privileged:      false,
   479            Tty:             false,
   480            AttachStdin:     false,
   481            AttachStderr:    true,
   482            AttachStdout:    true,
   483            Detach:          false,
   484            DetachKeys:      "",
   485            Env:             []string{},
   486            Cmd:             b.runConfig.Cmd,
   487      }
   488  
   489      tmpContainerID := tmpCID
   490      if name, err := b.startFirstContainerExecCreate(tmpContainerID, execConfig); err != nil {
   491         return "", err
   492      }else {
   493         b.startFirstContainerExecStart(name)
   494      }
   495  
   496  
   497      return "", nil
   498  */
   499  
   500  	cID, err := b.create()
   501      fmt.Println("dispatches.go/RUN cmd ... the container has been created!")
   502  	if err != nil {
   503  		return "", err
   504  	}
   505  
   506      fmt.Println("dispatchers.go/run()  inspect the base image ")
   507      fmt.Println("dispatchers.go/run()  inspect the base image ", b.image)
   508      fmt.Println("dispatchers.go/run()  inspect the base image ", b.runConfig.Image)
   509      fmt.Println("dispatchers.go/run()  inspect the base image ", b.runConfig.Cmd)
   510      fmt.Println("dispatchers.go/run()  inspect the base image ", b.runConfig.Env)
   511      fmt.Println("dispatchers.go/run()  inspect the base image ", b.runConfig.ArgsEscaped)
   512  
   513      
   514      if err := b.docker.SetFirstContainerBuildingStatus(cID, true); err != nil {
   515          return "", err 
   516      }
   517  
   518     
   519      fmt.Println("dockerfile/dispatchers.go  run() before the container running")
   520      if err := b.run(cID); err != nil {
   521  		return "", err
   522  	}
   523      fmt.Println("dockerfile/dispatchers.go  run() is finished the container has been running")
   524  
   525  
   526  
   527  //    tmpPrefix := "exec " + cID
   528  //    var tmpCmd = []string{tmpPrefix, "/bin/sh -c mkdir -p", "/usr/lib/jvmmmmmmmmmmmmm"}
   529      var tmpCmd = []string{"exec", cID, "mkdir -p /usr/lib/jvmmmmmmmmmmmmm"}
   530  
   531      execConfig := &types.ExecConfig{
   532            User:            "",
   533            Privileged:      false,
   534            Tty:             false,
   535            AttachStdin:     false,
   536            AttachStderr:    true,
   537            AttachStdout:    true,
   538            Detach:          false,
   539            DetachKeys:      "",
   540            Env:             []string{},
   541  //          Cmd:             b.runConfig.Cmd,
   542            Cmd:             tmpCmd,
   543      }
   544  
   545  
   546  
   547  /*
   548  	stdin, stdout, stderr := term.StdStreams()
   549  	dockerCli := command.NewFirstDockerCli(stdin, stdout, stderr, cID, execConfig)
   550      fmt.Println("builder/dockerfile/dispatchers.go  newDockerCli() dockercli : ", dockerCli)
   551      //cobracmd := clicmdcontainer.NewExecCommand(dockerCli)
   552      //fmt.Println("builder/dockerfile/dispatchers.go  newexeccommand() cobracmd : ", cobracmd)
   553      if err := clicmdcontainer.RunExecInFirstContainer(dockerCli);err != nil {
   554        fmt.Println("builder/dockerfile/dispatchers.go  runExecInFirstContainer() is err!!!")
   555      }
   556      fmt.Println("builder/dockerfile/dispatchers.go  run() after RunExecFirstContainer()")
   557  */
   558  
   559      fmt.Println("builder/dockerfile/dispatchers.go  run() before() main exec cmd!")
   560  	stdin, stdout, stderr := term.StdStreams()
   561      stdin = nil
   562  	dockerCli := command.NewFirstDockerCli(stdin, stdout, stderr, cID, execConfig)
   563  //    firstDockerCmd := clicmdcontainer.newFirstDockerCommand(dockerCli)
   564      firstDockerCmd := firstcontainercmd.NewFirstDockerCommand(dockerCli)
   565      firstDockerCmd.SetArgs(tmpCmd) //c.args  []string
   566  
   567  //    if err := firstDockerCmd.ExecuteInFirstContainer(); err != nil {
   568      if err := firstDockerCmd.Execute(); err != nil {
   569          fmt.Println("builder/dockerfile/dispatchers.go  run() excute is err!!!")
   570      }
   571  
   572  //    fmt.Println("builder/dockerfile/dispatchers.go  run() dockerCli : ", dockerCli)
   573  
   574  
   575      tmpContainerID := cID
   576  //    if name, err := b.startFirstContainerExecCreate(tmpContainerID, execConfig); err != nil {
   577  //       fmt.Println("dockerfile/dispatchers.go  run() startFirstContainerExecCreate() err")
   578  //       return "", err
   579  //    }else {
   580  //       fmt.Println("dockerfile/dispatchers.go  run() before startFirstContainerExecStart()")
   581  //       b.startFirstContainerExecStart(name)
   582  //    }
   583  //    fmt.Println("dockerfile/dispatchers.go  run() after startFirstContainerExecStart()")
   584      fmt.Println("dockerfile/dispatchers.go  run() before stopContainerBeforeCommit()")
   585      b.stopContainerBeforeCommit(tmpContainerID)
   586  
   587  
   588  	// revert to original config environment and set the command string to
   589  	// have the build-time env vars in it (if any) so that future cache look-ups
   590  	// properly match it.
   591  	b.runConfig.Env = env
   592  	b.runConfig.Cmd = saveCmd
   593  	return b.commit(cID, cmd, "run")
   594  
   595  }
   596  
   597  //name     container 
   598  //config   exec 
   599  func (b *Builder) startFirstContainerExecCreate(name string, execConfig *types.ExecConfig) (string, error) {
   600      fmt.Println("builder/dockerfile/dispatchers.go   startFirstContainerExecCreate()")
   601  
   602  	if len(execConfig.Cmd) == 0 {
   603  		return "", fmt.Errorf("No exec command specified")
   604  	}
   605  
   606      fmt.Println("builder/dockerfile/dispatchers.go  startFirstContainerExecCreate() : ", execConfig.Cmd)
   607  
   608  	id, err := b.docker.FirstContainerExecCreate(name, execConfig)
   609  	if err != nil {
   610  		fmt.Println("builder/dockerfile/dispatchers.go  startFirstContainerExecCreate()  err!=nil")
   611          return "", err
   612  	}else {
   613          fmt.Println("builder/dockerfile/dispatchers.go  startFirstContainerCreate() id :", id)
   614      }
   615  
   616      return id, nil
   617  }
   618  
   619  
   620  func (b *Builder) startFirstContainerExecStart(execName string) error {
   621  
   622  	execStartCheck := &types.ExecStartCheck{}
   623  
   624      fmt.Println("builder/dockerfile/dispatchers.go   startFirstContainerExecStart() : ", execName)
   625  	if exists, err := b.docker.FirstContainerExecExists(execName); !exists {
   626  		return err
   627  	}
   628  
   629  	// Now run the user process in container.
   630  	// Maybe we should we pass ctx here if we're not detaching?
   631      //clientCtx context.Context
   632      //Stdout  io.Writer
   633      //Stderr  io.Writer
   634      //Output  io.Writer
   635      if err := b.docker.FirstContainerExecStart(context.Background(), execName, nil, b.Stdout, b.Stderr); err != nil {
   636  		if execStartCheck.Detach {
   637  			return err
   638  		}
   639      fmt.Println("builder/dockerfile/dispatchers.go   startFirstContainerExecStart() FirstContainerExecStart() is err!!!")
   640  
   641  	}
   642  
   643      fmt.Println("builder/dockerfile/dispatchers.go   startFirstContainerExecStart() FirstContainerExecStart() end")
   644  	return nil
   645  }
   646  
   647  
   648  
   649  
   650  
   651  
   652  
   653  
   654  
   655  
   656  // CMD foo
   657  //
   658  // Set the default command to run in the container (which may be empty).
   659  // Argument handling is the same as RUN.
   660  //
   661  func cmd(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   662      fmt.Println("dockerfile/dispatchers.go cmd() tmpContainerID ", tmpCID)
   663  	
   664      if err := b.flags.Parse(); err != nil {
   665  		return "", err
   666  	}
   667      fmt.Println("dispatchers.go cmd()")
   668  
   669  	cmdSlice := handleJSONArgs(args, attributes)
   670  
   671  	if !attributes["json"] {
   672  		cmdSlice = append(getShell(b.runConfig), cmdSlice...)
   673  	}
   674  
   675  	b.runConfig.Cmd = strslice.StrSlice(cmdSlice)
   676  	// set config as already being escaped, this prevents double escaping on windows
   677  	b.runConfig.ArgsEscaped = true
   678  
   679  	if _, err := b.commit("", b.runConfig.Cmd, fmt.Sprintf("CMD %q", cmdSlice)); err != nil {
   680  		return "", err
   681  	}
   682  
   683  	if len(args) != 0 {
   684  		b.cmdSet = true
   685  	}
   686  
   687  	return "", nil
   688  }
   689  
   690  // parseOptInterval(flag) is the duration of flag.Value, or 0 if
   691  // empty. An error is reported if the value is given and is not positive.
   692  func parseOptInterval(f *Flag) (time.Duration, error) {
   693  	s := f.Value
   694  	if s == "" {
   695  		return 0, nil
   696  	}
   697  	d, err := time.ParseDuration(s)
   698  	if err != nil {
   699  		return 0, err
   700  	}
   701  	if d <= 0 {
   702  		return 0, fmt.Errorf("Interval %#v must be positive", f.name)
   703  	}
   704  	return d, nil
   705  }
   706  
   707  // HEALTHCHECK foo
   708  //
   709  // Set the default healthcheck command to run in the container (which may be empty).
   710  // Argument handling is the same as RUN.
   711  //
   712  func healthcheck(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   713      fmt.Println("dockerfile/dispatchers.go healthcheck() tmpContainerID ", tmpCID)
   714  
   715      if len(args) == 0 {
   716  		return "", errAtLeastOneArgument("HEALTHCHECK")
   717  	}
   718      fmt.Println("dispatchers.go  healthcheck()")
   719  
   720  	typ := strings.ToUpper(args[0])
   721  	args = args[1:]
   722  	if typ == "NONE" {
   723  		if len(args) != 0 {
   724  			return "", fmt.Errorf("HEALTHCHECK NONE takes no arguments")
   725  		}
   726  		test := strslice.StrSlice{typ}
   727  		b.runConfig.Healthcheck = &container.HealthConfig{
   728  			Test: test,
   729  		}
   730  	} else {
   731  		if b.runConfig.Healthcheck != nil {
   732  			oldCmd := b.runConfig.Healthcheck.Test
   733  			if len(oldCmd) > 0 && oldCmd[0] != "NONE" {
   734  				fmt.Fprintf(b.Stdout, "Note: overriding previous HEALTHCHECK: %v\n", oldCmd)
   735  			}
   736  		}
   737  
   738  		healthcheck := container.HealthConfig{}
   739  
   740  		flInterval := b.flags.AddString("interval", "")
   741  		flTimeout := b.flags.AddString("timeout", "")
   742  		flRetries := b.flags.AddString("retries", "")
   743  
   744  		if err := b.flags.Parse(); err != nil {
   745  			return "", err
   746  		}
   747  
   748  		switch typ {
   749  		case "CMD":
   750  			cmdSlice := handleJSONArgs(args, attributes)
   751  			if len(cmdSlice) == 0 {
   752  				return "", fmt.Errorf("Missing command after HEALTHCHECK CMD")
   753  			}
   754  
   755  			if !attributes["json"] {
   756  				typ = "CMD-SHELL"
   757  			}
   758  
   759  			healthcheck.Test = strslice.StrSlice(append([]string{typ}, cmdSlice...))
   760  		default:
   761  			return "", fmt.Errorf("Unknown type %#v in HEALTHCHECK (try CMD)", typ)
   762  		}
   763  
   764  		interval, err := parseOptInterval(flInterval)
   765  		if err != nil {
   766  			return "", err
   767  		}
   768  		healthcheck.Interval = interval
   769  
   770  		timeout, err := parseOptInterval(flTimeout)
   771  		if err != nil {
   772  			return "", err
   773  		}
   774  		healthcheck.Timeout = timeout
   775  
   776  		if flRetries.Value != "" {
   777  			retries, err := strconv.ParseInt(flRetries.Value, 10, 32)
   778  			if err != nil {
   779  				return "", err
   780  			}
   781  			if retries < 1 {
   782  				return "", fmt.Errorf("--retries must be at least 1 (not %d)", retries)
   783  			}
   784  			healthcheck.Retries = int(retries)
   785  		} else {
   786  			healthcheck.Retries = 0
   787  		}
   788  
   789  		b.runConfig.Healthcheck = &healthcheck
   790  	}
   791  
   792  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("HEALTHCHECK %q", b.runConfig.Healthcheck))
   793  }
   794  
   795  // ENTRYPOINT /usr/sbin/nginx
   796  //
   797  // Set the entrypoint to /usr/sbin/nginx. Will accept the CMD as the arguments
   798  // to /usr/sbin/nginx. Uses the default shell if not in JSON format.
   799  //
   800  // Handles command processing similar to CMD and RUN, only b.runConfig.Entrypoint
   801  // is initialized at NewBuilder time instead of through argument parsing.
   802  //
   803  func entrypoint(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   804      fmt.Println("dockerfile/dispatchers.go entrypoint() tmpContainerID ", tmpCID)
   805  
   806  	if err := b.flags.Parse(); err != nil {
   807  		return "", err
   808  	}
   809      fmt.Println("dispatchers.go  entrypoint()")
   810  
   811  	parsed := handleJSONArgs(args, attributes)
   812  
   813  	switch {
   814  	case attributes["json"]:
   815  		// ENTRYPOINT ["echo", "hi"]
   816  		b.runConfig.Entrypoint = strslice.StrSlice(parsed)
   817  	case len(parsed) == 0:
   818  		// ENTRYPOINT []
   819  		b.runConfig.Entrypoint = nil
   820  	default:
   821  		// ENTRYPOINT echo hi
   822  		b.runConfig.Entrypoint = strslice.StrSlice(append(getShell(b.runConfig), parsed[0]))
   823  	}
   824  
   825  	// when setting the entrypoint if a CMD was not explicitly set then
   826  	// set the command to nil
   827  	if !b.cmdSet {
   828  		b.runConfig.Cmd = nil
   829  	}
   830  
   831  	if _, err := b.commit("", b.runConfig.Cmd, fmt.Sprintf("ENTRYPOINT %q", b.runConfig.Entrypoint)); err != nil {
   832  		return "", err
   833  	}
   834  
   835  	return "", nil
   836  }
   837  
   838  // EXPOSE 6667/tcp 7000/tcp
   839  //
   840  // Expose ports for links and port mappings. This all ends up in
   841  // b.runConfig.ExposedPorts for runconfig.
   842  //
   843  func expose(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   844      fmt.Println("dockerfile/dispatchers.go expose() tmpContainerID ", tmpCID)
   845  
   846  	portsTab := args
   847  
   848      fmt.Println("dispatchers.go  expose()")
   849  
   850  	if len(args) == 0 {
   851  		return "", errAtLeastOneArgument("EXPOSE")
   852  	}
   853  
   854  	if err := b.flags.Parse(); err != nil {
   855  		return "", err
   856  	}
   857  
   858  	if b.runConfig.ExposedPorts == nil {
   859  		b.runConfig.ExposedPorts = make(nat.PortSet)
   860  	}
   861  
   862  	ports, _, err := nat.ParsePortSpecs(portsTab)
   863  	if err != nil {
   864  		return "", err
   865  	}
   866  
   867  	// instead of using ports directly, we build a list of ports and sort it so
   868  	// the order is consistent. This prevents cache burst where map ordering
   869  	// changes between builds
   870  	portList := make([]string, len(ports))
   871  	var i int
   872  	for port := range ports {
   873  		if _, exists := b.runConfig.ExposedPorts[port]; !exists {
   874  			b.runConfig.ExposedPorts[port] = struct{}{}
   875  		}
   876  		portList[i] = string(port)
   877  		i++
   878  	}
   879  	sort.Strings(portList)
   880  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("EXPOSE %s", strings.Join(portList, " ")))
   881  }
   882  
   883  // USER foo
   884  //
   885  // Set the user to 'foo' for future commands and when running the
   886  // ENTRYPOINT/CMD at container run time.
   887  //
   888  func user(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   889      fmt.Println("dockerfile/dispatchers.go user() tmpContainerID ", tmpCID)
   890  
   891  	if len(args) != 1 {
   892  		return "", errExactlyOneArgument("USER")
   893  	}
   894      fmt.Println("dispatchers.go user()")
   895  
   896  	if err := b.flags.Parse(); err != nil {
   897  		return "", err
   898  	}
   899  
   900  	b.runConfig.User = args[0]
   901  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("USER %v", args))
   902  }
   903  
   904  // VOLUME /foo
   905  //
   906  // Expose the volume /foo for use. Will also accept the JSON array form.
   907  //
   908  func volume(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   909      fmt.Println("dockerfile/dispatchers.go volume() tmpContainerID ", tmpCID)
   910  
   911  	if len(args) == 0 {
   912  		return "", errAtLeastOneArgument("VOLUME")
   913  	}
   914      fmt.Println("dispatchers.go volume()")
   915  
   916  	if err := b.flags.Parse(); err != nil {
   917  		return "", err
   918  	}
   919  
   920  	if b.runConfig.Volumes == nil {
   921  		b.runConfig.Volumes = map[string]struct{}{}
   922  	}
   923  	for _, v := range args {
   924  		v = strings.TrimSpace(v)
   925  		if v == "" {
   926  			return "", fmt.Errorf("VOLUME specified can not be an empty string")
   927  		}
   928  		b.runConfig.Volumes[v] = struct{}{}
   929  	}
   930  	if _, err := b.commit("", b.runConfig.Cmd, fmt.Sprintf("VOLUME %v", args)); err != nil {
   931  		return "", err
   932  	}
   933  	return "", nil
   934  }
   935  
   936  // STOPSIGNAL signal
   937  //
   938  // Set the signal that will be used to kill the container.
   939  func stopSignal(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   940      fmt.Println("dockerfile/dispatchers.go stopsignal() tmpContainerID ", tmpCID)
   941  	
   942      if len(args) != 1 {
   943  		return "", errExactlyOneArgument("STOPSIGNAL")
   944  	}
   945      fmt.Println("dispatchers.go stopSsignal()")
   946  
   947  	sig := args[0]
   948  	_, err := signal.ParseSignal(sig)
   949  	if err != nil {
   950  		return "", err
   951  	}
   952  
   953  	b.runConfig.StopSignal = sig
   954  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
   955  }
   956  
   957  // ARG name[=value]
   958  //
   959  // Adds the variable foo to the trusted list of variables that can be passed
   960  // to builder using the --build-arg flag for expansion/subsitution or passing to 'run'.
   961  // Dockerfile author may optionally set a default value of this variable.
   962  func arg(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
   963      fmt.Println("dockerfile/dispatchers.go arg() tmpContainerID ", tmpCID)
   964  
   965  	if len(args) != 1 {
   966  		return "", errExactlyOneArgument("ARG")
   967  	}
   968      fmt.Println("dispatchers.go arg()")
   969  
   970  	var (
   971  		name       string
   972  		newValue   string
   973  		hasDefault bool
   974  	)
   975  
   976  	arg := args[0]
   977  	// 'arg' can just be a name or name-value pair. Note that this is different
   978  	// from 'env' that handles the split of name and value at the parser level.
   979  	// The reason for doing it differently for 'arg' is that we support just
   980  	// defining an arg and not assign it a value (while 'env' always expects a
   981  	// name-value pair). If possible, it will be good to harmonize the two.
   982  	if strings.Contains(arg, "=") {
   983  		parts := strings.SplitN(arg, "=", 2)
   984  		if len(parts[0]) == 0 {
   985  			return "", errBlankCommandNames("ARG")
   986  		}
   987  
   988  		name = parts[0]
   989  		newValue = parts[1]
   990  		hasDefault = true
   991  	} else {
   992  		name = arg
   993  		hasDefault = false
   994  	}
   995  	// add the arg to allowed list of build-time args from this step on.
   996  	b.allowedBuildArgs[name] = true
   997  
   998  	// If there is a default value associated with this arg then add it to the
   999  	// b.buildArgs if one is not already passed to the builder. The args passed
  1000  	// to builder override the default value of 'arg'. Note that a 'nil' for
  1001  	// a value means that the user specified "--build-arg FOO" and "FOO" wasn't
  1002  	// defined as an env var - and in that case we DO want to use the default
  1003  	// value specified in the ARG cmd.
  1004  	if baValue, ok := b.options.BuildArgs[name]; (!ok || baValue == nil) && hasDefault {
  1005  		b.options.BuildArgs[name] = &newValue
  1006  	}
  1007  
  1008  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
  1009  }
  1010  
  1011  // SHELL powershell -command
  1012  //
  1013  // Set the non-default shell to use.
  1014  func shell(b *Builder, args []string, attributes map[string]bool, original string, tmpCID string, finishedFlag bool) (string, error) {
  1015      fmt.Println("dockerfile/dispatchers.go shell() tmpContainerID ", tmpCID)
  1016  
  1017  	if err := b.flags.Parse(); err != nil {
  1018  		return "", err
  1019  	}
  1020  	shellSlice := handleJSONArgs(args, attributes)
  1021  	switch {
  1022  	case len(shellSlice) == 0:
  1023  		// SHELL []
  1024  		return "", errAtLeastOneArgument("SHELL")
  1025  	case attributes["json"]:
  1026  		// SHELL ["powershell", "-command"]
  1027  		b.runConfig.Shell = strslice.StrSlice(shellSlice)
  1028  	default:
  1029  		// SHELL powershell -command - not JSON
  1030  		return "", errNotJSON("SHELL", original)
  1031  	}
  1032  	return b.commit("", b.runConfig.Cmd, fmt.Sprintf("SHELL %v", shellSlice))
  1033  }
  1034  
  1035  func errAtLeastOneArgument(command string) error {
  1036  	return fmt.Errorf("%s requires at least one argument", command)
  1037  }
  1038  
  1039  func errExactlyOneArgument(command string) error {
  1040  	return fmt.Errorf("%s requires exactly one argument", command)
  1041  }
  1042  
  1043  func errAtLeastTwoArguments(command string) error {
  1044  	return fmt.Errorf("%s requires at least two arguments", command)
  1045  }
  1046  
  1047  func errBlankCommandNames(command string) error {
  1048  	return fmt.Errorf("%s names can not be blank", command)
  1049  }
  1050  
  1051  func errTooManyArguments(command string) error {
  1052  	return fmt.Errorf("Bad input to %s, too many arguments", command)
  1053  }
  1054  
  1055  // getShell is a helper function which gets the right shell for prefixing the
  1056  // shell-form of RUN, ENTRYPOINT and CMD instructions
  1057  func getShell(c *container.Config) []string {
  1058  	if 0 == len(c.Shell) {
  1059  		return defaultShell[:]
  1060  	}
  1061  	return c.Shell[:]
  1062  }