func printStreams(result docker.CommandResult) { out := strings.TrimSpace(result.Stdout) err := strings.TrimSpace(result.Stderr) if len(out) > 0 { glog.Infof("stdout:\n%s\n", strings.TrimSpace(result.Stdout)) } if len(err) > 0 { glog.Errorf("stderr:\n%s\n", strings.TrimSpace(result.Stderr)) } }
func pull(image string) { if !docker.OutOfDate(image) { return } glog.Infof("Pulling image %s", image) result := docker.Pull(image) printStreams(result) if result.Err != nil { glog.Errorf("Error from pull: %v", result.Err) return } glog.Infoln("Pulling complete") }
func pull(image string) { // If we are "local", use a local version and don't actually do a pull. // Also don't pull if we aren't out of date yet. if strings.HasSuffix(image, ":local") || !docker.OutOfDate(image) { return } glog.Infof("Pulling image %s", image) result := docker.Pull(image) printStreams(result) if result.Err != nil { glog.Errorf("Error from pull: %v", result.Err) return } glog.Infoln("Pulling complete") }
func (i *Invocation) Run() (int, error) { glog.Infof("Starting shipshape...") fs, err := os.Stat(i.options.File) if err != nil { return 0, fmt.Errorf("%s is not a valid file or directory\n", i.options.File) } origDir := i.options.File if !fs.IsDir() { origDir = filepath.Dir(i.options.File) } absRoot, err := filepath.Abs(origDir) if err != nil { return 0, fmt.Errorf("could not get absolute path for %s: %v\n", origDir, err) } if !docker.HasDocker() { return 0, fmt.Errorf("docker could not be found. Make sure you have docker installed.") } image := docker.FullImageName(i.options.Repo, image, i.options.Tag) glog.Infof("Starting shipshape using %s on %s", image, absRoot) // Create the request if len(i.options.TriggerCats) == 0 { glog.Infof("No categories provided. Will be using categories specified by the config file for the event %s", i.options.Event) } if len(i.options.ThirdPartyAnalyzers) == 0 { i.options.ThirdPartyAnalyzers, err = service.GlobalConfig(absRoot) if err != nil { glog.Infof("Could not get global config; using only the default analyzers: %v", err) } } // If we are not running in local mode, pull the latest copy // Notice this will use the local tag as a signal to not pull the // third-party analyzers either. if i.options.Tag != "local" { pull(image) pullAnalyzers(i.options.ThirdPartyAnalyzers) } // Put in this defer before calling run. Even if run fails, it can // still create the container. if !i.options.StayUp { // TODO(ciera): Rather than immediately sending a SIGKILL, // we should use the default 10 seconds and properly handle // SIGTERMs in the endpoint script. defer stop("shipping_container", 0) // Stop all the analyzers, even the ones that had trouble starting, // in case they did actually start for id, analyzerRepo := range i.options.ThirdPartyAnalyzers { container, _ := getContainerAndAddress(analyzerRepo, id) defer stop(container, 0) } } containers, errs := startAnalyzers(absRoot, i.options.ThirdPartyAnalyzers, i.options.Dind) for _, err := range errs { glog.Errorf("Could not start up third party analyzer: %v", err) } var c *client.Client var req *rpcpb.ShipshapeRequest var numNotes int // Run it on files relativeRoot := "" c, relativeRoot, err = startShipshapeService(image, absRoot, containers, i.options.Dind) if err != nil { return 0, fmt.Errorf("HTTP client did not become healthy: %v", err) } var files []string if !fs.IsDir() { files = []string{filepath.Base(i.options.File)} } req = createRequest(i.options.TriggerCats, files, i.options.Event, filepath.Join(workspace, relativeRoot), ctxpb.Stage_PRE_BUILD.Enum()) glog.Infof("Calling with request %v", req) numNotes, err = analyze(c, req, origDir, i.options.HandleResponse) if err != nil { return numNotes, fmt.Errorf("error making service call: %v", err) } // If desired, generate compilation units with a kythe image if i.options.Build != "" { // TODO(ciera): Handle other build systems fullKytheImage := docker.FullImageName(i.options.Repo, kytheImage, i.options.Tag) if !i.options.LocalKythe { pull(fullKytheImage) } // TODO(emso): Add a check for an already running kythe container. // The below defer should stop the one started below but in case this // failed for some reason (or a kythe container was started in some other // way) the below run command will fail. defer stop("kythe", 10*time.Second) glog.Infof("Retrieving compilation units with %s", i.options.Build) result := docker.RunKythe(fullKytheImage, "kythe", absRoot, i.options.Build, i.options.Dind) if result.Err != nil { // kythe spews output, so only capture it if something went wrong. printStreams(result) return numNotes, fmt.Errorf("error from run: %v", result.Err) } glog.Infoln("CompilationUnits prepared") req.Stage = ctxpb.Stage_POST_BUILD.Enum() glog.Infof("Calling with request %v", req) numBuildNotes, err := analyze(c, req, origDir, i.options.HandleResponse) numNotes += numBuildNotes if err != nil { return numNotes, fmt.Errorf("error making service call: %v", err) } } if i.options.ResponsesDone != nil { if err := i.options.ResponsesDone(); err != nil { return numNotes, err } } glog.Infoln("End of Results.") return numNotes, nil }
func (i *Invocation) startServices() (*client.Client, Paths, func(), error) { var paths Paths var err error glog.Infof("Starting shipshape...") paths.fs, err = os.Stat(i.options.File) if err != nil { return nil, paths, func() {}, fmt.Errorf("%s is not a valid file or directory\n", i.options.File) } paths.origDir = i.options.File if !paths.fs.IsDir() { paths.origDir = filepath.Dir(i.options.File) } paths.absRoot, err = filepath.Abs(paths.origDir) if err != nil { return nil, paths, func() {}, fmt.Errorf("could not get absolute path for %s: %v\n", paths.origDir, err) } if !docker.HasDocker() { return nil, paths, func() {}, fmt.Errorf("docker could not be found. Make sure you have docker installed.") } image := docker.FullImageName(i.options.Repo, image, i.options.Tag) glog.Infof("Starting shipshape using %s on %s", image, paths.absRoot) if len(i.options.ThirdPartyAnalyzers) == 0 { i.options.ThirdPartyAnalyzers, err = service.GlobalConfig(paths.absRoot) if err != nil { glog.Infof("Could not get global config; using only the default analyzers: %v", err) } } pull(image) pullAnalyzers(i.options.ThirdPartyAnalyzers) // Create a cleanup function that will stop all the containers we started, // if that is desired. cleanup := func() { if !i.options.StayUp { // TODO(ciera): Rather than immediately sending a SIGKILL, // we should use the default 10 seconds and properly handle // SIGTERMs in the endpoint script. stop("shipping_container", 0) } // Stop all the analyzers, even the ones that had trouble starting, // in case they did actually start for id, analyzerRepo := range i.options.ThirdPartyAnalyzers { container, _ := getContainerAndAddress(analyzerRepo, id) stop(container, 0) } } containers, errs := startAnalyzers(paths.absRoot, i.options.ThirdPartyAnalyzers, i.options.Dind) for _, err := range errs { glog.Errorf("Could not start up third party analyzer: %v", err) } var c *client.Client c, paths.relativeRoot, err = startShipshapeService(image, paths.absRoot, containers, i.options.Dind) if err != nil { return nil, paths, cleanup, fmt.Errorf("HTTP client did not become healthy: %v", err) } return c, paths, cleanup, nil }