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 String getModuleOutput(CompileContext context, ModuleChunk chunk) {
   final Module representativeModule = chunk.getModules().iterator().next();
   File moduleOutputDir =
       context
           .getProjectPaths()
           .getModuleOutputDir(representativeModule, context.isCompilingTests());
   assert moduleOutputDir != null;
   String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath());
   return moduleOutputPath.endsWith("/") ? moduleOutputPath : moduleOutputPath + "/";
 }
  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 boolean performCompilation(
      List<String> args,
      StringWriter out,
      StringWriter err,
      Map<String, List<String>> outputs,
      CompileContext context,
      ModuleChunk chunk) {
    try {
      Class<?> mainClass = Class.forName(GreclipseMain.class.getName(), true, myGreclipseLoader);
      Constructor<?> constructor =
          mainClass.getConstructor(PrintWriter.class, PrintWriter.class, Map.class, Map.class);
      Method compileMethod = mainClass.getMethod("compile", String[].class);

      HashMap<String, Object> customDefaultOptions = ContainerUtil.newHashMap();
      // without this greclipse won't load AST transformations
      customDefaultOptions.put(
          "org.eclipse.jdt.core.compiler.groovy.groovyClassLoaderPath", getClasspathString(chunk));

      // used by greclipse to cache transform loaders
      // names should be different for production & tests
      customDefaultOptions.put(
          "org.eclipse.jdt.core.compiler.groovy.groovyProjectName",
          chunk.getPresentableShortName());

      Object main =
          constructor.newInstance(
              new PrintWriter(out), new PrintWriter(err), customDefaultOptions, outputs);
      return (Boolean) compileMethod.invoke(main, new Object[] {ArrayUtil.toStringArray(args)});
    } catch (Exception e) {
      context.processMessage(new CompilerMessage(getPresentableName(), e));
      return false;
    }
  }
 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;
 }
 @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 void save(@NotNull final OutputFileObject fileObject) {
      if (JavaFileObject.Kind.CLASS != fileObject.getKind()) {
        // generated sources or resources must be saved synchronously, because some compilers (e.g.
        // eclipse)
        // may want to read generated text for further compilation
        try {
          final BinaryContent content = fileObject.getContent();
          if (content != null) {
            content.saveToFile(fileObject.getFile());
          }
        } catch (IOException e) {
          myContext.processMessage(
              new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, e.getMessage()));
        }
      }

      submitAsyncTask(
          myContext,
          new Runnable() {
            public void run() {
              try {
                for (ClassPostProcessor processor : ourClassProcessors) {
                  processor.process(myContext, fileObject);
                }
              } finally {
                myDelegateOutputFileSink.save(fileObject);
              }
            }
          });
    }
 static boolean useGreclipse(CompileContext context) {
   JpsProject project = context.getProjectDescriptor().getProject();
   return ID.equals(
       JpsJavaExtensionService.getInstance()
           .getOrCreateCompilerConfiguration(project)
           .getJavaCompilerId());
 }
 public void outputLineAvailable(String line) {
   if (!StringUtil.isEmpty(line)) {
     if (line.contains("java.lang.OutOfMemoryError")) {
       myContext.processMessage(
           new CompilerMessage(
               BUILDER_NAME, BuildMessage.Kind.ERROR, "OutOfMemoryError: insufficient memory"));
       myErrorCount++;
     } else {
       final BuildMessage.Kind kind = getKindByMessageText(line);
       if (kind == BuildMessage.Kind.ERROR) {
         myErrorCount++;
       } else if (kind == BuildMessage.Kind.WARNING) {
         myWarningCount++;
       }
       myContext.processMessage(new CompilerMessage(BUILDER_NAME, kind, line));
     }
   }
 }
  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 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);
 }
 private static void addMessages(
     @NotNull final CompileContext context,
     @NotNull final Map<CompilerMessageCategory, List<String>> messages,
     @NotNull final String url) {
   for (final CompilerMessageCategory category : messages.keySet()) {
     final List<String> messageList = messages.get(category);
     for (final String message : messageList) {
       context.addMessage(category, message, url, -1, -1);
     }
   }
 }
 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()));
   }
 }
  private static List<String> generateClasspath(CompileContext context, ModuleChunk chunk) {
    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()));
    }
    return new ArrayList<String>(cp);
  }
  private boolean updateDependencies(
      CompileContext context,
      ModuleChunk chunk,
      List<File> toCompile,
      String moduleOutputPath,
      List<GroovycOSProcessHandler.OutputItem> successfullyCompiled)
      throws IOException {
    final Mappings delta = context.createDelta();
    final List<File> successfullyCompiledFiles = new ArrayList<File>();
    if (!successfullyCompiled.isEmpty()) {

      final Callbacks.Backend callback = delta.getCallback();
      final FileGeneratedEvent generatedEvent = new FileGeneratedEvent();

      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));

        generatedEvent.add(
            moduleOutputPath, FileUtil.getRelativePath(moduleOutputPath, outputPath, '/'));
      }

      context.processMessage(generatedEvent);
    }

    return updateMappings(context, delta, chunk, toCompile, successfullyCompiledFiles);
  }
 @Override
 public void buildStarted(CompileContext context) {
   if (myForStubs) {
     File stubRoot = getStubRoot(context);
     if (stubRoot.exists() && !FileUtil.deleteWithRenaming(stubRoot)) {
       context.processMessage(
           new CompilerMessage(
               myBuilderName,
               BuildMessage.Kind.ERROR,
               "External make cannot clean " + stubRoot.getPath()));
     }
   }
 }
  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;
  }
  public static void updateDependencies(
      CompileContext context,
      List<File> toCompile,
      Map<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>> successfullyCompiled,
      OutputConsumer outputConsumer,
      Builder builder)
      throws IOException {
    JavaBuilderUtil.registerFilesToCompile(context, toCompile);
    if (!successfullyCompiled.isEmpty()) {

      final Callbacks.Backend callback = JavaBuilderUtil.getDependenciesRegistrar(context);

      for (Map.Entry<ModuleBuildTarget, Collection<GroovycOutputParser.OutputItem>> entry :
          successfullyCompiled.entrySet()) {
        final ModuleBuildTarget target = entry.getKey();
        final Collection<GroovycOutputParser.OutputItem> compiled = entry.getValue();
        for (GroovycOutputParser.OutputItem item : compiled) {
          final String sourcePath = FileUtil.toSystemIndependentName(item.sourcePath);
          final String outputPath = FileUtil.toSystemIndependentName(item.outputPath);
          final File outputFile = new File(outputPath);
          final File srcFile = new File(sourcePath);
          try {
            final byte[] bytes = FileUtil.loadFileBytes(outputFile);
            if (Utils.IS_TEST_MODE || LOG.isDebugEnabled()) {
              LOG.info("registerCompiledClass " + outputFile + " from " + srcFile);
            }
            outputConsumer.registerCompiledClass(
                target,
                new CompiledClass(
                    outputFile, srcFile, readClassName(bytes), new BinaryContent(bytes)));
            callback.associate(outputPath, sourcePath, new FailSafeClassReader(bytes));
          } catch (Throwable e) {
            // need this to make sure that unexpected errors in, for example, ASM will not ruin the
            // compilation
            final String message =
                "Class dependency information may be incomplete! Error parsing generated class "
                    + item.outputPath;
            LOG.info(message, e);
            context.processMessage(
                new CompilerMessage(
                    builder.getPresentableName(),
                    BuildMessage.Kind.WARNING,
                    message + "\n" + CompilerMessage.getTextFromThrowable(e),
                    sourcePath));
          }
          JavaBuilderUtil.registerSuccessfullyCompiled(context, srcFile);
        }
      }
    }
  }
 private static List<File> collectChangedFiles(CompileContext context, ModuleChunk chunk)
     throws IOException {
   final List<File> toCompile = new ArrayList<File>();
   context.processFilesToRecompile(
       chunk,
       new FileProcessor() {
         public boolean apply(Module module, File file, String sourceRoot) throws IOException {
           final String path = file.getPath();
           if (isGroovyFile(path)) { // todo file type check
             toCompile.add(file);
           }
           return true;
         }
       });
   return toCompile;
 }
 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 void report(Diagnostic<? extends JavaFileObject> diagnostic) {
   final CompilerMessage.Kind kind;
   switch (diagnostic.getKind()) {
     case ERROR:
       kind = BuildMessage.Kind.ERROR;
       myErrorCount++;
       break;
     case MANDATORY_WARNING:
     case WARNING:
     case NOTE:
       kind = BuildMessage.Kind.WARNING;
       myWarningCount++;
       break;
     default:
       kind = BuildMessage.Kind.INFO;
   }
   File sourceFile = null;
   try {
     // for eclipse compiler just an attempt to call getSource() may lead to an NPE,
     // so calling this method under try/catch to avoid induced compiler errors
     final JavaFileObject source = diagnostic.getSource();
     sourceFile = source != null ? Utils.convertToFile(source.toUri()) : null;
   } catch (Exception e) {
     LOG.info(e);
   }
   final String srcPath =
       sourceFile != null ? FileUtil.toSystemIndependentName(sourceFile.getPath()) : null;
   String message = diagnostic.getMessage(Locale.US);
   if (Utils.IS_TEST_MODE) {
     LOG.info(message);
   }
   myContext.processMessage(
       new CompilerMessage(
           BUILDER_NAME,
           kind,
           message,
           srcPath,
           diagnostic.getStartPosition(),
           diagnostic.getEndPosition(),
           diagnostic.getPosition(),
           diagnostic.getLineNumber(),
           diagnostic.getColumnNumber()));
 }
  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;
  }
  @Override
  public GenerationItem[] generate(
      final CompileContext context,
      final GenerationItem[] items,
      final VirtualFile outputRootDirectory) {
    if (items == null || items.length <= 0) {
      return EMPTY_GENERATION_ITEM_ARRAY;
    }

    context.getProgressIndicator().setText("Compiling RenderScript files...");
    final GenerationItem[] generationItems = doGenerate(context, items, outputRootDirectory);
    final Set<VirtualFile> generatedVFiles = new HashSet<VirtualFile>();
    final HashSet<VirtualFile> visited = new HashSet<VirtualFile>();

    outputRootDirectory.refresh(false, true);
    AndroidUtils.collectFiles(outputRootDirectory, visited, generatedVFiles);

    if (context instanceof CompileContextEx) {
      ((CompileContextEx) context).markGenerated(generatedVFiles);
    }
    return generationItems;
  }
 @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;
 }
  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;
  }
  public ModuleLevelBuilder.ExitCode build(final CompileContext context, ModuleChunk chunk)
      throws ProjectBuildException {
    try {
      final List<File> toCompile = collectChangedFiles(context, chunk);
      if (toCompile.isEmpty()) {
        return ExitCode.NOTHING_DONE;
      }

      String moduleOutput = getModuleOutput(context, chunk);
      String compilerOutput = getCompilerOutput(moduleOutput);

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

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

      String ideCharset = chunk.getProject().getProjectCharset();
      String encoding =
          !Comparing.equal(CharsetToolkit.getDefaultSystemCharset().name(), ideCharset)
              ? ideCharset
              : null;
      List<String> patchers = Collections.emptyList(); // todo patchers
      final File tempFile =
          GroovycOSProcessHandler.fillFileWithGroovycParameters(
              compilerOutput,
              toCompilePaths,
              FileUtil.toSystemDependentName(moduleOutput),
              class2Src,
              encoding,
              patchers);

      // todo different outputs in a chunk
      // todo xmx
      final List<String> cmd =
          ExternalProcessUtil.buildJavaCommandLine(
              getJavaExecutable(chunk),
              "org.jetbrains.groovy.compiler.rt.GroovycRunner",
              Collections.<String>emptyList(),
              new ArrayList<String>(generateClasspath(context, chunk)),
              Arrays.asList(
                  "-Xmx384m",
                  "-Dfile.encoding=" + CharsetToolkit.getDefaultSystemCharset().name() /*,
                      "-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239"*/),
              Arrays.<String>asList(myForStubs ? "stubs" : "groovyc", tempFile.getPath()));

      final Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(cmd));
      GroovycOSProcessHandler handler =
          GroovycOSProcessHandler.runGroovyc(
              process,
              new Consumer<String>() {
                public void consume(String s) {
                  context.processMessage(new ProgressMessage(s));
                }
              });

      if (handler.shouldRetry()) {
        if (CHUNK_REBUILD_ORDERED.get(context) != null) {
          CHUNK_REBUILD_ORDERED.set(context, null);
        } else {
          CHUNK_REBUILD_ORDERED.set(context, Boolean.TRUE);
          return ExitCode.CHUNK_REBUILD_REQUIRED;
        }
      }

      if (myForStubs) {
        JavaBuilder.addTempSourcePathRoot(context, new File(compilerOutput));
      }

      for (CompilerMessage message : handler.getCompilerMessages()) {
        context.processMessage(message);
      }
      if (!myForStubs
          && updateDependencies(
              context, chunk, toCompile, moduleOutput, handler.getSuccessfullyCompiled())) {
        return ExitCode.ADDITIONAL_PASS_REQUIRED;
      }
      return ExitCode.OK;
    } catch (Exception e) {
      throw new ProjectBuildException(e);
    }
  }
  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);
      }
    }
  }
 private static File getStubRoot(CompileContext context) {
   return new File(
       context.getProjectDescriptor().dataManager.getDataPaths().getDataStorageRoot(),
       "groovyStubs");
 }