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 Set<String> getPathsToCompile(List<File> toCompile) { final Set<String> toCompilePaths = new LinkedHashSet<String>(); for (File file : toCompile) { if (LOG.isDebugEnabled()) { LOG.debug("Path to compile: " + file.getPath()); } toCompilePaths.add(FileUtil.toSystemIndependentName(file.getPath())); } return toCompilePaths; }
private static String getClasspathString(ModuleChunk chunk) { final Set<String> cp = new LinkedHashSet<String>(); for (File file : ProjectPaths.getCompilationClasspathFiles(chunk, chunk.containsTests(), false, false)) { if (file.exists()) { cp.add(FileUtil.toCanonicalPath(file.getPath())); } } return StringUtil.join(cp, File.pathSeparator); }
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 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<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 Collection<String> generateClasspath(CompileContext context, ModuleChunk chunk) { final Set<String> cp = new LinkedHashSet<String>(); // groovy_rt.jar // IMPORTANT! must be the first in classpath cp.addAll(getGroovyRtRoots()); for (File file : ProjectPaths.getCompilationClasspathFiles(chunk, chunk.containsTests(), false, false)) { cp.add(FileUtil.toCanonicalPath(file.getPath())); } for (GroovyBuilderExtension extension : JpsServiceManager.getInstance().getExtensions(GroovyBuilderExtension.class)) { cp.addAll(extension.getCompilationClassPath(context, chunk)); } return cp; }
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); }
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); } }
@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; }
public static void addCompilationOptions( List<String> options, CompileContext context, ModuleChunk chunk, @Nullable ProcessorConfigProfile profile) { if (!isEncodingSet(options)) { final CompilerEncodingConfiguration config = context.getProjectDescriptor().getEncodingConfiguration(); final String encoding = config.getPreferredModuleChunkEncoding(chunk); if (config.getAllModuleChunkEncodings(chunk).size() > 1) { final StringBuilder msgBuilder = new StringBuilder(); msgBuilder.append("Multiple encodings set for module chunk ").append(chunk.getName()); if (encoding != null) { msgBuilder.append("\n\"").append(encoding).append("\" will be used by compiler"); } context.processMessage( new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO, msgBuilder.toString())); } if (!StringUtil.isEmpty(encoding)) { options.add("-encoding"); options.add(encoding); } } final String langLevel = getLanguageLevel(chunk.getModules().iterator().next()); if (!StringUtil.isEmpty(langLevel)) { options.add("-source"); options.add(langLevel); } JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance() .getOrCreateCompilerConfiguration(context.getProjectDescriptor().getProject()); String bytecodeTarget = null; int chunkSdkVersion = -1; for (JpsModule module : chunk.getModules()) { final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE); if (sdk != null) { final int moduleSdkVersion = convertToNumber(sdk.getVersionString()); if (moduleSdkVersion != 0 /*could determine the version*/ && (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) { chunkSdkVersion = moduleSdkVersion; } } final String moduleTarget = compilerConfiguration.getByteCodeTargetLevel(module.getName()); if (moduleTarget == null) { continue; } if (bytecodeTarget == null) { bytecodeTarget = moduleTarget; } else { if (moduleTarget.compareTo(bytecodeTarget) < 0) { bytecodeTarget = moduleTarget; // use the lower possible target among modules that form the chunk } } } if (bytecodeTarget != null) { options.add("-target"); options.add(bytecodeTarget); } else { if (chunkSdkVersion > 0 && getCompilerSdkVersion(context) > chunkSdkVersion) { // force lower bytecode target level to match the version of sdk assigned to this chunk options.add("-target"); options.add("1." + chunkSdkVersion); } } if (profile != null && profile.isEnabled()) { // configuring annotation processing if (!profile.isObtainProcessorsFromClasspath()) { final String processorsPath = profile.getProcessorPath(); options.add("-processorpath"); options.add( processorsPath == null ? "" : FileUtil.toSystemDependentName(processorsPath.trim())); } final Set<String> processors = profile.getProcessors(); if (!processors.isEmpty()) { options.add("-processor"); options.add(StringUtil.join(processors, ",")); } for (Map.Entry<String, String> optionEntry : profile.getProcessorOptions().entrySet()) { options.add("-A" + optionEntry.getKey() + "=" + optionEntry.getValue()); } final File srcOutput = ProjectPaths.getAnnotationProcessorGeneratedSourcesOutputDir( chunk.getModules().iterator().next(), chunk.containsTests(), profile); if (srcOutput != null) { srcOutput.mkdirs(); options.add("-s"); options.add(srcOutput.getPath()); } } else { options.add("-proc:none"); } }
private boolean compileJava( final CompileContext context, ModuleChunk chunk, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, DiagnosticOutputConsumer diagnosticSink, final OutputFileConsumer outputSink) throws Exception { final TasksCounter counter = new TasksCounter(); COUNTER_KEY.set(context, counter); final JpsJavaExtensionService javaExt = JpsJavaExtensionService.getInstance(); final JpsJavaCompilerConfiguration compilerConfig = javaExt.getCompilerConfiguration(context.getProjectDescriptor().getProject()); assert compilerConfig != null; final Set<JpsModule> modules = chunk.getModules(); ProcessorConfigProfile profile = null; if (modules.size() == 1) { final JpsModule module = modules.iterator().next(); profile = compilerConfig.getAnnotationProcessingProfile(module); } else { // perform cycle-related validations Pair<String, LanguageLevel> pair = null; for (JpsModule module : modules) { final LanguageLevel moduleLevel = javaExt.getLanguageLevel(module); if (pair == null) { pair = Pair.create(module.getName(), moduleLevel); // first value } else { if (!Comparing.equal(pair.getSecond(), moduleLevel)) { final String message = "Modules " + pair.getFirst() + " and " + module.getName() + " must have the same language level because of cyclic dependencies between them"; diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message)); return true; } } } // check that all chunk modules are excluded from annotation processing for (JpsModule module : modules) { final ProcessorConfigProfile prof = compilerConfig.getAnnotationProcessingProfile(module); if (prof.isEnabled()) { final String message = "Annotation processing is not supported for module cycles. Please ensure that all modules from cycle [" + chunk.getName() + "] are excluded from annotation processing"; diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, message)); return true; } } } final Map<File, Set<File>> outs = buildOutputDirectoriesMap(context, chunk); final List<String> options = getCompilationOptions(context, chunk, profile); final ClassProcessingConsumer classesConsumer = new ClassProcessingConsumer(context, outputSink); if (LOG.isDebugEnabled()) { LOG.debug( "Compiling chunk [" + chunk.getName() + "] with options: \"" + StringUtil.join(options, " ") + "\""); } try { final boolean rc; if (USE_EMBEDDED_JAVAC) { final boolean useEclipse = useEclipseCompiler(context); rc = JavacMain.compile( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, context.getCancelStatus(), useEclipse); } else { final JavacServerClient client = ensureJavacServerLaunched(context); final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest( options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer); while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) { if (context.getCancelStatus().isCanceled()) { future.cancel(false); } } rc = future.getMessageHandler().isTerminatedSuccessfully(); } return rc; } finally { counter.await(); } }
private ExitCode compile( final CompileContext context, ModuleChunk chunk, DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget> dirtyFilesHolder, Collection<File> files, OutputConsumer outputConsumer) throws Exception { ExitCode exitCode = ExitCode.NOTHING_DONE; final boolean hasSourcesToCompile = !files.isEmpty(); if (!hasSourcesToCompile && !dirtyFilesHolder.hasRemovedFiles()) { return exitCode; } final ProjectDescriptor pd = context.getProjectDescriptor(); JavaBuilderUtil.ensureModuleHasJdk( chunk.representativeTarget().getModule(), context, BUILDER_NAME); final Collection<File> classpath = ProjectPaths.getCompilationClasspath(chunk, false /*context.isProjectRebuild()*/); final Collection<File> platformCp = ProjectPaths.getPlatformCompilationClasspath(chunk, false /*context.isProjectRebuild()*/); // begin compilation round final DiagnosticSink diagnosticSink = new DiagnosticSink(context); final Mappings delta = pd.dataManager.getMappings().createDelta(); final Callbacks.Backend mappingsCallback = delta.getCallback(); final OutputFilesSink outputSink = new OutputFilesSink(context, outputConsumer, mappingsCallback, chunk.getName()); try { if (hasSourcesToCompile) { final AtomicReference<String> ref = COMPILER_VERSION_INFO.get(context); final String versionInfo = ref.getAndSet(null); // display compiler version info only once per compile session if (versionInfo != null) { LOG.info(versionInfo); context.processMessage(new CompilerMessage("", BuildMessage.Kind.INFO, versionInfo)); } exitCode = ExitCode.OK; final Set<File> srcPath = new HashSet<File>(); final BuildRootIndex index = pd.getBuildRootIndex(); for (ModuleBuildTarget target : chunk.getTargets()) { for (JavaSourceRootDescriptor rd : index.getTempTargetRoots(target, context)) { srcPath.add(rd.root); } } final String chunkName = chunk.getName(); context.processMessage(new ProgressMessage("Parsing java... [" + chunkName + "]")); final int filesCount = files.size(); boolean compiledOk = true; if (filesCount > 0) { LOG.info( "Compiling " + filesCount + " java files; module: " + chunkName + (chunk.containsTests() ? " (tests)" : "")); if (LOG.isDebugEnabled()) { for (File file : files) { LOG.debug("Compiling " + file.getPath()); } LOG.debug(" classpath for " + chunkName + ":"); for (File file : classpath) { LOG.debug(" " + file.getAbsolutePath()); } LOG.debug(" platform classpath for " + chunkName + ":"); for (File file : platformCp) { LOG.debug(" " + file.getAbsolutePath()); } } compiledOk = compileJava( context, chunk, files, classpath, platformCp, srcPath, diagnosticSink, outputSink); } context.checkCanceled(); if (!compiledOk && diagnosticSink.getErrorCount() == 0) { diagnosticSink.report( new PlainMessageDiagnostic( Diagnostic.Kind.ERROR, "Compilation failed: internal java compiler error")); } if (!Utils.PROCEED_ON_ERROR_KEY.get(context, Boolean.FALSE) && diagnosticSink.getErrorCount() > 0) { if (!compiledOk) { diagnosticSink.report( new PlainMessageDiagnostic( Diagnostic.Kind.OTHER, "Errors occurred while compiling module '" + chunkName + "'")); } throw new ProjectBuildException( "Compilation failed: errors: " + diagnosticSink.getErrorCount() + "; warnings: " + diagnosticSink.getWarningCount()); } } } finally { if (JavaBuilderUtil.updateMappings( context, delta, dirtyFilesHolder, chunk, files, outputSink.getSuccessfullyCompiled())) { exitCode = ExitCode.ADDITIONAL_PASS_REQUIRED; } } return exitCode; }
@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); } }