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 *FmtCmd) Get() (string, error) { t, err := toolchain.ChooseTool(fmtOpt, c.UnitType) if err != nil { return "", err } // Only call as a program for now. tool, err := toolchain.OpenTool(t.Toolchain, t.Subcmd, toolchain.AsProgram) if err != nil { return "", err } cmd, err := tool.Command() if err != nil { return "", err } out := &bytes.Buffer{} cmd.Stdout = out cmd.Args = append(cmd.Args, "--unit-type", c.UnitType, "--object-type", c.ObjectType, "--format", c.Format, "--object", c.Object) if err := cmd.Run(); err != nil { return "", err } return out.String(), nil }
// scanUnitsIntoConfig uses cfg to scan for source units. It modifies // cfg.SourceUnits, merging the scanned source units with those already present // in cfg. func scanUnitsIntoConfig(cfg *config.Repository, configOpt config.Options, execOpt ToolchainExecOpt, quiet bool) error { scanners := make([]toolchain.Tool, len(cfg.Scanners)) for i, scannerRef := range cfg.Scanners { scanner, err := toolchain.OpenTool(scannerRef.Toolchain, scannerRef.Subcmd, execOpt.ToolchainMode()) if err != nil { return err } scanners[i] = scanner } units, err := scan.ScanMulti(scanners, scan.Options{Options: configOpt, Quiet: quiet}, cfg.Config) if err != nil { return err } // Merge the repo/tree config with each source unit's config. if cfg.Config == nil { cfg.Config = map[string]interface{}{} } for _, u := range units { for k, v := range cfg.Config { if uv, present := u.Config[k]; present { log.Printf("Both the scanned source unit %q and the Srcfile specify a Config key %q. Using the value from the scanned source unit (%+v).", u.ID(), k, uv) } else { if u.Config == nil { u.Config = map[string]interface{}{} } u.Config[k] = v } } } // collect manually specified source units by ID manualUnits := make(map[unit.ID]*unit.SourceUnit, len(cfg.SourceUnits)) for _, u := range cfg.SourceUnits { manualUnits[u.ID()] = u xf, err := unit.ExpandPaths(".", u.Files) if err != nil { return err } u.Files = xf } for _, u := range units { if mu, present := manualUnits[u.ID()]; present { log.Printf("Found manually specified source unit %q with same ID as scanned source unit. Using manually specified unit, ignoring scanned source unit.", mu.ID()) continue } unitDir := u.Dir if unitDir == "" && len(u.Files) > 0 { // in case the unit doesn't specify a Dir, obtain it from the first file unitDir = filepath.Dir(u.Files[0]) } // heed SkipDirs if pathHasAnyPrefix(unitDir, cfg.SkipDirs) { continue } skip := false for _, skipUnit := range cfg.SkipUnits { if u.Name == skipUnit.Name && u.Type == skipUnit.Type { skip = true break } } if skip { continue } cfg.SourceUnits = append(cfg.SourceUnits, u) } return nil }