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 }