private static Map<String, String> buildClassToSourceMap(
     ModuleChunk chunk,
     CompileContext context,
     Set<String> toCompilePaths,
     Map<ModuleBuildTarget, String> finalOutputs)
     throws IOException {
   final Map<String, String> class2Src = new HashMap<String, String>();
   JpsJavaCompilerConfiguration configuration =
       JpsJavaExtensionService.getInstance()
           .getOrCreateCompilerConfiguration(context.getProjectDescriptor().getProject());
   for (ModuleBuildTarget target : chunk.getTargets()) {
     String moduleOutputPath = finalOutputs.get(target);
     final SourceToOutputMapping srcToOut =
         context.getProjectDescriptor().dataManager.getSourceToOutputMap(target);
     for (String src : srcToOut.getSources()) {
       if (!toCompilePaths.contains(src)
           && isGroovyFile(src)
           && !configuration.getCompilerExcludes().isExcluded(new File(src))) {
         final Collection<String> outs = srcToOut.getOutputs(src);
         if (outs != null) {
           for (String out : outs) {
             if (out.endsWith(".class") && out.startsWith(moduleOutputPath)) {
               final String className =
                   out.substring(moduleOutputPath.length(), out.length() - ".class".length())
                       .replace('/', '.');
               class2Src.put(className, src);
             }
           }
         }
       }
     }
   }
   return class2Src;
 }
 public static void markDeleted(CompileContext context, File file) throws IOException {
   final JavaSourceRootDescriptor rd =
       context.getProjectDescriptor().getBuildRootIndex().getModuleAndRoot(context, file);
   if (rd != null) {
     final ProjectDescriptor pd = context.getProjectDescriptor();
     pd.fsState.registerDeleted(rd.target, file, pd.timestamps.getStorage());
   }
 }
 public static void markDirty(
     CompileContext context, final CompilationRound round, final File file) throws IOException {
   final JavaSourceRootDescriptor rd =
       context.getProjectDescriptor().getBuildRootIndex().findJavaRootDescriptor(context, file);
   if (rd != null) {
     final ProjectDescriptor pd = context.getProjectDescriptor();
     pd.fsState.markDirty(context, round, file, rd, pd.timestamps.getStorage());
   }
 }
 /**
  * @param context
  * @param round
  * @param file
  * @return true if file is marked as "dirty" in the specified compilation round
  * @throws IOException
  */
 public static boolean isMarkedDirty(
     CompileContext context, final CompilationRound round, final File file) throws IOException {
   final JavaSourceRootDescriptor rd =
       context.getProjectDescriptor().getBuildRootIndex().findJavaRootDescriptor(context, file);
   if (rd != null) {
     final ProjectDescriptor pd = context.getProjectDescriptor();
     return pd.fsState.isMarkedForRecompilation(context, round, rd, file);
   }
   return false;
 }
  public static void markDirtyRecursively(
      CompileContext context,
      final CompilationRound round,
      ModuleChunk chunk,
      @Nullable FileFilter filter)
      throws IOException {
    Set<JpsModule> modules = chunk.getModules();
    Set<ModuleBuildTarget> targets = chunk.getTargets();
    final Set<ModuleBuildTarget> dirtyTargets = new HashSet<ModuleBuildTarget>(targets);

    // now mark all modules that depend on dirty modules
    final JpsJavaClasspathKind classpathKind = JpsJavaClasspathKind.compile(chunk.containsTests());
    boolean found = false;
    for (BuildTargetChunk targetChunk :
        context.getProjectDescriptor().getBuildTargetIndex().getSortedTargetChunks(context)) {
      if (!found) {
        if (targetChunk.getTargets().equals(chunk.getTargets())) {
          found = true;
        }
      } else {
        for (final BuildTarget<?> target : targetChunk.getTargets()) {
          if (target instanceof ModuleBuildTarget) {
            final Set<JpsModule> deps =
                getDependentModulesRecursively(
                    ((ModuleBuildTarget) target).getModule(), classpathKind);
            if (ContainerUtil.intersects(deps, modules)) {
              for (BuildTarget<?> buildTarget : targetChunk.getTargets()) {
                if (buildTarget instanceof ModuleBuildTarget) {
                  dirtyTargets.add((ModuleBuildTarget) buildTarget);
                }
              }
              break;
            }
          }
        }
      }
    }

    removeTargetsAlreadyMarkedDirty(context, dirtyTargets);

    final Timestamps timestamps = context.getProjectDescriptor().timestamps.getStorage();
    for (ModuleBuildTarget target : dirtyTargets) {
      markDirtyFiles(context, target, round, timestamps, true, null, filter);
    }

    if (JavaBuilderUtil.isCompileJavaIncrementally(context)) {
      // mark as non-incremental only the module that triggered non-incremental change
      for (ModuleBuildTarget target : targets) {
        context.markNonIncremental(target);
      }
    }
  }
  public static void pruneEmptyDirs(
      CompileContext context, @Nullable final Set<File> dirsToDelete) {
    if (dirsToDelete == null || dirsToDelete.isEmpty()) return;

    Set<File> doNotDelete = ALL_OUTPUTS_KEY.get(context);
    if (doNotDelete == null) {
      doNotDelete = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
      for (BuildTarget<?> target :
          context.getProjectDescriptor().getBuildTargetIndex().getAllTargets()) {
        doNotDelete.addAll(target.getOutputRoots(context));
      }
      ALL_OUTPUTS_KEY.set(context, doNotDelete);
    }

    Set<File> additionalDirs = null;
    Set<File> toDelete = dirsToDelete;
    while (toDelete != null) {
      for (File file : toDelete) {
        // important: do not force deletion if the directory is not empty!
        final boolean deleted = !doNotDelete.contains(file) && file.delete();
        if (deleted) {
          final File parentFile = file.getParentFile();
          if (parentFile != null) {
            if (additionalDirs == null) {
              additionalDirs = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
            }
            additionalDirs.add(parentFile);
          }
        }
      }
      toDelete = additionalDirs;
      additionalDirs = null;
    }
  }
 public static void processFilesToRecompile(
     CompileContext context,
     @NotNull ModuleBuildTarget target,
     FileProcessor<JavaSourceRootDescriptor, ModuleBuildTarget> processor)
     throws IOException {
   context.getProjectDescriptor().fsState.processFilesToRecompile(context, target, processor);
 }
 @Override
 public void buildStarted(CompileContext context) {
   final JpsProject project = context.getProjectDescriptor().getProject();
   final JpsJavaCompilerConfiguration config =
       JpsJavaExtensionService.getInstance().getCompilerConfiguration(project);
   final String compilerId = config == null ? JavaCompilers.JAVAC_ID : config.getJavaCompilerId();
   if (LOG.isDebugEnabled()) {
     LOG.debug("Java compiler ID: " + compilerId);
   }
   final boolean isJavac =
       JavaCompilers.JAVAC_ID.equalsIgnoreCase(compilerId)
           || JavaCompilers.JAVAC_API_ID.equalsIgnoreCase(compilerId);
   final boolean isEclipse =
       JavaCompilers.ECLIPSE_ID.equalsIgnoreCase(compilerId)
           || JavaCompilers.ECLIPSE_EMBEDDED_ID.equalsIgnoreCase(compilerId);
   IS_ENABLED.set(context, isJavac || isEclipse);
   String messageText = null;
   if (isJavac) {
     messageText =
         "Using javac " + System.getProperty("java.version") + " to compile java sources";
   } else if (isEclipse) {
     messageText = "Using eclipse compiler to compile java sources";
   }
   COMPILER_VERSION_INFO.set(context, new AtomicReference<String>(messageText));
 }
 public static void markDirty(CompileContext context, final ModuleChunk chunk) throws IOException {
   final ProjectDescriptor pd = context.getProjectDescriptor();
   pd.fsState.clearContextRoundData(context);
   for (ModuleBuildTarget target : chunk.getTargets()) {
     markDirtyFiles(context, target, pd.timestamps.getStorage(), true, null);
   }
 }
 static boolean useGreclipse(CompileContext context) {
   JpsProject project = context.getProjectDescriptor().getProject();
   return ID.equals(
       JpsJavaExtensionService.getInstance()
           .getOrCreateCompilerConfiguration(project)
           .getJavaCompilerId());
 }
 private static void traverseRecursively(
     CompileContext context,
     final JavaSourceRootDescriptor rd,
     final File file,
     Set<File> excludes,
     @NotNull final Timestamps tsStorage,
     final boolean forceDirty,
     @Nullable Set<File> currentFiles)
     throws IOException {
   final File[] children = file.listFiles();
   if (children != null) { // is directory
     if (children.length > 0 && !JpsPathUtil.isUnder(excludes, file)) {
       for (File child : children) {
         traverseRecursively(context, rd, child, excludes, tsStorage, forceDirty, currentFiles);
       }
     }
   } else { // is file
     boolean markDirty = forceDirty;
     if (!markDirty) {
       markDirty = tsStorage.getStamp(file, rd.target) != FileSystemUtil.lastModified(file);
     }
     if (markDirty) {
       // if it is full project rebuild, all storages are already completely cleared;
       // so passing null because there is no need to access the storage to clear non-existing data
       final Timestamps marker = context.isProjectRebuild() ? null : tsStorage;
       context.getProjectDescriptor().fsState.markDirty(context, file, rd, marker);
     }
     if (currentFiles != null) {
       currentFiles.add(file);
     }
   }
 }
 private static int getJavacServerHeapSize(CompileContext context) {
   final JpsProject project = context.getProjectDescriptor().getProject();
   final JpsJavaCompilerConfiguration config =
       JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
   final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
   return options.MAXIMUM_HEAP_SIZE;
 }
 static void markDirtyFiles(
     CompileContext context,
     ModuleBuildTarget target,
     Timestamps timestamps,
     boolean forceMarkDirty,
     @Nullable THashSet<File> currentFiles)
     throws IOException {
   final ModuleExcludeIndex rootsIndex = context.getProjectDescriptor().getModuleExcludeIndex();
   final Set<File> excludes = new HashSet<File>(rootsIndex.getModuleExcludes(target.getModule()));
   for (JavaSourceRootDescriptor rd :
       context.getProjectDescriptor().getBuildRootIndex().getTargetRoots(target, context)) {
     if (!rd.root.exists()) {
       continue;
     }
     context.getProjectDescriptor().fsState.clearRecompile(rd);
     traverseRecursively(context, rd, rd.root, excludes, timestamps, forceMarkDirty, currentFiles);
   }
 }
  private static void loadCommonJavacOptions(CompileContext context) {
    final List<String> options = new ArrayList<String>();
    final List<String> vmOptions = new ArrayList<String>();

    final JpsProject project = context.getProjectDescriptor().getProject();
    final JpsJavaCompilerConfiguration compilerConfig =
        JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
    final JpsJavaCompilerOptions compilerOptions = compilerConfig.getCurrentCompilerOptions();
    if (compilerOptions.DEBUGGING_INFO) {
      options.add("-g");
    }
    if (compilerOptions.DEPRECATION) {
      options.add("-deprecation");
    }
    if (compilerOptions.GENERATE_NO_WARNINGS) {
      options.add("-nowarn");
    }
    if (compilerOptions instanceof EclipseCompilerOptions) {
      final EclipseCompilerOptions eclipseOptions = (EclipseCompilerOptions) compilerOptions;
      if (eclipseOptions.PROCEED_ON_ERROR) {
        options.add("-proceedOnError");
      }
    }
    final String customArgs = compilerOptions.ADDITIONAL_OPTIONS_STRING;
    if (customArgs != null) {
      final StringTokenizer customOptsTokenizer = new StringTokenizer(customArgs, " \t\r\n");
      boolean skip = false;
      while (customOptsTokenizer.hasMoreTokens()) {
        final String userOption = customOptsTokenizer.nextToken();
        if (FILTERED_OPTIONS.contains(userOption)) {
          skip = true;
          continue;
        }
        if (!skip) {
          if (!FILTERED_SINGLE_OPTIONS.contains(userOption)) {
            if (userOption.startsWith("-J-")) {
              vmOptions.add(userOption.substring("-J".length()));
            } else {
              options.add(userOption);
            }
          }
        }
      }
    }

    if (useEclipseCompiler(context)) {
      for (String option : options) {
        if (option.startsWith("-proceedOnError")) {
          Utils.PROCEED_ON_ERROR_KEY.set(context, Boolean.TRUE);
          break;
        }
      }
    }

    JAVAC_OPTIONS.set(context, options);
    JAVAC_VM_OPTIONS.set(context, vmOptions);
  }
 private static void addStubRootsToJavacSourcePath(
     CompileContext context, Map<ModuleBuildTarget, String> generationOutputs) {
   final BuildRootIndex rootsIndex = context.getProjectDescriptor().getBuildRootIndex();
   for (ModuleBuildTarget target : generationOutputs.keySet()) {
     File root = new File(generationOutputs.get(target));
     rootsIndex.associateTempRoot(
         context,
         target,
         new JavaSourceRootDescriptor(root, target, true, true, "", Collections.<File>emptySet()));
   }
 }
 public static void markDirty(
     CompileContext context,
     final CompilationRound round,
     final ModuleChunk chunk,
     @Nullable FileFilter filter)
     throws IOException {
   final ProjectDescriptor pd = context.getProjectDescriptor();
   for (ModuleBuildTarget target : chunk.getTargets()) {
     markDirtyFiles(context, target, round, pd.timestamps.getStorage(), true, null, filter);
   }
 }
 private static boolean useEclipseCompiler(CompileContext context) {
   if (!USE_EMBEDDED_JAVAC) {
     return false;
   }
   JpsProject project = context.getProjectDescriptor().getProject();
   final JpsJavaCompilerConfiguration configuration =
       JpsJavaExtensionService.getInstance().getCompilerConfiguration(project);
   final String compilerId = configuration != null ? configuration.getJavaCompilerId() : null;
   return JavaCompilers.ECLIPSE_ID.equalsIgnoreCase(compilerId)
       || JavaCompilers.ECLIPSE_EMBEDDED_ID.equalsIgnoreCase(compilerId);
 }
 public static void processFilesToRecompile(
     final CompileContext context,
     final ModuleChunk chunk,
     final Condition<JpsModule> moduleFilter,
     final FileProcessor processor)
     throws IOException {
   final BuildFSState fsState = context.getProjectDescriptor().fsState;
   for (ModuleBuildTarget target : chunk.getTargets()) {
     if (moduleFilter.value(target.getModule())) {
       fsState.processFilesToRecompile(context, target, processor);
     }
   }
 }
 private static void traverseRecursively(
     CompileContext context,
     final BuildRootDescriptor rd,
     final CompilationRound round,
     final File file,
     @NotNull final Timestamps tsStorage,
     final boolean forceDirty,
     @Nullable Set<File> currentFiles,
     @Nullable FileFilter filter,
     @NotNull FSCache fsCache)
     throws IOException {
   BuildRootIndex rootIndex = context.getProjectDescriptor().getBuildRootIndex();
   final File[] children = fsCache.getChildren(file);
   if (children != null) { // is directory
     if (children.length > 0 && rootIndex.isDirectoryAccepted(file, rd)) {
       for (File child : children) {
         traverseRecursively(
             context, rd, round, child, tsStorage, forceDirty, currentFiles, filter, fsCache);
       }
     }
   } else { // is file
     if (rootIndex.isFileAccepted(file, rd) && (filter == null || filter.accept(file))) {
       boolean markDirty = forceDirty;
       if (!markDirty) {
         markDirty = tsStorage.getStamp(file, rd.getTarget()) != FileSystemUtil.lastModified(file);
       }
       if (markDirty) {
         // if it is full project rebuild, all storages are already completely cleared;
         // so passing null because there is no need to access the storage to clear non-existing
         // data
         final Timestamps marker = context.isProjectRebuild() ? null : tsStorage;
         context.getProjectDescriptor().fsState.markDirty(context, round, file, rd, marker);
       }
       if (currentFiles != null) {
         currentFiles.add(file);
       }
     }
   }
 }
  static List<File> collectChangedFiles(
      CompileContext context,
      DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
      final boolean forStubs,
      final boolean forEclipse,
      final Ref<Boolean> hasExcludes)
      throws IOException {

    final JpsJavaCompilerConfiguration configuration =
        JpsJavaExtensionService.getInstance()
            .getCompilerConfiguration(context.getProjectDescriptor().getProject());
    assert configuration != null;

    final JpsGroovySettings settings =
        JpsGroovySettings.getSettings(context.getProjectDescriptor().getProject());

    final List<File> toCompile = new ArrayList<File>();
    dirtyFilesHolder.processDirtyFiles(
        new FileProcessor<JavaSourceRootDescriptor, ModuleBuildTarget>() {
          public boolean apply(
              ModuleBuildTarget target, File file, JavaSourceRootDescriptor sourceRoot)
              throws IOException {
            final String path = file.getPath();
            // todo file type check
            if ((isGroovyFile(path) || forEclipse && path.endsWith(".java"))
                && !configuration.isResourceFile(file, sourceRoot.root)) {
              if (forStubs && settings.isExcludedFromStubGeneration(file)) {
                hasExcludes.set(true);
                return true;
              }

              toCompile.add(file);
            }
            return true;
          }
        });
    return toCompile;
  }
  static void markDirtyFiles(
      CompileContext context,
      BuildTarget<?> target,
      final CompilationRound round,
      Timestamps timestamps,
      boolean forceMarkDirty,
      @Nullable THashSet<File> currentFiles,
      @Nullable FileFilter filter)
      throws IOException {
    if (filter == null && forceMarkDirty) {
      addCompletelyMarkedDirtyTarget(context, target);
    }

    for (BuildRootDescriptor rd :
        context.getProjectDescriptor().getBuildRootIndex().getTargetRoots(target, context)) {
      if (!rd.getRootFile().exists()
          ||
          // temp roots are managed by compilers themselves
          (rd instanceof JavaSourceRootDescriptor && ((JavaSourceRootDescriptor) rd).isTemp)) {
        continue;
      }
      if (filter == null) {
        context.getProjectDescriptor().fsState.clearRecompile(rd);
      }
      final FSCache fsCache =
          rd.canUseFileCache() ? context.getProjectDescriptor().getFSCache() : FSCache.NO_CACHE;
      traverseRecursively(
          context,
          rd,
          round,
          rd.getRootFile(),
          timestamps,
          forceMarkDirty,
          currentFiles,
          filter,
          fsCache);
    }
  }
 @NotNull
 @Override
 public Collection<File> getOutputRoots(final CompileContext context) {
   final Set<File> result = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
   final JpsProject jpsProject = context.getProjectDescriptor().getProject();
   processJavaModuleTargets(
       jpsProject,
       new Processor<ModuleBuildTarget>() {
         @Override
         public boolean process(ModuleBuildTarget target) {
           result.addAll(target.getOutputRoots(context));
           return true;
         }
       });
   return result;
 }
 private static Map<File, Set<File>> buildOutputDirectoriesMap(
     CompileContext context, ModuleChunk chunk) {
   final Map<File, Set<File>> map = new THashMap<File, Set<File>>(FileUtil.FILE_HASHING_STRATEGY);
   for (ModuleBuildTarget target : chunk.getTargets()) {
     final File outputDir = target.getOutputDir();
     if (outputDir == null) {
       continue;
     }
     final Set<File> roots = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY);
     for (JavaSourceRootDescriptor descriptor :
         context.getProjectDescriptor().getBuildRootIndex().getTargetRoots(target, context)) {
       roots.add(descriptor.root);
     }
     map.put(outputDir, roots);
   }
   return map;
 }
 private static int getCompilerSdkVersion(CompileContext context) {
   final Integer cached = JAVA_COMPILER_VERSION_KEY.get(context);
   if (cached != null) {
     return cached;
   }
   int javaVersion = convertToNumber(SystemProperties.getJavaVersion());
   if (!USE_EMBEDDED_JAVAC) {
     // in case of external javac, run compiler from the newest jdk that is used in the project
     for (JpsSdk<?> sdk : context.getProjectDescriptor().getProjectJavaSdks()) {
       final String version = sdk.getVersionString();
       final int ver = convertToNumber(version);
       if (ver > javaVersion) {
         javaVersion = ver;
       }
     }
   }
   JAVA_COMPILER_VERSION_KEY.set(context, javaVersion);
   return javaVersion;
 }
  public static Map<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>>
      processCompiledFiles(
          CompileContext context,
          ModuleChunk chunk,
          Map<ModuleBuildTarget, String> generationOutputs,
          String compilerOutput,
          List<GroovycOutputParser.OutputItem> successfullyCompiled)
          throws IOException {
    ProjectDescriptor pd = context.getProjectDescriptor();

    final Map<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>> compiled =
        new THashMap<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>>();
    for (final GroovycOutputParser.OutputItem item : successfullyCompiled) {
      if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
        LOG.info("compiled=" + item);
      }
      final JavaSourceRootDescriptor rd =
          pd.getBuildRootIndex().findJavaRootDescriptor(context, new File(item.sourcePath));
      if (rd != null) {
        final String outputPath =
            ensureCorrectOutput(chunk, item, generationOutputs, compilerOutput, rd.target);

        Collection<GroovycOutputParser.OutputItem> items = compiled.get(rd.target);
        if (items == null) {
          items = new ArrayList<GroovycOutputParser.OutputItem>();
          compiled.put(rd.target, items);
        }

        items.add(new GroovycOutputParser.OutputItem(outputPath, item.sourcePath));
      } else {
        if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
          LOG.info("No java source root descriptor for the item found =" + item);
        }
      }
    }
    if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
      LOG.info("Chunk " + chunk + " compilation finished");
    }
    return compiled;
  }
  private static synchronized JavacServerClient ensureJavacServerLaunched(CompileContext context)
      throws Exception {
    final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
    if (descriptor != null) {
      return descriptor.client;
    }
    // start server here
    final int port = findFreePort();
    final int heapSize = getJavacServerHeapSize(context);

    // defaulting to the same jdk that used to run the build process
    String javaHome = SystemProperties.getJavaHome();
    int javaVersion = convertToNumber(SystemProperties.getJavaVersion());

    for (JpsSdk<?> sdk : context.getProjectDescriptor().getProjectJavaSdks()) {
      final String version = sdk.getVersionString();
      final int ver = convertToNumber(version);
      if (ver > javaVersion) {
        javaVersion = ver;
        javaHome = sdk.getHomePath();
      }
    }

    final BaseOSProcessHandler processHandler =
        JavacServerBootstrap.launchJavacServer(
            javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context));
    final JavacServerClient client = new JavacServerClient();
    try {
      client.connect("127.0.0.1", port);
    } catch (Throwable ex) {
      processHandler.destroyProcess();
      throw new Exception("Failed to connect to external javac process: ", ex);
    }
    ExternalJavacDescriptor.KEY.set(context, new ExternalJavacDescriptor(processHandler, client));
    return client;
  }
  @Override
  public ExitCode build(
      CompileContext context,
      ModuleChunk chunk,
      DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
      OutputConsumer outputConsumer)
      throws ProjectBuildException, IOException {
    final IceConfig config =
        context.getProjectDescriptor().getProject().getContainer().getChild(IceConfig.ROLE);
    IceConfig iceConfig = config == null ? new IceConfig("") : config;

    File frameworkHome = JpsPathUtil.urlToFile(iceConfig.getFrameworkHomeUrl());
    List<String> includes = new ArrayList<String>();
    for (String include : iceConfig.getIncludeUrls()) {
      includes.add(JpsPathUtil.urlToFile(include).getAbsolutePath());
    }

    final Map<ModuleBuildTarget, List<File>> toCompile =
        collectChangedFiles(context, dirtyFilesHolder);
    if (toCompile.isEmpty()) {
      return ExitCode.NOTHING_DONE;
    }

    for (Map.Entry<ModuleBuildTarget, List<File>> e : toCompile.entrySet()) {
      final ModuleBuildTarget target = e.getKey();
      final JpsModule module = target.getModule();
      SliceCompilerSettings settings = module.getContainer().getChild(SliceCompilerSettings.ROLE);
      final SliceCompilerSettings facetConfig =
          settings == null ? new SliceCompilerSettings() : settings;
      final List<File> sourceFiles = e.getValue();

      List<Target> translators = facetConfig.getComponents();

      if (translators.isEmpty()) {
        context.processMessage(
            new CompilerMessage(
                getPresentableName(),
                BuildMessage.Kind.WARNING,
                "No valid translators found for module "
                    + module.getName()
                    + ". Check facet configuration."));

        continue;
      }

      // Translate files
      for (Target c : translators) {
        final File outputDir = c.getOutputFile();

        if (facetConfig.isCleanOutput()) {
          try {
            FileUtils.cleanDirectory(outputDir);
          } catch (IOException ex) {
            context.processMessage(
                new CompilerMessage(
                    getPresentableName(),
                    BuildMessage.Kind.ERROR,
                    "Failed to empty target directory: "
                        + outputDir.getPath()
                        + " . Error: "
                        + ex.getMessage()));
            return ExitCode.ABORT;
          }
        }

        compileFiles(
            context, frameworkHome, includes, target, sourceFiles, c.getComponent(), outputDir);
      }
    }

    return ExitCode.OK;
  }
  @NotNull
  private GroovycOutputParser runGroovycOrContinuation(
      CompileContext context,
      ModuleChunk chunk,
      JpsGroovySettings settings,
      Map<ModuleBuildTarget, String> finalOutputs,
      String compilerOutput,
      List<File> toCompile,
      boolean hasStubExcludes)
      throws Exception {
    GroovycContinuation continuation = takeContinuation(context, chunk);
    if (continuation != null) {
      if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
        LOG.info("using continuation for " + chunk);
      }
      return continuation.continueCompilation();
    }

    final Set<String> toCompilePaths = getPathsToCompile(toCompile);

    JpsSdk<JpsDummyElement> jdk = getJdk(chunk);
    String version = jdk == null ? SystemInfo.JAVA_RUNTIME_VERSION : jdk.getVersionString();
    boolean inProcess = "true".equals(System.getProperty("groovyc.in.process", "true"));
    boolean mayDependOnUtilJar =
        version != null && StringUtil.compareVersionNumbers(version, "1.6") >= 0;
    boolean optimizeClassLoading =
        !inProcess
            && mayDependOnUtilJar
            && ourOptimizeThreshold != 0
            && toCompilePaths.size() >= ourOptimizeThreshold;

    Map<String, String> class2Src =
        buildClassToSourceMap(chunk, context, toCompilePaths, finalOutputs);

    final String encoding =
        context
            .getProjectDescriptor()
            .getEncodingConfiguration()
            .getPreferredModuleChunkEncoding(chunk);
    List<String> patchers = new ArrayList<String>();

    for (GroovyBuilderExtension extension :
        JpsServiceManager.getInstance().getExtensions(GroovyBuilderExtension.class)) {
      patchers.addAll(extension.getCompilationUnitPatchers(context, chunk));
    }

    Collection<String> classpath = generateClasspath(context, chunk);
    if (LOG.isDebugEnabled()) {
      LOG.debug("Optimized class loading: " + optimizeClassLoading);
      LOG.debug("Groovyc classpath: " + classpath);
    }

    final File tempFile =
        GroovycOutputParser.fillFileWithGroovycParameters(
            compilerOutput,
            toCompilePaths,
            finalOutputs.values(),
            class2Src,
            encoding,
            patchers,
            optimizeClassLoading ? StringUtil.join(classpath, File.pathSeparator) : "");
    GroovycFlavor groovyc =
        inProcess
            ? new InProcessGroovyc(finalOutputs.values(), hasStubExcludes)
            : new ForkedGroovyc(optimizeClassLoading, chunk);

    GroovycOutputParser parser = new GroovycOutputParser(chunk, context);

    continuation = groovyc.runGroovyc(classpath, myForStubs, settings, tempFile, parser);
    setContinuation(context, chunk, continuation);
    return parser;
  }
 private static File getStubRoot(CompileContext context) {
   return new File(
       context.getProjectDescriptor().dataManager.getDataPaths().getDataStorageRoot(),
       "groovyStubs");
 }
  public ModuleLevelBuilder.ExitCode build(
      final CompileContext context,
      final ModuleChunk chunk,
      DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
      OutputConsumer outputConsumer)
      throws ProjectBuildException {
    if (GreclipseBuilder.useGreclipse(context)) return ExitCode.NOTHING_DONE;

    long start = 0;
    try {
      JpsGroovySettings settings =
          JpsGroovySettings.getSettings(context.getProjectDescriptor().getProject());

      Ref<Boolean> hasStubExcludes = Ref.create(false);
      final List<File> toCompile =
          collectChangedFiles(context, dirtyFilesHolder, myForStubs, false, hasStubExcludes);
      if (toCompile.isEmpty()) {
        return hasFilesToCompileForNextRound(context)
            ? ExitCode.ADDITIONAL_PASS_REQUIRED
            : ExitCode.NOTHING_DONE;
      }
      if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
        LOG.info("forStubs=" + myForStubs);
      }

      Map<ModuleBuildTarget, String> finalOutputs = getCanonicalModuleOutputs(context, chunk, this);
      if (finalOutputs == null) {
        return ExitCode.ABORT;
      }

      start = System.currentTimeMillis();

      Map<ModuleBuildTarget, String> generationOutputs =
          myForStubs ? getStubGenerationOutputs(chunk, context) : finalOutputs;
      String compilerOutput = generationOutputs.get(chunk.representativeTarget());

      GroovycOutputParser parser =
          runGroovycOrContinuation(
              context,
              chunk,
              settings,
              finalOutputs,
              compilerOutput,
              toCompile,
              hasStubExcludes.get());

      Map<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>> compiled =
          processCompiledFiles(
              context, chunk, generationOutputs, compilerOutput, parser.getSuccessfullyCompiled());

      if (checkChunkRebuildNeeded(context, parser)) {
        clearContinuation(context, chunk);
        return ExitCode.CHUNK_REBUILD_REQUIRED;
      }

      if (myForStubs) {
        addStubRootsToJavacSourcePath(context, generationOutputs);
        rememberStubSources(context, compiled);
      }

      for (CompilerMessage message : parser.getCompilerMessages()) {
        context.processMessage(message);
      }

      if (!myForStubs) {
        updateDependencies(context, toCompile, compiled, outputConsumer, this);
      }
      return hasFilesToCompileForNextRound(context)
          ? ExitCode.ADDITIONAL_PASS_REQUIRED
          : ExitCode.OK;
    } catch (Exception e) {
      throw new ProjectBuildException(e);
    } finally {
      if (start > 0 && LOG.isDebugEnabled()) {
        LOG.debug(
            myBuilderName
                + " took "
                + (System.currentTimeMillis() - start)
                + " on "
                + chunk.getName());
      }
      if (!myForStubs) {
        FILES_MARKED_DIRTY_FOR_NEXT_ROUND.set(context, null);
      }
    }
  }