func (c *ToolCmd) Execute(args []string) error { tc, err := toolchain.Open(string(c.Args.Toolchain), c.ToolchainMode()) if err != nil { log.Fatal(err) } var cmder interface { Command() (*exec.Cmd, error) } if c.Args.Tool != "" { cmder, err = toolchain.OpenTool(string(c.Args.Toolchain), string(c.Args.Tool), c.ToolchainMode()) } else { cmder = tc } // HACK: Buffer stdout to work around // https://github.com/docker/docker/issues/3631. Otherwise, lots // of builds fail. Also, if a lot of data is printed, the return // code is 0, but JSON parsing fails, retry it up to 4 times until // JSON parsing succeeds. for tries := 4; ; tries-- { cmd, err := cmder.Command() if err != nil { log.Fatal(err) } cmd.Args = append(cmd.Args, c.Args.ToolArgs...) cmd.Stderr = os.Stderr var out bytes.Buffer cmd.Stdout = &out cmd.Stdin = os.Stdin if GlobalOpt.Verbose { log.Printf("Running tool: %v", cmd.Args) } if err := cmd.Run(); err != nil { log.Fatal(err) } b := out.Bytes() if tries > 0 { // Try parsing (see HACK) above. if len(b) > 2000 { var o interface{} if err := json.Unmarshal(b, &o); err != nil { log.Printf("Suspect JSON output by %v (%d bytes, parse error %q); retrying %d more times. (This is a workaround for https://github.com/docker/docker/issues/3631.)", cmd.Args, len(b), err, tries) continue // retry } } } os.Stdout.Write(b) return nil } }
func (c *ToolchainBuildCmd) Execute(args []string) error { var wg sync.WaitGroup for _, tc := range c.Args.Toolchains { tc, err := toolchain.Open(string(tc), toolchain.AsDockerContainer) if err != nil { log.Fatal(err) } wg.Add(1) go func() { defer wg.Done() if err := tc.Build(); err != nil { log.Fatal(err) } }() } wg.Wait() return nil }