/**
   * Go through all sources and check which have been removed, added or modified and taint the
   * corresponding packages.
   */
  public void checkSourceStatus(boolean check_gensrc) {
    removedSources = calculateRemovedSources();
    for (Source s : removedSources) {
      if (!s.isGenerated() || check_gensrc) {
        taintPackage(s.pkg().name(), "source " + s.name() + " was removed");
      }
    }

    addedSources = calculateAddedSources();
    for (Source s : addedSources) {
      String msg = null;
      if (isIncremental()) {
        // When building from scratch, there is no point
        // printing "was added" for every file since all files are added.
        // However for an incremental build it makes sense.
        msg = "source " + s.name() + " was added";
      }
      if (!s.isGenerated() || check_gensrc) {
        taintPackage(s.pkg().name(), msg);
      }
    }

    modifiedSources = calculateModifiedSources();
    for (Source s : modifiedSources) {
      if (!s.isGenerated() || check_gensrc) {
        taintPackage(s.pkg().name(), "source " + s.name() + " was modified");
      }
    }
  }
 /** Store the source into the set of sources belonging to the given transform. */
 private void addFileToTransform(
     Map<Transformer, Map<String, Set<URI>>> gs, Transformer t, Source s) {
   Map<String, Set<URI>> fs = gs.get(t);
   if (fs == null) {
     fs = new HashMap<>();
     gs.put(t, fs);
   }
   Set<URI> ss = fs.get(s.pkg().name());
   if (ss == null) {
     ss = new HashSet<>();
     fs.put(s.pkg().name(), ss);
   }
   ss.add(s.file().toURI());
 }
  /**
   * For all packages, find all sources belonging to the package, group the sources based on their
   * transformers and apply the transformers on each source code group.
   */
  private boolean perform(File outputDir, Map<String, Transformer> suffixRules) {
    boolean rc = true;
    // Group sources based on transforms. A source file can only belong to a single transform.
    Map<Transformer, Map<String, Set<URI>>> groupedSources = new HashMap<>();
    for (Source src : now.sources().values()) {
      Transformer t = suffixRules.get(src.suffix());
      if (t != null) {
        if (taintedPackages.contains(src.pkg().name()) && !src.isLinkedOnly()) {
          addFileToTransform(groupedSources, t, src);
        }
      }
    }
    // Go through the transforms and transform them.
    for (Map.Entry<Transformer, Map<String, Set<URI>>> e : groupedSources.entrySet()) {
      Transformer t = e.getKey();
      Map<String, Set<URI>> srcs = e.getValue();
      // These maps need to be synchronized since multiple threads will be writing results into
      // them.
      Map<String, Set<URI>> packageArtifacts =
          Collections.synchronizedMap(new HashMap<String, Set<URI>>());
      Map<String, Set<String>> packageDependencies =
          Collections.synchronizedMap(new HashMap<String, Set<String>>());
      Map<String, String> packagePublicApis =
          Collections.synchronizedMap(new HashMap<String, String>());

      boolean r =
          t.transform(
              srcs,
              visibleSrcs,
              visibleClasses,
              prev.dependents(),
              outputDir.toURI(),
              packageArtifacts,
              packageDependencies,
              packagePublicApis,
              0,
              isIncremental(),
              numCores,
              out,
              err);
      if (!r) rc = false;

      for (String p : srcs.keySet()) {
        recompiledPackages.add(p);
      }
      // The transform is done! Extract all the artifacts and store the info into the Package
      // objects.
      for (Map.Entry<String, Set<URI>> a : packageArtifacts.entrySet()) {
        Module mnow = now.findModuleFromPackageName(a.getKey());
        mnow.addArtifacts(a.getKey(), a.getValue());
      }
      // Extract all the dependencies and store the info into the Package objects.
      for (Map.Entry<String, Set<String>> a : packageDependencies.entrySet()) {
        Set<String> deps = a.getValue();
        Module mnow = now.findModuleFromPackageName(a.getKey());
        mnow.setDependencies(a.getKey(), deps);
      }
      // Extract all the pubapis and store the info into the Package objects.
      for (Map.Entry<String, String> a : packagePublicApis.entrySet()) {
        Module mprev = prev.findModuleFromPackageName(a.getKey());
        List<String> pubapi = Package.pubapiToList(a.getValue());
        Module mnow = now.findModuleFromPackageName(a.getKey());
        mnow.setPubapi(a.getKey(), pubapi);
        if (mprev.hasPubapiChanged(a.getKey(), pubapi)) {
          // Aha! The pubapi of this package has changed!
          // It can also be a new compile from scratch.
          if (mprev.lookupPackage(a.getKey()).existsInJavacState()) {
            // This is an incremental compile! The pubapi
            // did change. Trigger recompilation of dependents.
            packagesWithChangedPublicApis.add(a.getKey());
            Log.info("The pubapi of " + Util.justPackageName(a.getKey()) + " has changed!");
          }
        }
      }
    }
    return rc;
  }