mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
support cyclic module deps compilation for groovy
This commit is contained in:
@@ -32,23 +32,22 @@ public class IdeaTestUtil extends PlatformTestUtil {
|
||||
|
||||
public static void withLevel(final Module module, final LanguageLevel level, final Runnable r) {
|
||||
final LanguageLevelProjectExtension projectExt = LanguageLevelProjectExtension.getInstance(module.getProject());
|
||||
final LanguageLevelModuleExtension moduleExt = LanguageLevelModuleExtension.getInstance(module);
|
||||
|
||||
final LanguageLevel projectLevel = projectExt.getLanguageLevel();
|
||||
final LanguageLevel moduleLevel = moduleExt.getLanguageLevel();
|
||||
final LanguageLevel moduleLevel = LanguageLevelModuleExtension.getInstance(module).getLanguageLevel();
|
||||
try {
|
||||
projectExt.setLanguageLevel(level);
|
||||
setModuleLanguageLevel(level, moduleExt);
|
||||
setModuleLanguageLevel(module, level);
|
||||
r.run();
|
||||
}
|
||||
finally {
|
||||
setModuleLanguageLevel(moduleLevel, moduleExt);
|
||||
setModuleLanguageLevel(module, moduleLevel);
|
||||
projectExt.setLanguageLevel(projectLevel);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setModuleLanguageLevel(final LanguageLevel level, final LanguageLevelModuleExtension moduleExt) {
|
||||
final LanguageLevelModuleExtension modifiable = (LanguageLevelModuleExtension)moduleExt.getModifiableModel(true);
|
||||
public static void setModuleLanguageLevel(Module module, final LanguageLevel level) {
|
||||
final LanguageLevelModuleExtension modifiable = (LanguageLevelModuleExtension)LanguageLevelModuleExtension.getInstance(module).getModifiableModel(true);
|
||||
modifiable.setLanguageLevel(level);
|
||||
modifiable.commit();
|
||||
}
|
||||
|
||||
@@ -52,23 +52,23 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
return ExitCode.NOTHING_DONE;
|
||||
}
|
||||
|
||||
String moduleOutput = getModuleOutput(context, chunk);
|
||||
String compilerOutput = getCompilerOutput(moduleOutput);
|
||||
Map<Module, String> finalOutputs = getCanonicalModuleOutputs(context, chunk);
|
||||
Map<Module, String> generationOutputs = getGenerationOutputs(chunk, finalOutputs);
|
||||
|
||||
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);
|
||||
Map<String, String> class2Src = buildClassToSourceMap(chunk, context, toCompilePaths, finalOutputs);
|
||||
|
||||
final String encoding = context.getProjectDescriptor().getEncodingConfiguration().getPreferredModuleChunkEncoding(chunk);
|
||||
List<String> patchers = Collections.emptyList(); //todo patchers
|
||||
String compilerOutput = generationOutputs.get(chunk.representativeModule());
|
||||
final File tempFile = GroovycOSProcessHandler.fillFileWithGroovycParameters(
|
||||
compilerOutput, toCompilePaths, FileUtil.toSystemDependentName(moduleOutput), class2Src, encoding, patchers
|
||||
compilerOutput, toCompilePaths, finalOutputs.get(chunk.representativeModule()), class2Src, encoding, patchers
|
||||
);
|
||||
|
||||
//todo different outputs in a chunk
|
||||
//todo xmx
|
||||
final List<String> cmd = ExternalProcessUtil.buildJavaCommandLine(
|
||||
getJavaExecutable(chunk),
|
||||
@@ -98,13 +98,24 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
|
||||
if (myForStubs) {
|
||||
JavaBuilder.addTempSourcePathRoot(context, new File(compilerOutput));
|
||||
for (Module module : generationOutputs.keySet()) {
|
||||
File root = new File(generationOutputs.get(module));
|
||||
context.getRootsIndex().associateRoot(root, module, context.isCompilingTests(), true);
|
||||
JavaBuilder.addTempSourcePathRoot(context, root);
|
||||
}
|
||||
}
|
||||
|
||||
for (CompilerMessage message : handler.getCompilerMessages()) {
|
||||
context.processMessage(message);
|
||||
}
|
||||
if (!myForStubs && updateDependencies(context, chunk, toCompile, moduleOutput, handler.getSuccessfullyCompiled())) {
|
||||
|
||||
|
||||
List<GroovycOSProcessHandler.OutputItem> compiled = new ArrayList<GroovycOSProcessHandler.OutputItem>();
|
||||
for (GroovycOSProcessHandler.OutputItem item : handler.getSuccessfullyCompiled()) {
|
||||
compiled.add(ensureCorrectOutput(context, chunk, item, generationOutputs, compilerOutput));
|
||||
}
|
||||
|
||||
if (!myForStubs && updateDependencies(context, chunk, toCompile, generationOutputs, compiled)) {
|
||||
return ExitCode.ADDITIONAL_PASS_REQUIRED;
|
||||
}
|
||||
return ExitCode.OK;
|
||||
@@ -114,6 +125,48 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Module, String> getGenerationOutputs(ModuleChunk chunk, Map<Module, String> finalOutputs) throws IOException {
|
||||
Map<Module, String> generationOutputs = new HashMap<Module, String>();
|
||||
for (Module module : chunk.getModules()) {
|
||||
generationOutputs.put(module, myForStubs ? FileUtil.createTempDirectory("groovyStubs", module.getName()).getPath() : finalOutputs.get(module));
|
||||
}
|
||||
return generationOutputs;
|
||||
}
|
||||
|
||||
private static Map<Module, String> getCanonicalModuleOutputs(CompileContext context, ModuleChunk chunk) {
|
||||
Map<Module, String> finalOutputs = new HashMap<Module, String>();
|
||||
for (Module module : chunk.getModules()) {
|
||||
File moduleOutputDir = context.getProjectPaths().getModuleOutputDir(module, context.isCompilingTests());
|
||||
assert moduleOutputDir != null;
|
||||
String moduleOutputPath = FileUtil.toCanonicalPath(moduleOutputDir.getPath());
|
||||
assert moduleOutputPath != null;
|
||||
finalOutputs.put(module, moduleOutputPath.endsWith("/") ? moduleOutputPath : moduleOutputPath + "/");
|
||||
}
|
||||
return finalOutputs;
|
||||
}
|
||||
|
||||
private static GroovycOSProcessHandler.OutputItem ensureCorrectOutput(CompileContext context,
|
||||
ModuleChunk chunk,
|
||||
GroovycOSProcessHandler.OutputItem item, Map<Module, String> generationOutputs, String compilerOutput) throws IOException {
|
||||
if (chunk.getModules().size() > 1) {
|
||||
RootDescriptor descriptor = context.getModuleAndRoot(new File(item.sourcePath));
|
||||
if (descriptor != null) {
|
||||
Module srcModule = context.getProject().getModules().get(descriptor.module);
|
||||
if (srcModule != null && srcModule != chunk.representativeModule()) {
|
||||
File output = new File(item.outputPath);
|
||||
|
||||
//todo honor package prefixes
|
||||
File correctRoot = new File(generationOutputs.get(srcModule));
|
||||
File correctOutput = new File(correctRoot, FileUtil.getRelativePath(new File(compilerOutput), output));
|
||||
|
||||
FileUtil.rename(output, correctOutput);
|
||||
return new GroovycOSProcessHandler.OutputItem(correctOutput.getPath(), item.sourcePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private static String getJavaExecutable(ModuleChunk chunk) {
|
||||
Sdk sdk = chunk.getModules().iterator().next().getSdk();
|
||||
if (sdk instanceof JavaSdk) {
|
||||
@@ -122,23 +175,11 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
return SystemProperties.getJavaHome() + "/bin/java";
|
||||
}
|
||||
|
||||
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 + "/";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldHonorFileEncodingForCompilation(File file) {
|
||||
return isGroovyFile(file.getAbsolutePath());
|
||||
}
|
||||
|
||||
private String getCompilerOutput(String moduleOutputDir) throws IOException {
|
||||
return FileUtil.toCanonicalPath((myForStubs ? FileUtil.createTempDirectory("groovyStubs", null) : new File(moduleOutputDir)).getPath());
|
||||
}
|
||||
|
||||
private static List<File> collectChangedFiles(CompileContext context, ModuleChunk chunk) throws IOException {
|
||||
final List<File> toCompile = new ArrayList<File>();
|
||||
context.processFilesToRecompile(chunk, new FileProcessor() {
|
||||
@@ -156,7 +197,7 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
private boolean updateDependencies(CompileContext context,
|
||||
ModuleChunk chunk,
|
||||
List<File> toCompile,
|
||||
String moduleOutputPath,
|
||||
Map<Module, String> generationOutputs,
|
||||
List<GroovycOSProcessHandler.OutputItem> successfullyCompiled) throws IOException {
|
||||
final Mappings delta = context.createDelta();
|
||||
final List<File> successfullyCompiledFiles = new ArrayList<File>();
|
||||
@@ -172,11 +213,11 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
if (moduleAndRoot != null) {
|
||||
final String moduleName = moduleAndRoot.module;
|
||||
context.getDataManager().getSourceToOutputMap(moduleName, moduleAndRoot.isTestRoot).appendData(sourcePath, outputPath);
|
||||
String moduleOutputPath = generationOutputs.get(context.getProject().getModules().get(moduleName));
|
||||
generatedEvent.add(moduleOutputPath, FileUtil.getRelativePath(moduleOutputPath, outputPath, '/'));
|
||||
}
|
||||
callback.associate(outputPath, sourcePath, new ClassReader(FileUtil.loadFileBytes(new File(outputPath))));
|
||||
successfullyCompiledFiles.add(new File(sourcePath));
|
||||
|
||||
generatedEvent.add(moduleOutputPath, FileUtil.getRelativePath(moduleOutputPath, outputPath, '/'));
|
||||
}
|
||||
|
||||
context.processMessage(generatedEvent);
|
||||
@@ -205,9 +246,10 @@ public class GroovyBuilder extends ModuleLevelBuilder {
|
||||
return path.endsWith(".groovy") || path.endsWith(".gpp");
|
||||
}
|
||||
|
||||
private static Map<String, String> buildClassToSourceMap(ModuleChunk chunk, CompileContext context, Set<String> toCompilePaths, String moduleOutputPath) throws IOException {
|
||||
private static Map<String, String> buildClassToSourceMap(ModuleChunk chunk, CompileContext context, Set<String> toCompilePaths, Map<Module, String> finalOutputs) throws IOException {
|
||||
final Map<String, String> class2Src = new HashMap<String, String>();
|
||||
for (Module module : chunk.getModules()) {
|
||||
String moduleOutputPath = finalOutputs.get(module);
|
||||
final SourceToOutputMapping srcToOut = context.getDataManager().getSourceToOutputMap(module.getName(), context.isCompilingTests());
|
||||
for (String src : srcToOut.getKeys()) {
|
||||
if (!toCompilePaths.contains(src) && isGroovyFile(src) &&
|
||||
|
||||
@@ -567,6 +567,42 @@ class Main {
|
||||
assertEmpty make()
|
||||
}
|
||||
|
||||
public void "test module cycle"() {
|
||||
def dep = addDependentModule()
|
||||
PsiTestUtil.addDependency(myModule, dep)
|
||||
addGroovyLibrary(dep)
|
||||
|
||||
myFixture.addFileToProject('Foo.groovy', 'class Foo extends Bar { static void main(String[] args) { println "Hello from Foo" } }')
|
||||
myFixture.addFileToProject('FooX.java', 'class FooX extends Bar { }')
|
||||
myFixture.addFileToProject("dependent/Bar.groovy", "class Bar { Foo f; static void main(String[] args) { println 'Hello from Bar' } }")
|
||||
myFixture.addFileToProject("dependent/BarX.java", "class BarX { Foo f; }")
|
||||
|
||||
def checkClassFiles = {
|
||||
assert findClassFile('Foo', myModule)
|
||||
assert findClassFile('FooX', myModule)
|
||||
assert findClassFile('Bar', dep)
|
||||
assert findClassFile('BarX', dep)
|
||||
|
||||
assert !findClassFile('Bar', myModule)
|
||||
assert !findClassFile('BarX', myModule)
|
||||
assert !findClassFile('Foo', dep)
|
||||
assert !findClassFile('FooX', dep)
|
||||
}
|
||||
|
||||
println '1'
|
||||
assertEmpty make()
|
||||
checkClassFiles()
|
||||
|
||||
println '2'
|
||||
assertEmpty make()
|
||||
checkClassFiles()
|
||||
|
||||
assertOutput('Foo', 'Hello from Foo', myModule)
|
||||
assertOutput('Bar', 'Hello from Bar', dep)
|
||||
|
||||
checkClassFiles()
|
||||
}
|
||||
|
||||
public void testCompileTimeConstants() {
|
||||
myFixture.addFileToProject 'Gr.groovy', '''
|
||||
interface Gr {
|
||||
|
||||
+12
-3
@@ -51,6 +51,7 @@ import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
|
||||
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
|
||||
@@ -184,8 +185,10 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC
|
||||
final ContentEntry entry = model.addContentEntry(depRoot);
|
||||
entry.addSourceFolder(depRoot, false);
|
||||
model.setSdk(ModuleRootManager.getInstance(myModule).getSdk());
|
||||
|
||||
model.commit();
|
||||
|
||||
IdeaTestUtil.setModuleLanguageLevel(dep, LanguageLevelModuleExtension.getInstance(myModule).getLanguageLevel());
|
||||
|
||||
result.setResult(dep);
|
||||
}
|
||||
}.execute().getResultObject();
|
||||
@@ -208,9 +211,15 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC
|
||||
}
|
||||
|
||||
@Nullable protected VirtualFile findClassFile(String className) {
|
||||
final CompilerModuleExtension extension = ModuleRootManager.getInstance(myModule).getModuleExtension(CompilerModuleExtension.class);
|
||||
return findClassFile(className, myModule);
|
||||
}
|
||||
@Nullable protected VirtualFile findClassFile(String className, Module module) {
|
||||
//noinspection ConstantConditions
|
||||
return extension.getCompilerOutputPath().findChild(className + ".class");
|
||||
VirtualFile path = ModuleRootManager.getInstance(module).getModuleExtension(CompilerModuleExtension.class).getCompilerOutputPath();
|
||||
path.getChildren();
|
||||
assert path != null;
|
||||
path.refresh(false, true);
|
||||
return path.findChild(className + ".class");
|
||||
}
|
||||
|
||||
protected static void touch(VirtualFile file) throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user