Example #1
0
// Analyze will determine which analyzers to run and call them as appropriate. If necessary, it will
// also modify the context before calling the analyzers. It recovers from all analyzer panics with a
// note that the analyzer failed.
func (s analyzerService) Analyze(ctx server.Context, in *rpcpb.AnalyzeRequest) (resp *rpcpb.AnalyzeResponse, err error) {
	resp = new(rpcpb.AnalyzeResponse)

	log.Printf("called with: %v", proto.MarshalTextString(in))
	log.Print("starting analyzing")
	var nts []*notepb.Note
	var errs []*rpcpb.AnalysisFailure

	defer func() {
		resp.Note = nts
		resp.Failure = errs
	}()

	orgDir, restore, err := file.ChangeDir(*in.ShipshapeContext.RepoRoot)
	if err != nil {
		log.Printf("Internal error before analyzing: %v", err)
		appendFailure(&errs, "InternalFailure", err)
		return resp, err
	}
	defer func() {
		if err := restore(); err != nil {
			log.Printf("could not return back into %s from %s: %v", orgDir, *in.ShipshapeContext.RepoRoot, err)
		}
	}()

	reqCats := strset.New(in.Category...)
	for _, a := range s.analyzers {
		if reqCats.Contains(a.Category()) {
			runAnalyzer(a, in.ShipshapeContext, &nts, &errs)
		}
	}
	log.Printf("finished analyzing, sending back %d notes and %d errors", len(nts), len(errs))
	return resp, nil
}
Example #2
0
// Run runs the analyzers that this driver knows about on the provided ShipshapeRequest,
// taking configuration into account.
func (sd ShipshapeDriver) Run(ctx server.Context, in *rpcpb.ShipshapeRequest, out chan<- *rpcpb.ShipshapeResponse) error {
	var ars []*rpcpb.AnalyzeResponse
	log.Printf("Received analysis request for event %v, stage %v, categories %v, repo %v", *in.Event, *in.Stage, in.TriggeredCategory, *in.ShipshapeContext.RepoRoot)

	// However we exit, send back the set of collected AnalyzeResponses
	// TODO(ciera): we should be streaming back the responses, not sending them all at the end.
	defer func() {
		out <- &rpcpb.ShipshapeResponse{
			AnalyzeResponse: ars,
		}
	}()

	if in.ShipshapeContext.RepoRoot == nil {
		return fmt.Errorf("No repo root was set")
	}
	root := *in.ShipshapeContext.RepoRoot

	// cd into the root directory
	orgDir, restore, err := file.ChangeDir(root)
	if err != nil {
		log.Printf("Could not change into directory %s from base %s", root, orgDir)
		ars = append(ars, generateFailure("Driver setup", fmt.Sprint(err)))
		return err
	}
	defer func() {
		if err := restore(); err != nil {
			log.Printf("could not return back into %s from %s: %v", orgDir, root, err)
		}
	}()

	cfg, err := loadConfig(configFilename, *in.Event)
	if err != nil {
		log.Print("error loading config")
		// TODO(collinwinter): attach the error to the config file.
		ars = append(ars, generateFailure("Driver setup", err.Error()))
		return err
	}

	// Get the list of all categories
	sd.serviceMap = sd.getAllServiceInfo()
	allCats := sd.allCats()

	// Use the triggered categories if specified
	var desiredCats strset.Set
	if len(in.TriggeredCategory) > 0 {
		desiredCats = strset.New(in.TriggeredCategory...)
	} else if cfg != nil {
		desiredCats = strset.New(cfg.categories...)
		if len(desiredCats) > 0 {
			log.Printf("Running with categories from .shipshape file: %s" + desiredCats.String())
		} else if *in.Event != defaults.DefaultEvent {
			return fmt.Errorf("No categories configured for event %s", *in.Event)
		}
	}

	if len(desiredCats) == 0 {
		log.Printf("No categories specified, running with default categories: %s", sd.defaultCategories.String())
		desiredCats = sd.defaultCategories
	}

	// Find out what categories we have available, and remove/warn on the missing ones
	missingCats := strset.New().AddSet(desiredCats).RemoveSet(allCats)
	for missing := range missingCats {
		ars = append(ars, generateFailure(missing, fmt.Sprintf("The triggered category %q could not be found at the locations %v", missing, sd.AnalyzerLocations)))
	}
	desiredCats = desiredCats.RemoveSet(missingCats)

	if len(desiredCats) == 0 {
		log.Printf("No categories configured to run, doing nothing")
		return nil
	}

	// TODO(ciera): move this global ignore stuff into the CLI processing
	ignorePaths := []string{}
	if cfg != nil {
		ignorePaths = cfg.ignore
	}
	// Fill in the file_paths if they are empty in the context
	context := proto.Clone(in.ShipshapeContext).(*contextpb.ShipshapeContext)
	context.FilePath, err = retrieveAndFilterFiles(*context.RepoRoot, context.FilePath, ignorePaths)
	if err != nil {
		log.Printf("Had problems accessing files: %v", err.Error())
		ars = append(ars, generateFailure("Driver setup", fmt.Sprint(err)))
		return err
	}
	if len(context.FilePath) == 0 {
		log.Print("No files to run on, doing nothing")
		return nil
	}

	// TODO(ciera): rather than pass the stage through here and checking all analyzers,
	// filter out the stages earlier, when we check categories
	stage := contextpb.Stage_PRE_BUILD
	if in.Stage != nil {
		stage = *in.Stage
	}

	log.Printf("Analyzing stage %s", stage.String())
	if stage == contextpb.Stage_PRE_BUILD {
		ars = append(ars, sd.callAllAnalyzers(desiredCats, context, stage)...)
	} /*else {
		comps := filepath.Join(*context.RepoRoot, compilationsDir)
		compUnits, err := findCompilationUnits(comps)
		log.Printf("Found %d compUnits at %s", len(compUnits), comps)
		if err != nil {
			log.Printf("Could not retrieve compilation units: %v", err)
			ars = append(ars, generateFailure("Driver setup", err.Error()))
			return nil
		}
		for path, compUnit := range compUnits {
			context.CompilationDetails = &contextpb.CompilationDetails{
				CompilationUnit:            compUnit,
				CompilationDescriptionPath: proto.String(path),
			}
			log.Printf("Calling services with comp unit at %s", path)
			ars = append(ars, sd.callAllAnalyzers(desiredCats, context, stage)...)
		}

	}
	*/

	log.Print("Analysis completed")
	return nil
}