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

     1  package dockerfile
     2  
     3  // internals for handling commands. Covers many areas and a lot of
     4  // non-contiguous functionality. Please read the comments.
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"encoding/hex"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"net/http"
    14  	"net/url"
    15  	"os"
    16  	"path/filepath"
    17  	"sort"
    18  	"strings"
    19  	"time"
    20      
    21  //    containerd "github.com/docker/containerd/api/grpc/types"
    22  
    23  	"github.com/Sirupsen/logrus"
    24  	"github.com/docker/docker/api/types"
    25  	"github.com/docker/docker/api/types/backend"
    26  	"github.com/docker/docker/api/types/container"
    27  	"github.com/docker/docker/api/types/strslice"
    28  	"github.com/docker/docker/builder"
    29  	"github.com/docker/docker/builder/dockerfile/parser"
    30  	"github.com/docker/docker/pkg/archive"
    31  	"github.com/docker/docker/pkg/httputils"
    32  	"github.com/docker/docker/pkg/ioutils"
    33  	"github.com/docker/docker/pkg/jsonmessage"
    34  	"github.com/docker/docker/pkg/progress"
    35  	"github.com/docker/docker/pkg/streamformatter"
    36  	"github.com/docker/docker/pkg/stringid"
    37  	"github.com/docker/docker/pkg/system"
    38  	"github.com/docker/docker/pkg/tarsum"
    39  	"github.com/docker/docker/pkg/urlutil"
    40  	"github.com/docker/docker/runconfig/opts"
    41  )
    42  
    43  func (b *Builder) commit(id string, autoCmd strslice.StrSlice, comment string,) (string, error) {
    44  
    45      fmt.Println("dockerfile/internals.go commit()")
    46  
    47      if b.disableCommit {
    48  		return "", nil
    49  	}
    50  	if b.image == "" && !b.noBaseImage {
    51  		return "", fmt.Errorf("Please provide a source image with `from` prior to commit")
    52  	}
    53  	b.runConfig.Image = b.image
    54  
    55  	if id == "" {
    56          fmt.Println("dockerfile/internals.go  commit()  id is null")
    57  		cmd := b.runConfig.Cmd
    58  		b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), "#(nop) ", comment))
    59  		defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
    60  
    61  		hit, err := b.probeCache()
    62  		if err != nil {
    63  			return "", err
    64  		} else if hit {
    65  			return "", nil
    66  		}
    67  		id, err = b.create()
    68  		if err != nil {
    69  			return "", err
    70  		}
    71  	}
    72  
    73  
    74  	// Note: Actually copy the struct
    75  	autoConfig := *b.runConfig
    76  	autoConfig.Cmd = autoCmd
    77  
    78  	commitCfg := &backend.ContainerCommitConfig{
    79  		ContainerCommitConfig: types.ContainerCommitConfig{
    80  			Author: b.maintainer,
    81  			Pause:  true,
    82  			Config: &autoConfig,
    83  		},
    84  	}
    85  
    86  	// Commit the container
    87  	imageID, err := b.docker.Commit(id, commitCfg)
    88  	if err != nil {
    89  		return "", err
    90  	}
    91  
    92  	b.image = imageID
    93  	return "", nil
    94  }
    95  
    96  type copyInfo struct {
    97  	builder.FileInfo
    98  	decompress bool
    99  }
   100  
   101  func (b *Builder) runContextCommand(args []string, allowRemote bool, allowLocalDecompression bool, cmdName string) (string, error) {
   102  	if b.context == nil {
   103  		return "", fmt.Errorf("No context given. Impossible to use %s", cmdName)
   104  	}
   105  
   106  	if len(args) < 2 {
   107  		return "", fmt.Errorf("Invalid %s format - at least two arguments required", cmdName)
   108  	}
   109  
   110      fmt.Println("internals.go runContextCommand()")
   111  
   112  	// Work in daemon-specific filepath semantics
   113  	dest := filepath.FromSlash(args[len(args)-1]) // last one is always the dest
   114  
   115  	b.runConfig.Image = b.image
   116  
   117  	var infos []copyInfo
   118  
   119  	// Loop through each src file and calculate the info we need to
   120  	// do the copy (e.g. hash value if cached).  Don't actually do
   121  	// the copy until we've looked at all src files
   122  	var err error
   123  	for _, orig := range args[0 : len(args)-1] {
   124  		var fi builder.FileInfo
   125  		decompress := allowLocalDecompression
   126  		if urlutil.IsURL(orig) {
   127  			if !allowRemote {
   128  				return "", fmt.Errorf("Source can't be a URL for %s", cmdName)
   129  			}
   130  			fi, err = b.download(orig)
   131  			if err != nil {
   132  				return "", err
   133  			}
   134  			defer os.RemoveAll(filepath.Dir(fi.Path()))
   135  			decompress = false
   136  			infos = append(infos, copyInfo{fi, decompress})
   137  			continue
   138  		}
   139  		// not a URL
   140  		subInfos, err := b.calcCopyInfo(cmdName, orig, allowLocalDecompression, true)
   141  		if err != nil {
   142  			return "", err
   143  		}
   144  
   145  		infos = append(infos, subInfos...)
   146  	}
   147  
   148  	if len(infos) == 0 {
   149  		return "", fmt.Errorf("No source files were specified")
   150  	}
   151  	if len(infos) > 1 && !strings.HasSuffix(dest, string(os.PathSeparator)) {
   152  		return "", fmt.Errorf("When using %s with more than one source file, the destination must be a directory and end with a /", cmdName)
   153  	}
   154  
   155  	// For backwards compat, if there's just one info then use it as the
   156  	// cache look-up string, otherwise hash 'em all into one
   157  	var srcHash string
   158  	var origPaths string
   159  
   160  	if len(infos) == 1 {
   161  		fi := infos[0].FileInfo
   162  		origPaths = fi.Name()
   163  		if hfi, ok := fi.(builder.Hashed); ok {
   164  			srcHash = hfi.Hash()
   165  		}
   166  	} else {
   167  		var hashs []string
   168  		var origs []string
   169  		for _, info := range infos {
   170  			fi := info.FileInfo
   171  			origs = append(origs, fi.Name())
   172  			if hfi, ok := fi.(builder.Hashed); ok {
   173  				hashs = append(hashs, hfi.Hash())
   174  			}
   175  		}
   176  		hasher := sha256.New()
   177  		hasher.Write([]byte(strings.Join(hashs, ",")))
   178  		srcHash = "multi:" + hex.EncodeToString(hasher.Sum(nil))
   179  		origPaths = strings.Join(origs, " ")
   180  	}
   181  
   182  	cmd := b.runConfig.Cmd
   183  	b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), fmt.Sprintf("#(nop) %s %s in %s ", cmdName, srcHash, dest)))
   184  	defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd)
   185  
   186  	if hit, err := b.probeCache(); err != nil {
   187  		return "", err
   188  	} else if hit {
   189  		return "", nil
   190  	}
   191  
   192  	container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig})
   193  	if err != nil {
   194  		return "", err
   195  	}
   196  	b.tmpContainers[container.ID] = struct{}{}
   197  
   198  	comment := fmt.Sprintf("%s %s in %s", cmdName, origPaths, dest)
   199  
   200  	// Twiddle the destination when its a relative path - meaning, make it
   201  	// relative to the WORKINGDIR
   202  	if dest, err = normaliseDest(cmdName, b.runConfig.WorkingDir, dest); err != nil {
   203  		return "", err
   204  	}
   205  
   206  	for _, info := range infos {
   207  		if err := b.docker.CopyOnBuild(container.ID, dest, info.FileInfo, info.decompress); err != nil {
   208  			return "", err
   209  		}
   210  	}
   211  
   212  	return b.commit(container.ID, cmd, comment)
   213  }
   214  
   215  func (b *Builder) download(srcURL string) (fi builder.FileInfo, err error) {
   216  	// get filename from URL
   217  	u, err := url.Parse(srcURL)
   218  	if err != nil {
   219  		return
   220  	}
   221  	path := filepath.FromSlash(u.Path) // Ensure in platform semantics
   222  	if strings.HasSuffix(path, string(os.PathSeparator)) {
   223  		path = path[:len(path)-1]
   224  	}
   225  	parts := strings.Split(path, string(os.PathSeparator))
   226  	filename := parts[len(parts)-1]
   227  	if filename == "" {
   228  		err = fmt.Errorf("cannot determine filename from url: %s", u)
   229  		return
   230  	}
   231  
   232  	// Initiate the download
   233  	resp, err := httputils.Download(srcURL)
   234  	if err != nil {
   235  		return
   236  	}
   237  
   238  	// Prepare file in a tmp dir
   239  	tmpDir, err := ioutils.TempDir("", "docker-remote")
   240  	if err != nil {
   241  		return
   242  	}
   243  	defer func() {
   244  		if err != nil {
   245  			os.RemoveAll(tmpDir)
   246  		}
   247  	}()
   248  	tmpFileName := filepath.Join(tmpDir, filename)
   249  	tmpFile, err := os.OpenFile(tmpFileName, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
   250  	if err != nil {
   251  		return
   252  	}
   253  
   254  	stdoutFormatter := b.Stdout.(*streamformatter.StdoutFormatter)
   255  	progressOutput := stdoutFormatter.StreamFormatter.NewProgressOutput(stdoutFormatter.Writer, true)
   256  	progressReader := progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Downloading")
   257  	// Download and dump result to tmp file
   258  	if _, err = io.Copy(tmpFile, progressReader); err != nil {
   259  		tmpFile.Close()
   260  		return
   261  	}
   262  	fmt.Fprintln(b.Stdout)
   263  	// ignoring error because the file was already opened successfully
   264  	tmpFileSt, err := tmpFile.Stat()
   265  	if err != nil {
   266  		tmpFile.Close()
   267  		return
   268  	}
   269  
   270  	// Set the mtime to the Last-Modified header value if present
   271  	// Otherwise just remove atime and mtime
   272  	mTime := time.Time{}
   273  
   274  	lastMod := resp.Header.Get("Last-Modified")
   275  	if lastMod != "" {
   276  		// If we can't parse it then just let it default to 'zero'
   277  		// otherwise use the parsed time value
   278  		if parsedMTime, err := http.ParseTime(lastMod); err == nil {
   279  			mTime = parsedMTime
   280  		}
   281  	}
   282  
   283  	tmpFile.Close()
   284  
   285  	if err = system.Chtimes(tmpFileName, mTime, mTime); err != nil {
   286  		return
   287  	}
   288  
   289  	// Calc the checksum, even if we're using the cache
   290  	r, err := archive.Tar(tmpFileName, archive.Uncompressed)
   291  	if err != nil {
   292  		return
   293  	}
   294  	tarSum, err := tarsum.NewTarSum(r, true, tarsum.Version1)
   295  	if err != nil {
   296  		return
   297  	}
   298  	if _, err = io.Copy(ioutil.Discard, tarSum); err != nil {
   299  		return
   300  	}
   301  	hash := tarSum.Sum(nil)
   302  	r.Close()
   303  	return &builder.HashedFileInfo{FileInfo: builder.PathFileInfo{FileInfo: tmpFileSt, FilePath: tmpFileName}, FileHash: hash}, nil
   304  }
   305  
   306  func (b *Builder) calcCopyInfo(cmdName, origPath string, allowLocalDecompression, allowWildcards bool) ([]copyInfo, error) {
   307  
   308  	// Work in daemon-specific OS filepath semantics
   309  	origPath = filepath.FromSlash(origPath)
   310  
   311  	if origPath != "" && origPath[0] == os.PathSeparator && len(origPath) > 1 {
   312  		origPath = origPath[1:]
   313  	}
   314  	origPath = strings.TrimPrefix(origPath, "."+string(os.PathSeparator))
   315  
   316  	// Deal with wildcards
   317  	if allowWildcards && containsWildcards(origPath) {
   318  		var copyInfos []copyInfo
   319  		if err := b.context.Walk("", func(path string, info builder.FileInfo, err error) error {
   320  			if err != nil {
   321  				return err
   322  			}
   323  			if info.Name() == "" {
   324  				// Why are we doing this check?
   325  				return nil
   326  			}
   327  			if match, _ := filepath.Match(origPath, path); !match {
   328  				return nil
   329  			}
   330  
   331  			// Note we set allowWildcards to false in case the name has
   332  			// a * in it
   333  			subInfos, err := b.calcCopyInfo(cmdName, path, allowLocalDecompression, false)
   334  			if err != nil {
   335  				return err
   336  			}
   337  			copyInfos = append(copyInfos, subInfos...)
   338  			return nil
   339  		}); err != nil {
   340  			return nil, err
   341  		}
   342  		return copyInfos, nil
   343  	}
   344  
   345  	// Must be a dir or a file
   346  
   347  	statPath, fi, err := b.context.Stat(origPath)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	copyInfos := []copyInfo{{FileInfo: fi, decompress: allowLocalDecompression}}
   353  
   354  	hfi, handleHash := fi.(builder.Hashed)
   355  	if !handleHash {
   356  		return copyInfos, nil
   357  	}
   358  
   359  	// Deal with the single file case
   360  	if !fi.IsDir() {
   361  		hfi.SetHash("file:" + hfi.Hash())
   362  		return copyInfos, nil
   363  	}
   364  	// Must be a dir
   365  	var subfiles []string
   366  	err = b.context.Walk(statPath, func(path string, info builder.FileInfo, err error) error {
   367  		if err != nil {
   368  			return err
   369  		}
   370  		// we already checked handleHash above
   371  		subfiles = append(subfiles, info.(builder.Hashed).Hash())
   372  		return nil
   373  	})
   374  	if err != nil {
   375  		return nil, err
   376  	}
   377  
   378  	sort.Strings(subfiles)
   379  	hasher := sha256.New()
   380  	hasher.Write([]byte(strings.Join(subfiles, ",")))
   381  	hfi.SetHash("dir:" + hex.EncodeToString(hasher.Sum(nil)))
   382  
   383  	return copyInfos, nil
   384  }
   385  
   386  func (b *Builder) processImageFrom(img builder.Image) (string, error) {
   387  	if img != nil {
   388      fmt.Println("internals.go processImageFrom  image!=nil")
   389  		b.image = img.ImageID()
   390  
   391  		if img.RunConfig() != nil {
   392  			b.runConfig = img.RunConfig()
   393      fmt.Println("internals.go processImageFrom  img.RunConfig!=nil ", b.runConfig.Image)        
   394  		}
   395  	}
   396  
   397      fmt.Println("internals.go  processImageFrom()")
   398  
   399  	// Check to see if we have a default PATH, note that windows won't
   400  	// have one as its set by HCS
   401  	if system.DefaultPathEnv != "" {
   402  		// Convert the slice of strings that represent the current list
   403  		// of env vars into a map so we can see if PATH is already set.
   404  		// If its not set then go ahead and give it our default value
   405  		configEnv := opts.ConvertKVStringsToMap(b.runConfig.Env)
   406  		if _, ok := configEnv["PATH"]; !ok {
   407  			b.runConfig.Env = append(b.runConfig.Env,
   408  				"PATH="+system.DefaultPathEnv)
   409  		}
   410  	}
   411  
   412  	if img == nil {
   413  		// Typically this means they used "FROM scratch"
   414  		return "", nil
   415  	}
   416  
   417  	// Process ONBUILD triggers if they exist
   418  	if nTriggers := len(b.runConfig.OnBuild); nTriggers != 0 {
   419  		word := "trigger"
   420  		if nTriggers > 1 {
   421  			word = "triggers"
   422  		}
   423  		fmt.Fprintf(b.Stderr, "# Executing %d build %s...\n", nTriggers, word)
   424  	}
   425  
   426  	// Copy the ONBUILD triggers, and remove them from the config, since the config will be committed.
   427  	onBuildTriggers := b.runConfig.OnBuild
   428  	b.runConfig.OnBuild = []string{}
   429  
   430  	// parse the ONBUILD triggers by invoking the parser
   431  	for _, step := range onBuildTriggers {
   432  		ast, err := parser.Parse(strings.NewReader(step), &b.directive)
   433  		if err != nil {
   434  			return "", err
   435  		}
   436  
   437  		total := len(ast.Children)
   438  		for _, n := range ast.Children {
   439  			if err := b.checkDispatch(n, true); err != nil {
   440  				return "", err
   441  			}
   442  		}
   443  		for i, n := range ast.Children {
   444  			if _, err := b.dispatch(i, total, n, ""); err != nil {
   445  				return "", err
   446  			}
   447  		}
   448  	}
   449  
   450     
   451      //start the base image
   452  
   453      fmt.Println("internals.go/processImageFrom  start the base image ")
   454      fmt.Println("internals.go/processImageFrom  start the base image ", b.image)
   455      fmt.Println("internals.go/processImageFrom  start the base image ", b.runConfig.Image)
   456      fmt.Println("internals.go/processImageFrom  start the base image ", b.runConfig.Cmd)
   457      fmt.Println("internals.go/processImageFrom  start the base image ", b.runConfig.Env)
   458      fmt.Println("internals.go/processImageFrom  start the base image ", b.runConfig.ArgsEscaped)
   459      
   460  //    b.runConfig.Image = b.image
   461  //    bContainerID, err := b.create()
   462  //    fmt.Println("start the base image : %v", bContainerID)
   463  //    if err != nil {
   464  //        return "", err
   465  //    }
   466  
   467      
   468      fmt.Println("internals.go/processImageFrom  before run the base image ", b.noBaseImage)
   469  
   470  //    if err := b.run(bContainerID);err != nil {
   471  //        return "", err
   472  //    }
   473  
   474  //    b.startFirstContainer(bContainerID)
   475  
   476  //    return bContainerID, nil
   477  	return "", nil
   478  }
   479  
   480  func (b *Builder) startFirstContainer(id string) error {
   481      fmt.Println("internals.go startFirstContainer() ", id)
   482      return b.docker.GetFirstContainerStatus(id) 
   483  }
   484  
   485  
   486  /*
   487  
   488  type ExecConfig struct {
   489  	User         string   // User that will run the command
   490  	Privileged   bool     // Is the container in privileged mode
   491  	Tty          bool     // Attach standard streams to a tty.
   492  	AttachStdin  bool     // Attach the standard input, makes possible user interaction
   493  	AttachStderr bool     // Attach the standard error
   494  	AttachStdout bool     // Attach the standard output
   495  	Detach       bool     // Execute in detach mode
   496  	DetachKeys   string   // Escape keys for detach
   497  	Env          []string // Environment variables
   498  	Cmd          []string // Execution commands and args
   499  }
   500  
   501  */
   502  
   503  /*
   504  //name     container 
   505  //config   exec 
   506  func (b *Builder) firstContainerExecCreate(name string, execConfig *types.ExecConfig) error {
   507      fmt.Println("builder/dockerfile/internals.go   firstContainerExecCreate()")
   508  
   509  	if len(execConfig.Cmd) == 0 {
   510  		return fmt.Errorf("No exec command specified")
   511  	}
   512  
   513      fmt.Println("builder/dockerfile/internals.go  firstContainerExecCreate() : ", execConfig.Cmd)
   514  
   515  	id, err := b.docker.ContainerExecCreate(name, config)
   516  	if err != nil {
   517  		fmt.Println("builder/dockerfile/internals.go  firstContainerExecCreate()  err!=nil")
   518          return "", err
   519  	}
   520  
   521      return nil
   522  }
   523  */
   524  
   525  
   526  
   527  /*
   528  func (b *Builder) firstContainerExecStart(ctx context.Context, vars map[string]string) error {
   529  
   530  	var (
   531  		execName                  = vars["name"]
   532  		stdin, inStream           io.ReadCloser
   533  		stdout, stderr, outStream io.Writer
   534  	)
   535  
   536  	execStartCheck := &types.ExecStartCheck{}
   537  	if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
   538  		return err
   539  	}
   540  
   541      fmt.Println("builder/dockerfile/internals.go   firstContainerExecStart() : ", execName)
   542  	if exists, err := s.backend.ExecExists(execName); !exists {
   543  		return err
   544  	}
   545  
   546  	// Now run the user process in container.
   547  	// Maybe we should we pass ctx here if we're not detaching?
   548      fmt.Println("api/server/router/container/exec.go   postContainerExecStart() ")
   549  	
   550      if err := b.docker.ContainerExecStart(context.Background(), execName, stdin, stdout, stderr); err != nil {
   551  		if execStartCheck.Detach {
   552  			return err
   553  		}
   554  	}
   555  
   556      fmt.Println("builder/dockerfile/internals.go  firstContainerExecStart() ContainerExecStart()")
   557  	return nil
   558  }
   559  
   560  
   561  //func (daemon *Daemon) GetFirstContainerStatus(id string) error {
   562      container, err := daemon.GetContainer(id)
   563      if err != nil {
   564         return err
   565      }
   566      fmt.Println("internals.go getFirstContainer() ", container.ImageID)
   567      return nil
   568  }
   569  
   570  
   571  func (b *Builder) startFirstContainer() error {
   572       if b.disableCommit {
   573           return nil
   574       }
   575       if b.image == "" && !b.noBaseImage {
   576           return fmt.Errorf("Please provide a image ")
   577       }
   578       b.runConfig.Image = b.image
   579  
   580       id, err = b.create()
   581       if err != nil {
   582            return err
   583       }
   584  }
   585  
   586  func firstContainerExecCmd() error {
   587  
   588  }
   589  
   590  */
   591  
   592  
   593  
   594  // probeCache checks if cache match can be found for current build instruction.
   595  // If an image is found, probeCache returns `(true, nil)`.
   596  // If no image is found, it returns `(false, nil)`.
   597  // If there is any error, it returns `(false, err)`.
   598  func (b *Builder) probeCache() (bool, error) {
   599  	c := b.imageCache
   600  	if c == nil || b.options.NoCache || b.cacheBusted {
   601  		return false, nil
   602  	}
   603  	cache, err := c.GetCache(b.image, b.runConfig)
   604  	if err != nil {
   605  		return false, err
   606  	}
   607  	if len(cache) == 0 {
   608  		logrus.Debugf("[BUILDER] Cache miss: %s", b.runConfig.Cmd)
   609  		b.cacheBusted = true
   610  		return false, nil
   611  	}
   612  
   613  	fmt.Fprintf(b.Stdout, " ---> Using cache\n")
   614  	logrus.Debugf("[BUILDER] Use cached version: %s", b.runConfig.Cmd)
   615  	b.image = string(cache)
   616  
   617  	return true, nil
   618  }
   619  
   620  func (b *Builder) create() (string, error) {
   621  	if b.image == "" && !b.noBaseImage {
   622  		return "", fmt.Errorf("Please provide a source image with `from` prior to run")
   623  	}
   624  	b.runConfig.Image = b.image
   625  
   626      fmt.Println("internals.go create() ")
   627  
   628  	resources := container.Resources{
   629  		CgroupParent: b.options.CgroupParent,
   630  		CPUShares:    b.options.CPUShares,
   631  		CPUPeriod:    b.options.CPUPeriod,
   632  		CPUQuota:     b.options.CPUQuota,
   633  		CpusetCpus:   b.options.CPUSetCPUs,
   634  		CpusetMems:   b.options.CPUSetMems,
   635  		Memory:       b.options.Memory,
   636  		MemorySwap:   b.options.MemorySwap,
   637  		Ulimits:      b.options.Ulimits,
   638  	}
   639  
   640  	// TODO: why not embed a hostconfig in builder?
   641  	hostConfig := &container.HostConfig{
   642  		SecurityOpt: b.options.SecurityOpt,
   643  		Isolation:   b.options.Isolation,
   644  		ShmSize:     b.options.ShmSize,
   645  		Resources:   resources,
   646  		NetworkMode: container.NetworkMode(b.options.NetworkMode),
   647  	}
   648  
   649  	config := *b.runConfig
   650  
   651  	// Create the container
   652  	c, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
   653  		Config:     b.runConfig,
   654  		HostConfig: hostConfig,
   655  	})
   656  	if err != nil {
   657  		return "", err
   658  	}
   659  	for _, warning := range c.Warnings {
   660  		fmt.Fprintf(b.Stdout, " ---> [Warning] %s\n", warning)
   661  	}
   662  
   663  	b.tmpContainers[c.ID] = struct{}{}
   664  	fmt.Fprintf(b.Stdout, " ---> Running in %s   internals.go/create()\n", stringid.TruncateID(c.ID))
   665  
   666  	// override the entry point that may have been picked up from the base image
   667  	if err := b.docker.ContainerUpdateCmdOnBuild(c.ID, config.Cmd); err != nil {
   668  		return "", err
   669  	}
   670  
   671  	return c.ID, nil
   672  }
   673  
   674  var errCancelled = errors.New("build cancelled")
   675  
   676  func (b *Builder) run(cID string) (err error) {
   677      fmt.Println("dockerfile/dispatchers.go  run()")
   678  	errCh := make(chan error)
   679  	go func() {
   680  		errCh <- b.docker.ContainerAttachRaw(cID, nil, b.Stdout, b.Stderr, true)
   681  	}()
   682  
   683  	finished := make(chan struct{})
   684  	cancelErrCh := make(chan error, 1)
   685  	go func() {
   686  		select {
   687  		case <-b.clientCtx.Done():
   688  			logrus.Debugln("Build cancelled, killing and removing container:", cID)
   689  			b.docker.ContainerKill(cID, 0)
   690  			b.removeContainer(cID)
   691  			cancelErrCh <- errCancelled
   692  		case <-finished:
   693  			cancelErrCh <- nil
   694  		}
   695  	}()
   696  
   697  
   698      fmt.Println("internals.go run before ContainerStart")
   699  
   700  	if err := b.docker.ContainerStart(cID, nil, "", ""); err != nil {
   701  		close(finished)
   702  		if cancelErr := <-cancelErrCh; cancelErr != nil {
   703  			logrus.Debugf("Build cancelled (%v) and got an error from ContainerStart: %v",
   704  				cancelErr, err)
   705  		}
   706  		return err
   707  	}
   708  
   709      fmt.Println("builder/dockerfile/internals.go run after ContainerStart")
   710  
   711      fmt.Println("builder/dockerfile/internals.go run begin to receive finished event!!!")
   712  
   713  
   714  	// Block on reading output from container, stop on err or chan closed
   715  /*	if err := <-errCh; err != nil {
   716          fmt.Println("internals.go ContainerStart err!=nil before close")
   717  		close(finished)
   718          fmt.Println("internals.go ContainerStart err!=nil after close")
   719  		if cancelErr := <-cancelErrCh; cancelErr != nil {
   720  			logrus.Debugf("Build cancelled (%v) and got an error from errCh: %v",
   721  				cancelErr, err)
   722              fmt.Println("internals.go/run() got an error from errCh")
   723  		}
   724  		return err
   725  	}
   726  */
   727     
   728  /*    ret, _ := b.docker.ContainerWait(cID, -1)
   729      if ret != 0 {
   730  		close(finished)
   731  		if cancelErr := <-cancelErrCh; cancelErr != nil {
   732  			logrus.Debugf("Build cancelled (%v) and got a non-zero code from ContainerWait: %d",
   733  				cancelErr, ret)
   734  		}
   735  		// TODO: change error type, because jsonmessage.JSONError assumes HTTP
   736  		return &jsonmessage.JSONError{
   737  			Message: fmt.Sprintf("The command '%s' returned a non-zero code: %d", strings.Join(b.runConfig.Cmd, " "), ret),
   738  			Code:    ret,
   739  		}
   740  	}
   741  */   
   742      fmt.Println("dockerfile/internals.go run() remove the ContainerWait()")
   743      b.docker.GetFirstContainerStatus(cID)
   744  
   745  	close(finished)
   746  	return <-cancelErrCh
   747  }
   748  
   749  
   750  
   751  func (b *Builder) stopContainerBeforeCommit(cID string) (err error) {
   752      fmt.Println("dockerfile/internals.go  stopContainerBeforeCommit()")
   753      
   754      fmt.Println("dockerfile/internals.go  stopContainerBeforeCommit() set false to building status!")    
   755      if err := b.docker.SetFirstContainerBuildingStatus(cID, false); err != nil {
   756          fmt.Println("dockerfile/internals.go  stopContainerBeforeCommit() set building status is err!!!")
   757          return err 
   758      }
   759  /*
   760      e := &containerd.Event{
   761           Type:      "exit",
   762           Id:        cID,
   763           Status:    "",
   764           Pid:       "init",
   765           Timestamp  time.Now().UnixNano()
   766      }
   767  
   768      container, err := b.docker.GetFirstContainer(cID)
   769      if err != nil {
   770          return err
   771      }
   772      if err := container.handleEvent(e); err != nil {
   773          fmt.Println("dockerfile/internals.go  stopContainerBeforeCommit() handleEvent is err!!!")
   774      }
   775  */
   776  
   777      if err := b.docker.TriggerExitEvent(cID); err != nil {
   778          fmt.Println("dockerfile/internals.go  stopContainerBeforeCommit() triggger exit event  err!!!")
   779          return err
   780      }
   781      fmt.Println("dockerfile/internals.go  stopContainerBeforeCommit() triggger exit event  success!!!")
   782  
   783  
   784      errCh := make(chan error)
   785  	go func() {
   786  		errCh <- b.docker.ContainerAttachRaw(cID, nil, b.Stdout, b.Stderr, true)
   787  	}()
   788  
   789  	finished := make(chan struct{})
   790  	cancelErrCh := make(chan error, 1)
   791  	go func() {
   792  		select {
   793  		case <-b.clientCtx.Done():
   794  			logrus.Debugln("Build cancelled, killing and removing container:", cID)
   795  			b.docker.ContainerKill(cID, 0)
   796  			b.removeContainer(cID)
   797  			cancelErrCh <- errCancelled
   798  		case <-finished:
   799  			cancelErrCh <- nil
   800  		}
   801  	}()
   802  
   803      fmt.Println("dockerfile/internals.go stopContainerBeforeCommit() receive finished event!!!")
   804  
   805  	// Block on reading output from container, stop on err or chan closed
   806  	errChannel := <-errCh
   807      fmt.Println("dockerfile/internals.go stopContainerBeforeCommit() channel message : ", errChannel)
   808      if errChannel != nil {
   809          fmt.Println("internals.go ContainerStart err!=nil before close")
   810  		close(finished)
   811          fmt.Println("internals.go ContainerStart err!=nil after close")
   812  		if cancelErr := <-cancelErrCh; cancelErr != nil {
   813  			logrus.Debugf("Build cancelled (%v) and got an error from errCh: %v",
   814  				cancelErr, err)
   815              fmt.Println("internals.go/run() got an error from errCh")
   816  		}
   817  		return err
   818  	}
   819   
   820     
   821      fmt.Println("dockerfile/internals.go stopContainerBeforeCommit() before ContainerWait")
   822      ret, _ := b.docker.ContainerWait(cID, -1)
   823      if ret != 0 {
   824  		close(finished)
   825  		if cancelErr := <-cancelErrCh; cancelErr != nil {
   826  			logrus.Debugf("Build cancelled (%v) and got a non-zero code from ContainerWait: %d",
   827  				cancelErr, ret)
   828  		}
   829  		// TODO: change error type, because jsonmessage.JSONError assumes HTTP
   830  		return &jsonmessage.JSONError{
   831  			Message: fmt.Sprintf("The command '%s' returned a non-zero code: %d", strings.Join(b.runConfig.Cmd, " "), ret),
   832  			Code:    ret,
   833  		}
   834  	}
   835     
   836      fmt.Println("dockerfile/internals.go stopContainerBeforeCommit() finished ")
   837      b.docker.GetFirstContainerStatus(cID)
   838      fmt.Println("dockerfile/internals.go  before commit the container is stopped!!!")
   839  
   840  	close(finished)
   841  	return <-cancelErrCh
   842  }
   843  
   844  
   845  
   846  
   847  func (b *Builder) removeContainer(c string) error {
   848  	rmConfig := &types.ContainerRmConfig{
   849  		ForceRemove:  true,
   850  		RemoveVolume: true,
   851  	}
   852  	if err := b.docker.ContainerRm(c, rmConfig); err != nil {
   853  		fmt.Fprintf(b.Stdout, "Error removing intermediate container %s: %v\n", stringid.TruncateID(c), err)
   854  		return err
   855  	}
   856  	return nil
   857  }
   858  
   859  func (b *Builder) clearTmp() {
   860  	for c := range b.tmpContainers {
   861  		if err := b.removeContainer(c); err != nil {
   862  			return
   863  		}
   864  		delete(b.tmpContainers, c)
   865  		fmt.Fprintf(b.Stdout, "Removing intermediate container %s internals.go/clearTmp()\n", stringid.TruncateID(c))
   866  	}
   867  }
   868  
   869  // readDockerfile reads a Dockerfile from the current context.
   870  func (b *Builder) readDockerfile() error {
   871  	// If no -f was specified then look for 'Dockerfile'. If we can't find
   872  	// that then look for 'dockerfile'.  If neither are found then default
   873  	// back to 'Dockerfile' and use that in the error message.
   874  	if b.options.Dockerfile == "" {
   875  		b.options.Dockerfile = builder.DefaultDockerfileName
   876  		if _, _, err := b.context.Stat(b.options.Dockerfile); os.IsNotExist(err) {
   877  			lowercase := strings.ToLower(b.options.Dockerfile)
   878  			if _, _, err := b.context.Stat(lowercase); err == nil {
   879  				b.options.Dockerfile = lowercase
   880  			}
   881  		}
   882  	}
   883  
   884  	err := b.parseDockerfile()
   885  
   886  	if err != nil {
   887  		return err
   888  	}
   889  
   890  	// After the Dockerfile has been parsed, we need to check the .dockerignore
   891  	// file for either "Dockerfile" or ".dockerignore", and if either are
   892  	// present then erase them from the build context. These files should never
   893  	// have been sent from the client but we did send them to make sure that
   894  	// we had the Dockerfile to actually parse, and then we also need the
   895  	// .dockerignore file to know whether either file should be removed.
   896  	// Note that this assumes the Dockerfile has been read into memory and
   897  	// is now safe to be removed.
   898  	if dockerIgnore, ok := b.context.(builder.DockerIgnoreContext); ok {
   899  		dockerIgnore.Process([]string{b.options.Dockerfile})
   900  	}
   901  	return nil
   902  }
   903  
   904  func (b *Builder) parseDockerfile() error {
   905  	f, err := b.context.Open(b.options.Dockerfile)
   906  	if err != nil {
   907  		if os.IsNotExist(err) {
   908  			return fmt.Errorf("Cannot locate specified Dockerfile: %s", b.options.Dockerfile)
   909  		}
   910  		return err
   911  	}
   912  	defer f.Close()
   913  	if f, ok := f.(*os.File); ok {
   914  		// ignoring error because Open already succeeded
   915  		fi, err := f.Stat()
   916  		if err != nil {
   917  			return fmt.Errorf("Unexpected error reading Dockerfile: %v", err)
   918  		}
   919  		if fi.Size() == 0 {
   920  			return fmt.Errorf("The Dockerfile (%s) cannot be empty", b.options.Dockerfile)
   921  		}
   922  	}
   923  	b.dockerfile, err = parser.Parse(f, &b.directive)
   924  	if err != nil {
   925  		return err
   926  	}
   927  
   928  	return nil
   929  }
   930  
   931  // determine if build arg is part of built-in args or user
   932  // defined args in Dockerfile at any point in time.
   933  func (b *Builder) isBuildArgAllowed(arg string) bool {
   934  	if _, ok := BuiltinAllowedBuildArgs[arg]; ok {
   935  		return true
   936  	}
   937  	if _, ok := b.allowedBuildArgs[arg]; ok {
   938  		return true
   939  	}
   940  	return false
   941  }