func cleanExistingContainer(t *testing.T, container string) {
	exists, err := docker.ContainerExists(container)
	if err != nil {
		t.Fatalf("Problem checking docker state; err: %v", err)
	}
	if exists {
		if result := docker.Stop(container, 0, true); result.Err != nil {
			t.Fatalf("Problem cleaning up the docker state; err: %v", result.Err)
		}
	}
}
// startShipshapeService ensures that there is a service started with the given image and
// attached analyzers that can analyze the directory at absRoot (an absolute path). If a
// service is not started up that can do this, it will shut down the existing one and start
// a new one.
// The methods returns the (ready) client, the relative path from the docker container's mapped
// volume to the absRoot that we are analyzing, and any errors from attempting to run the service.
func startShipshapeService(image, absRoot string, analyzers []string, dind bool) (*client.Client, string, error) {
	glog.Infof("Starting shipshape...")
	container := "shipping_container"
	exists, err := docker.ContainerExists(container)
	if err != nil {
		return nil, "", err
	}

	var subPath string
	if !exists {
		result := docker.RunService(image, container, absRoot, localLogs, analyzers, dind)
		printStreams(result)
		if result.Err != nil {
			return nil, "", result.Err
		}
		subPath = ""
	} else {
		var isMapped bool
		// subPath is the relative path from the mapped volume on shipping container
		// to the directory we are analyzing (absRoot)
		isMapped, subPath = docker.MappedVolume(absRoot, container)
		// Stop and restart the container if:
		// 1: The container is not mapped to the right directory OR
		// 2: The container is not using the latest image OR
		// 3: The container is not linked to the right analyzer containers
		// Otherwise, use the existing container
		if !isMapped || !docker.ImageMatches(image, container) || !docker.ContainsLinks(container, analyzers) {
			glog.Infof("Restarting container with %s", image)
			stop(container, 0)
			result := docker.RunService(image, container, absRoot, localLogs, analyzers, dind)
			printStreams(result)
			if result.Err != nil {
				return nil, "", result.Err
			}
			subPath = ""
		}
	}
	glog.Infof("Image %s running in service mode", image)
	c := client.NewHTTPClient("localhost:10007")
	return c, subPath, c.WaitUntilReady(10 * time.Second)
}
func (i *Invocation) Run() (int, error) {
	var c *client.Client
	var req *rpcpb.ShipshapeRequest
	var numNotes int

	// Run it on files
	c, paths, cleanup, err := i.startServices()
	defer cleanup()
	if err != nil {
		return 0, err
	}
	var files []string
	if !paths.fs.IsDir() {
		files = []string{filepath.Base(i.options.File)}
	}
	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)
	}
	req = createRequest(i.options.TriggerCats, files, i.options.Event, filepath.Join(workspace, paths.relativeRoot), ctxpb.Stage_PRE_BUILD.Enum())
	glog.Infof("Calling with request %v", req)
	numNotes, err = analyze(c, req, paths.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)
		}

		// Stop kythe if it is running otherwise we will fail when we start kythe below
		exists, err := docker.ContainerExists(fullKytheImage)
		if err != nil {
			return numNotes, fmt.Errorf("error making service call: %v", err)
		}
		if exists {
			stop(fullKytheImage, 0)
		}
		// Make sure we stop kythe after we are done
		defer stop("kythe", 10*time.Second)

		glog.Infof("Retrieving compilation units with %s", i.options.Build)
		result := docker.RunKythe(fullKytheImage, "kythe", paths.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, paths.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
}