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 String ensureCorrectOutput(
      ModuleChunk chunk,
      GroovycOutputParser.OutputItem item,
      Map<ModuleBuildTarget, String> generationOutputs,
      String compilerOutput,
      @NotNull ModuleBuildTarget srcTarget)
      throws IOException {
    if (chunk.getModules().size() > 1 && !srcTarget.equals(chunk.representativeTarget())) {
      File output = new File(item.outputPath);

      String srcTargetOutput = generationOutputs.get(srcTarget);
      if (srcTargetOutput == null) {
        LOG.info(
            "No output for "
                + srcTarget
                + "; outputs="
                + generationOutputs
                + "; targets = "
                + chunk.getTargets());
        return item.outputPath;
      }

      // todo honor package prefixes
      File correctRoot = new File(srcTargetOutput);
      File correctOutput =
          new File(correctRoot, FileUtil.getRelativePath(new File(compilerOutput), output));

      FileUtil.rename(output, correctOutput);
      return correctOutput.getPath();
    }
    return item.outputPath;
  }
 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 Map<ModuleBuildTarget, String> getStubGenerationOutputs(
     ModuleChunk chunk, CompileContext context) throws IOException {
   Map<ModuleBuildTarget, String> generationOutputs = new HashMap<ModuleBuildTarget, String>();
   File commonRoot = getStubRoot(context);
   for (ModuleBuildTarget target : chunk.getTargets()) {
     File targetRoot =
         new File(
             commonRoot,
             target.getModule().getName() + File.separator + target.getTargetType().getTypeId());
     if (targetRoot.exists() && !FileUtil.deleteWithRenaming(targetRoot)) {
       throw new IOException("External make cannot clean " + targetRoot.getPath());
     }
     if (!targetRoot.mkdirs()) {
       throw new IOException("External make cannot create " + targetRoot.getPath());
     }
     generationOutputs.put(target, targetRoot.getPath());
   }
   return generationOutputs;
 }
 @Nullable
 public static Map<ModuleBuildTarget, String> getCanonicalModuleOutputs(
     CompileContext context, ModuleChunk chunk, Builder builder) {
   Map<ModuleBuildTarget, String> finalOutputs = new LinkedHashMap<ModuleBuildTarget, String>();
   for (ModuleBuildTarget target : chunk.getTargets()) {
     File moduleOutputDir = target.getOutputDir();
     if (moduleOutputDir == null) {
       context.processMessage(
           new CompilerMessage(
               builder.getPresentableName(),
               BuildMessage.Kind.ERROR,
               "Output directory not specified for module " + target.getModule().getName()));
       return null;
     }
     //noinspection ResultOfMethodCallIgnored
     moduleOutputDir.mkdirs();
     String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath());
     assert moduleOutputPath != null;
     finalOutputs.put(
         target, moduleOutputPath.endsWith("/") ? moduleOutputPath : moduleOutputPath + "/");
   }
   return finalOutputs;
 }
 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);
   }
 }
  @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;
  }
  private void compileFiles(
      final CompileContext context,
      File frameworkHome,
      List<String> includes,
      ModuleBuildTarget buildTarget,
      List<File> sourceFiles,
      IceComponent target,
      File outputDir)
      throws StopBuildException {
    final JpsModule module = buildTarget.getModule();

    final String translatorName = target.getTranslatorName();
    if (outputDir == null) {
      context.processMessage(
          new CompilerMessage(
              getPresentableName(),
              BuildMessage.Kind.WARNING,
              "Output folder is not specified for "
                  + translatorName
                  + " in module "
                  + module.getName()
                  + ". Check facet configuration."));

      return;
    }

    List<String> command = new ArrayList<String>();
    command.add(target.getTranslatorPath(frameworkHome).getAbsolutePath());
    command.add("--list-generated");
    command.add("--output-dir");
    final String outputDirPath = outputDir.getAbsolutePath();
    command.add(outputDirPath);
    for (String include : includes) {
      command.add("-I" + include);
    }
    for (JpsModuleSourceRoot contentRoot : module.getSourceRoots()) {
      command.add("-I" + contentRoot.getFile().getAbsolutePath());
    }
    for (File source : sourceFiles) {
      command.add(source.getAbsolutePath());
    }

    try {
      Process process = new ProcessBuilder().command(command).start();

      BaseOSProcessHandler handler =
          new BaseOSProcessHandler(
              process, StringUtil.join(command, " "), CharsetToolkit.UTF8_CHARSET);
      final AtomicBoolean hasErrors = new AtomicBoolean();
      handler.addProcessListener(
          new ProcessAdapter() {
            final StringBuilder errorOutput = new StringBuilder();
            final StringBuilder stdOutput = new StringBuilder();

            @Override
            public void onTextAvailable(ProcessEvent event, Key outputType) {
              if (outputType == ProcessOutputTypes.STDERR) {
                errorOutput.append(event.getText());
              } else if (outputType == ProcessOutputTypes.STDOUT) {
                stdOutput.append(event.getText());
              }
            }

            @Override
            public void processTerminated(ProcessEvent event) {
              Document res;
              final String stdout = stdOutput.toString();
              try {
                res = JDOMUtil.loadDocument(stdout);
              } catch (Exception e) {
                context.processMessage(
                    new CompilerMessage(
                        BUILDER_NAME,
                        BuildMessage.Kind.ERROR,
                        "Can't process compiler output: " + stdout));
                hasErrors.set(true);
                return;
              }

              int exitCode = event.getExitCode();
              if (exitCode != 0) {
                for (Element source : res.getRootElement().getChildren("source")) {
                  final Element output = source.getChild("output");
                  if (output != null) {
                    String message = output.getTextTrim();

                    for (String line : message.split("\n")) {
                      int separatorIndex = line.indexOf(": ");
                      final String path;
                      final long lineNumber;
                      if (separatorIndex <= 0) {
                        path = null;
                        lineNumber = -1L;
                      } else {
                        int lineSep = line.lastIndexOf(':', separatorIndex - 1);
                        if (lineSep == -1) {
                          path = null;
                          lineNumber = -1L;
                        } else {
                          path = line.substring(0, lineSep);
                          long l;
                          try {
                            l = Long.parseLong(line.substring(lineSep + 1, separatorIndex));
                          } catch (NumberFormatException e) {
                            l = -1L;
                          }
                          lineNumber = l;
                        }
                      }

                      context.processMessage(
                          new CompilerMessage(
                              BUILDER_NAME,
                              BuildMessage.Kind.ERROR,
                              line,
                              path,
                              -1L,
                              -1L,
                              -1L,
                              lineNumber,
                              -1L));
                    }
                  }
                }

                final String stdErr = errorOutput.toString();
                if (stdErr.length() > 0) {
                  context.processMessage(
                      new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, stdErr));
                }
                context.processMessage(
                    new CompilerMessage(
                        BUILDER_NAME,
                        BuildMessage.Kind.ERROR,
                        "translator '"
                            + translatorName
                            + "' for '"
                            + module.getName()
                            + "' finished with exit code "
                            + exitCode));
                hasErrors.set(true);
              } else {
                final FileGeneratedEvent msg = new FileGeneratedEvent();

                for (Element source : res.getRootElement().getChildren("source")) {
                  for (Element file : source.getChildren("file")) {
                    final String fileName = file.getAttributeValue("name");

                    if (fileName.startsWith(outputDirPath)) {
                      msg.add(outputDirPath, fileName.substring(outputDirPath.length() + 1));
                    }
                  }
                }

                context.processMessage(msg);
              }
            }
          });
      handler.startNotify();
      handler.waitFor();
      if (hasErrors.get()) {
        throw new StopBuildException();
      }

    } catch (IOException e) {
      context.processMessage(
          new CompilerMessage(
              getPresentableName(),
              BuildMessage.Kind.ERROR,
              "Failed to translate files with " + translatorName + ". Error: " + e.getMessage()));
    }
  }