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;
 }
 private static Map<String, String> buildClassToSourceMap(
     ModuleChunk chunk,
     CompileContext context,
     Set<String> toCompilePaths,
     String moduleOutputPath)
     throws IOException {
   final Map<String, String> class2Src = new HashMap<String, String>();
   for (Module module : chunk.getModules()) {
     final String moduleName = module.getName().toLowerCase(Locale.US);
     final SourceToOutputMapping srcToOut =
         context.getDataManager().getSourceToOutputMap(moduleName, context.isCompilingTests());
     for (String src : srcToOut.getKeys()) {
       if (!toCompilePaths.contains(src) && isGroovyFile(src)) {
         final Collection<String> outs = srcToOut.getState(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;
 }
 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 ExitCode build(
      final CompileContext context,
      final ModuleChunk chunk,
      DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
      OutputConsumer outputConsumer)
      throws ProjectBuildException {
    if (!IS_ENABLED.get(context, Boolean.TRUE)) {
      return ExitCode.NOTHING_DONE;
    }
    try {
      final Map<File, ModuleBuildTarget> filesToCompile =
          new THashMap<File, ModuleBuildTarget>(FileUtil.FILE_HASHING_STRATEGY);

      dirtyFilesHolder.processDirtyFiles(
          new FileProcessor<JavaSourceRootDescriptor, ModuleBuildTarget>() {
            public boolean apply(
                ModuleBuildTarget target, File file, JavaSourceRootDescriptor descriptor)
                throws IOException {
              if (JAVA_SOURCES_FILTER.accept(file)) {
                filesToCompile.put(file, target);
              }
              return true;
            }
          });

      if (context.isMake()) {
        final ProjectBuilderLogger logger = context.getLoggingManager().getProjectBuilderLogger();
        if (logger.isEnabled()) {
          if (filesToCompile.size() > 0) {
            logger.logCompiledFiles(filesToCompile.keySet(), BUILDER_NAME, "Compiling files:");
          }
        }
      }

      return compile(context, chunk, dirtyFilesHolder, filesToCompile.keySet(), outputConsumer);
    } catch (ProjectBuildException e) {
      throw e;
    } catch (Exception e) {
      String message = e.getMessage();
      if (message == null) {
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        final PrintStream stream = new PrintStream(out);
        try {
          e.printStackTrace(stream);
        } finally {
          stream.close();
        }
        message = "Internal error: \n" + out.toString();
      }
      context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, message));
      throw new ProjectBuildException(message, e);
    }
  }
 private static void rememberStubSources(
     CompileContext context,
     Map<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>> compiled) {
   Map<String, String> stubToSrc = STUB_TO_SRC.get(context);
   if (stubToSrc == null) {
     STUB_TO_SRC.set(context, stubToSrc = new HashMap<String, String>());
   }
   for (Collection<GroovycOutputParser.OutputItem> items : compiled.values()) {
     for (GroovycOutputParser.OutputItem item : items) {
       stubToSrc.put(FileUtil.toSystemIndependentName(item.outputPath), item.sourcePath);
     }
   }
 }
  private static void setContinuation(
      CompileContext context, ModuleChunk chunk, @Nullable GroovycContinuation continuation) {
    clearContinuation(context, chunk);
    if (continuation != null) {
      if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
        LOG.info("registering continuation for " + chunk);
      }

      Map<ModuleChunk, GroovycContinuation> map = CONTINUATIONS.get(context);
      if (map == null) CONTINUATIONS.set(context, map = ContainerUtil.newConcurrentMap());
      map.put(chunk, continuation);
    }
  }
  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<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;
 }
 public void process(CompileContext context, OutputFileObject out) {
   Map<String, String> stubToSrc = STUB_TO_SRC.get(context);
   if (stubToSrc == null) {
     return;
   }
   File src = out.getSourceFile();
   if (src == null) {
     return;
   }
   String groovy = stubToSrc.get(FileUtil.toSystemIndependentName(src.getPath()));
   if (groovy == null) {
     return;
   }
   try {
     final File groovyFile = new File(groovy);
     if (!FSOperations.isMarkedDirty(context, CompilationRound.CURRENT, groovyFile)) {
       FSOperations.markDirty(context, CompilationRound.NEXT, groovyFile);
       FILES_MARKED_DIRTY_FOR_NEXT_ROUND.set(context, Boolean.TRUE);
     }
   } catch (IOException e) {
     LOG.error(e);
   }
 }
 @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;
 }
  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);
      }
    }
  }
 @Nullable
 private static GroovycContinuation takeContinuation(CompileContext context, ModuleChunk chunk) {
   Map<ModuleChunk, GroovycContinuation> map = CONTINUATIONS.get(context);
   return map == null ? null : map.remove(chunk);
 }
  @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;
  }
  @Override
  public ExitCode build(
      final CompileContext context,
      ModuleChunk chunk,
      DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder,
      OutputConsumer outputConsumer)
      throws ProjectBuildException, IOException {
    if (!useGreclipse(context)) return ModuleLevelBuilder.ExitCode.NOTHING_DONE;

    try {
      final List<File> toCompile =
          GroovyBuilder.collectChangedFiles(
              context, dirtyFilesHolder, false, true, Ref.create(false));
      if (toCompile.isEmpty()) {
        return ExitCode.NOTHING_DONE;
      }

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

      JpsProject project = context.getProjectDescriptor().getProject();
      GreclipseSettings greclipseSettings = GreclipseJpsCompilerSettings.getSettings(project);
      if (greclipseSettings == null) {
        String message = "Compiler settings component not initialized for " + project;
        LOG.error(message);
        context.processMessage(
            new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, message));
        return ExitCode.ABORT;
      }

      ClassLoader loader = createGreclipseLoader(greclipseSettings.greclipsePath);
      if (loader == null) {
        context.processMessage(
            new CompilerMessage(
                getPresentableName(),
                BuildMessage.Kind.ERROR,
                "Invalid jar path in the compiler settings: '"
                    + greclipseSettings.greclipsePath
                    + "'"));
        return ExitCode.ABORT;
      }

      final JpsJavaExtensionService javaExt = JpsJavaExtensionService.getInstance();
      final JpsJavaCompilerConfiguration compilerConfig = javaExt.getCompilerConfiguration(project);
      assert compilerConfig != null;

      final Set<JpsModule> modules = chunk.getModules();
      ProcessorConfigProfile profile = null;
      if (modules.size() == 1) {
        profile = compilerConfig.getAnnotationProcessingProfile(modules.iterator().next());
      } else {
        String message = JavaBuilder.validateCycle(chunk, javaExt, compilerConfig, modules);
        if (message != null) {
          context.processMessage(
              new CompilerMessage(getPresentableName(), BuildMessage.Kind.ERROR, message));
          return ExitCode.ABORT;
        }
      }

      String mainOutputDir = outputDirs.get(chunk.representativeTarget());
      final List<String> args =
          createCommandLine(context, chunk, toCompile, mainOutputDir, profile, greclipseSettings);

      if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
        LOG.debug("Compiling with args: " + args);
      }

      Boolean notified = COMPILER_VERSION_INFO.get(context);
      if (notified != Boolean.TRUE) {
        context.processMessage(
            new CompilerMessage(
                "",
                BuildMessage.Kind.INFO,
                "Using Groovy-Eclipse to compile Java & Groovy sources"));
        COMPILER_VERSION_INFO.set(context, Boolean.TRUE);
      }

      context.processMessage(
          new ProgressMessage("Compiling java & groovy [" + chunk.getPresentableShortName() + "]"));

      StringWriter out = new StringWriter();
      StringWriter err = new StringWriter();
      HashMap<String, List<String>> outputMap = ContainerUtil.newHashMap();

      boolean success = performCompilation(args, out, err, outputMap, context, chunk);

      List<GroovycOutputParser.OutputItem> items = ContainerUtil.newArrayList();
      for (String src : outputMap.keySet()) {
        //noinspection ConstantConditions
        for (String classFile : outputMap.get(src)) {
          items.add(
              new GroovycOutputParser.OutputItem(
                  FileUtil.toSystemIndependentName(mainOutputDir + classFile),
                  FileUtil.toSystemIndependentName(src)));
        }
      }
      Map<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>> successfullyCompiled =
          GroovyBuilder.processCompiledFiles(context, chunk, outputDirs, mainOutputDir, items);

      EclipseOutputParser parser = new EclipseOutputParser(getPresentableName(), chunk);
      List<CompilerMessage> messages =
          ContainerUtil.concat(
              parser.parseMessages(out.toString()), parser.parseMessages(err.toString()));
      boolean hasError = false;
      for (CompilerMessage message : messages) {
        if (message.getKind() == BuildMessage.Kind.ERROR) {
          hasError = true;
        }
        context.processMessage(message);
      }

      if (!success && !hasError) {
        context.processMessage(
            new CompilerMessage(
                getPresentableName(), BuildMessage.Kind.ERROR, "Compilation failed"));
      }

      GroovyBuilder.updateDependencies(
          context, toCompile, successfullyCompiled, outputConsumer, this);
      return ExitCode.OK;

    } catch (Exception e) {
      throw new ProjectBuildException(e);
    }
  }
  public Builder.ExitCode build(final CompileContext context, ModuleChunk chunk)
      throws ProjectBuildException {
    ExitCode exitCode = ExitCode.OK;
    final Map<File, Module> toCompile = new HashMap<File, Module>();
    try {
      context.processFilesToRecompile(
          chunk,
          new FileProcessor() {
            @Override
            public boolean apply(Module module, File file, String sourceRoot) throws Exception {
              final String path = file.getPath();
              if (isGroovyFile(path)) { // todo file type check
                toCompile.put(file, module);
              }
              return true;
            }
          });

      if (toCompile.isEmpty()) {
        return exitCode;
      }

      final Set<String> cp = new LinkedHashSet<String>();
      // groovy_rt.jar
      // IMPORTANT! must be the first in classpath
      cp.add(ClasspathBootstrap.getResourcePath(GroovyCompilerWrapper.class).getPath());

      for (File file :
          context
              .getProjectPaths()
              .getClasspathFiles(chunk, ClasspathKind.compile(context.isCompilingTests()), false)) {
        cp.add(FileUtil.toCanonicalPath(file.getPath()));
      }
      for (File file :
          context
              .getProjectPaths()
              .getClasspathFiles(chunk, ClasspathKind.runtime(context.isCompilingTests()), false)) {
        cp.add(FileUtil.toCanonicalPath(file.getPath()));
      }

      final File tempFile = FileUtil.createTempFile("ideaGroovyToCompile", ".txt", true);
      final Module representativeModule = chunk.getModules().iterator().next();
      File moduleOutputDir =
          context
              .getProjectPaths()
              .getModuleOutputDir(representativeModule, context.isCompilingTests());
      final File dir =
          myForStubs
              ? FileUtil.createTempDirectory(/*new File("/tmp/stubs/"), */ "groovyStubs", null)
              : moduleOutputDir;
      assert dir != null;

      final Set<String> toCompilePaths = new LinkedHashSet<String>();
      for (File file : toCompile.keySet()) {
        toCompilePaths.add(FileUtil.toSystemIndependentName(file.getPath()));
      }

      String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath());
      if (!moduleOutputPath.endsWith("/")) {
        moduleOutputPath += "/";
      }
      Map<String, String> class2Src =
          buildClassToSourceMap(chunk, context, toCompilePaths, moduleOutputPath);

      String encoding = "UTF-8"; // todo encoding
      List<String> patchers = Collections.emptyList(); // todo patchers
      GroovycOSProcessHandler.fillFileWithGroovycParameters(
          tempFile,
          FileUtil.toCanonicalPath(dir.getPath()),
          toCompilePaths,
          FileUtil.toSystemDependentName(moduleOutputPath),
          class2Src,
          encoding,
          patchers);

      if (myForStubs) {
        JavaBuilder.addTempSourcePathRoot(context, dir);
      }

      // todo CompilerUtil.addLocaleOptions()
      // todo different outputs in a chunk
      // todo module jdk path
      final List<String> cmd =
          ExternalProcessUtil.buildJavaCommandLine(
              SystemProperties.getJavaHome() + "/bin/java",
              "org.jetbrains.groovy.compiler.rt.GroovycRunner",
              Collections.<String>emptyList(),
              new ArrayList<String>(cp),
              Arrays.asList(
                  "-Xmx384m" /*, "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5858"*/),
              Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath()));

      deleteCorrespondingOutputFiles(context, toCompile);

      List<GroovycOSProcessHandler.OutputItem> successfullyCompiled = Collections.emptyList();
      try {
        final Process process = Runtime.getRuntime().exec(cmd.toArray(new String[cmd.size()]));
        GroovycOSProcessHandler handler =
            new GroovycOSProcessHandler(process, null) {
              @Override
              protected void updateStatus(@Nullable String status) {
                context.processMessage(
                    new ProgressMessage(status == null ? GROOVY_COMPILER_IN_OPERATION : status));
              }
            };
        handler.startNotify();
        handler.waitFor();

        successfullyCompiled = handler.getSuccessfullyCompiled();

        final List<CompilerMessage> messages = handler.getCompilerMessages();
        for (CompilerMessage message : messages) {
          context.processMessage(message);
        }

        boolean hasMessages = !messages.isEmpty();

        final StringBuffer unparsedBuffer = handler.getStdErr();
        if (unparsedBuffer.length() != 0) {
          context.processMessage(
              new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, unparsedBuffer.toString()));
        }

        final int exitValue = handler.getProcess().exitValue();
        if (!hasMessages && exitValue != 0) {
          context.processMessage(
              new CompilerMessage(
                  BUILDER_NAME,
                  BuildMessage.Kind.ERROR,
                  "Internal groovyc error: code " + exitValue));
        }
      } finally {
        if (!myForStubs) {
          final Mappings delta = context.createDelta();
          final List<File> successfullyCompiledFiles = new ArrayList<File>();
          if (!successfullyCompiled.isEmpty()) {
            final Callbacks.Backend callback = delta.getCallback();

            for (GroovycOSProcessHandler.OutputItem item : successfullyCompiled) {
              final String sourcePath = FileUtil.toSystemIndependentName(item.sourcePath);
              final String outputPath = FileUtil.toSystemIndependentName(item.outputPath);
              final RootDescriptor moduleAndRoot = context.getModuleAndRoot(new File(sourcePath));
              if (moduleAndRoot != null) {
                final String moduleName = moduleAndRoot.module.getName().toLowerCase(Locale.US);
                context
                    .getDataManager()
                    .getSourceToOutputMap(moduleName, moduleAndRoot.isTestRoot)
                    .appendData(sourcePath, outputPath);
              }
              callback.associate(
                  outputPath,
                  Callbacks.getDefaultLookup(sourcePath),
                  new ClassReader(FileUtil.loadFileBytes(new File(outputPath))));
              successfullyCompiledFiles.add(new File(sourcePath));
            }
          }

          final boolean needSecondPass =
              updateMappings(context, delta, chunk, toCompile.keySet(), successfullyCompiledFiles);
          if (needSecondPass) {
            exitCode = ExitCode.ADDITIONAL_PASS_REQUIRED;
          }
        }
      }

      return exitCode;
    } catch (Exception e) {
      throw new ProjectBuildException(e);
    }
  }