mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
1. jps incremental builders, initial
2. set one project JDK and have modules use it
This commit is contained in:
Generated
+1
-1
@@ -44,7 +44,7 @@
|
||||
<component name="ProjectResources">
|
||||
<default-html-doctype>http://www.w3.org/1999/xhtml</default-html-doctype>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="1.6" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_5" assert-keyword="true" jdk-15="true" project-jdk-name="IDEA jdk" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
<component name="SvnBranchConfigurationManager">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Ant" level="project" />
|
||||
</component>
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/proto" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/build" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
<orderEntry type="library" name="Ant" level="project" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
<orderEntry type="module" module-name="jps" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="jps" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
<orderEntry type="module" module-name="jps" />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
<orderEntry type="module" module-name="jps" />
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="jps" />
|
||||
<orderEntry type="library" name="Groovy" level="project" />
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="IDEA jdk" jdkType="JavaSDK" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="jps" />
|
||||
<orderEntry type="module-library">
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public abstract class BuildTask {
|
||||
public abstract void build(CompileContext context) throws ProjectBuildException;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public abstract class Builder {
|
||||
public static enum ExitCode {
|
||||
FINISHED, ABORT, ADDITIONAL_PASS_REQUIRED
|
||||
}
|
||||
|
||||
public abstract ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException;
|
||||
|
||||
public abstract String getDescription();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public enum BuilderCategory {
|
||||
SOURCE_GENERATOR,
|
||||
SOURCE_INSTRUMENTER,
|
||||
SOURCE_PROCESSOR,
|
||||
TRANSLATOR,
|
||||
CLASS_INSTRUMENTER,
|
||||
CLASS_POST_PROCESSOR,
|
||||
PACKAGER,
|
||||
VALIDATOR
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public class BuilderRegistry {
|
||||
|
||||
public List<BuildTask> getBeforeTasks(){
|
||||
return Collections.emptyList(); // todo
|
||||
}
|
||||
|
||||
public List<BuildTask> getAfterTasks(){
|
||||
return Collections.emptyList(); // todo
|
||||
}
|
||||
|
||||
public List<Builder> getBuilders(BuilderCategory category){
|
||||
return Collections.emptyList(); // todo
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import org.jetbrains.jps.Module;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public class CompileContext {
|
||||
private final CompileScope myScope;
|
||||
|
||||
public CompileContext(CompileScope scope) {
|
||||
myScope = scope;
|
||||
}
|
||||
|
||||
|
||||
public CompileScope getScope() {
|
||||
return myScope;
|
||||
}
|
||||
|
||||
public boolean isDirty(File file) {
|
||||
return true; // todo
|
||||
}
|
||||
|
||||
public void processFiles(ModuleChunk chunk, FileProcessor processor) {
|
||||
for (Module module : chunk.getModules()) {
|
||||
if (!processModule(module, processor)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean processModule(Module module, FileProcessor processor) {
|
||||
final Set<File> excludes = new HashSet<File>();
|
||||
for (String excludePath : (Collection<String>)module.getExcludes()) {
|
||||
excludes.add(new File(excludePath));
|
||||
}
|
||||
|
||||
for (String root : (Collection<String>)module.getSourceRoots()) {
|
||||
if (!processRootRecursively(module, new File(root), processor, excludes)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processRootRecursively(final Module module, final File file, FileProcessor processor, final Set<File> excluded) {
|
||||
if (file.isDirectory()) {
|
||||
if (isExcluded(excluded, file)) {
|
||||
return true;
|
||||
}
|
||||
final File[] children = file.listFiles();
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
final boolean shouldContinue = processRootRecursively(module, child, processor, excluded);
|
||||
if (!shouldContinue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return processor.apply(module, file);
|
||||
}
|
||||
|
||||
private static boolean isExcluded(final Set<File> excludedRoots, File file) {
|
||||
while (file != null) {
|
||||
if (excludedRoots.contains(file)) {
|
||||
return true;
|
||||
}
|
||||
file = file.getParentFile();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import org.jetbrains.jps.Module;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public abstract class CompileScope {
|
||||
|
||||
public abstract Collection<Module> getAffectedModules();
|
||||
|
||||
public boolean isAffected(ModuleChunk chunk) {
|
||||
final Set<Module> modules = chunk.getModules();
|
||||
for (Module module : getAffectedModules()) {
|
||||
if (modules.contains(module)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import org.jetbrains.jps.Module;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/21/11
|
||||
*/
|
||||
public interface FileProcessor {
|
||||
/**
|
||||
* @return true if processing should continue, false if should stop
|
||||
*/
|
||||
boolean apply(Module module, File file);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import org.jetbrains.jps.Module;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/21/11
|
||||
*/
|
||||
public class FilesCollector implements FileProcessor{
|
||||
private static FileFilter ALL_FILES = new FileFilter() {
|
||||
public boolean accept(File pathname) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private final Collection<File> myContainer;
|
||||
private final FileFilter myFilter;
|
||||
|
||||
public FilesCollector() {
|
||||
this(ALL_FILES);
|
||||
}
|
||||
|
||||
public FilesCollector(FileFilter filter) {
|
||||
this(new ArrayList<File>(), filter);
|
||||
}
|
||||
|
||||
public FilesCollector(Collection<File> container, FileFilter filter) {
|
||||
myFilter = filter;
|
||||
myContainer = container;
|
||||
}
|
||||
|
||||
public Collection<File> getFiles() {
|
||||
return myContainer;
|
||||
}
|
||||
|
||||
public boolean apply(Module module, File file) {
|
||||
if (myFilter.accept(file)) {
|
||||
myContainer.add(file);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
import org.jetbrains.jps.ClasspathKind;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.Project;
|
||||
import org.jetbrains.jps.ProjectChunks;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public class IncProjectBuilder {
|
||||
|
||||
private final Project myProject;
|
||||
private final BuilderRegistry myBuilderRegistry;
|
||||
private ProjectChunks myProductionChunks;
|
||||
private ProjectChunks myTestChunks;
|
||||
|
||||
public IncProjectBuilder(Project project, BuilderRegistry builderRegistry) {
|
||||
myProject = project;
|
||||
myBuilderRegistry = builderRegistry;
|
||||
myProductionChunks = new ProjectChunks(project, ClasspathKind.PRODUCTION_COMPILE);
|
||||
myTestChunks = new ProjectChunks(project, ClasspathKind.TEST_COMPILE);
|
||||
}
|
||||
|
||||
public void build(CompileScope scope) {
|
||||
final CompileContext context = new CompileContext(scope);
|
||||
try {
|
||||
runTasks(context, myBuilderRegistry.getBeforeTasks());
|
||||
|
||||
buildChunks(context, myProductionChunks);
|
||||
|
||||
buildChunks(context, myTestChunks);
|
||||
|
||||
runTasks(context, myBuilderRegistry.getAfterTasks());
|
||||
}
|
||||
catch (ProjectBuildException e) {
|
||||
e.printStackTrace(); // todo
|
||||
}
|
||||
}
|
||||
|
||||
private void runTasks(CompileContext context, final List<BuildTask> tasks) throws ProjectBuildException {
|
||||
for (BuildTask task : tasks) {
|
||||
task.build(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildChunks(CompileContext context, ProjectChunks chunks) throws ProjectBuildException {
|
||||
final CompileScope scope = context.getScope();
|
||||
for (ModuleChunk chunk : chunks.getChunkList()) {
|
||||
if (scope.isAffected(chunk)) {
|
||||
buildChunk(context, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildChunk(CompileContext context, ModuleChunk chunk) throws ProjectBuildException{
|
||||
for (BuilderCategory category : BuilderCategory.values()) {
|
||||
runBuilders(context, chunk, myBuilderRegistry.getBuilders(category));
|
||||
}
|
||||
}
|
||||
|
||||
private void runBuilders(CompileContext context, ModuleChunk chunk, List<Builder> builders) throws ProjectBuildException {
|
||||
boolean nextPassRequired;
|
||||
do {
|
||||
nextPassRequired = false;
|
||||
for (Builder builder : builders) {
|
||||
final Builder.ExitCode buildResult = builder.build(context, chunk);
|
||||
if (buildResult == Builder.ExitCode.ABORT) {
|
||||
throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
|
||||
}
|
||||
if (buildResult == Builder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
|
||||
nextPassRequired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (nextPassRequired);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.jps.incremental;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/20/11
|
||||
*/
|
||||
public class ProjectBuildException extends Exception{
|
||||
|
||||
public ProjectBuildException() {
|
||||
}
|
||||
|
||||
public ProjectBuildException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ProjectBuildException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ProjectBuildException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/23/11
|
||||
*/
|
||||
public class EmbeddedJavac {
|
||||
private final JavaCompiler myCompiler;
|
||||
private final ExecutorService myTaskRunner;
|
||||
private final SequentialTaskExecutor mySequentialTaskExecutor;
|
||||
private final List<ClassPostProcessor> myClassProcessors = new ArrayList<ClassPostProcessor>();
|
||||
|
||||
public static interface OutputConsumer extends DiagnosticListener<JavaFileObject> {
|
||||
void outputLineAvailable(String line);
|
||||
}
|
||||
|
||||
public static interface ClassPostProcessor {
|
||||
void process(OutputFileObject out);
|
||||
}
|
||||
|
||||
public EmbeddedJavac(ExecutorService taskRunner) {
|
||||
myTaskRunner = taskRunner;
|
||||
mySequentialTaskExecutor = new SequentialTaskExecutor(taskRunner);
|
||||
myCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
}
|
||||
|
||||
public void addClassProcessor(ClassPostProcessor processor) {
|
||||
myClassProcessors.add(processor);
|
||||
}
|
||||
|
||||
public boolean compile(final List<File> sources, final List<String> options, File outputDir, final OutputConsumer outConsumer) {
|
||||
|
||||
final JavacFileManager fileManager = new JavacFileManager(new FileManagerContext(outConsumer));
|
||||
if (!fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Collections.singleton(outputDir))) {
|
||||
return false;
|
||||
}
|
||||
//todo setup file manager to support multiple outputs
|
||||
|
||||
final LineOutputWriter out = new LineOutputWriter() {
|
||||
protected void lineAvailable(String line) {
|
||||
outConsumer.outputLineAvailable(line);
|
||||
}
|
||||
};
|
||||
final List<String> _options = new ArrayList<String>();
|
||||
boolean skip = false;
|
||||
for (String option : options) {
|
||||
if ("-d".equals(option)) {
|
||||
skip = true;
|
||||
continue;
|
||||
}
|
||||
if (!skip) {
|
||||
_options.add(option);
|
||||
}
|
||||
skip = false;
|
||||
}
|
||||
final JavaCompiler.CompilationTask task = myCompiler.getTask(
|
||||
out, fileManager, outConsumer, _options, null, fileManager.toJavaFileObjects(sources)
|
||||
);
|
||||
return task.call();
|
||||
}
|
||||
|
||||
|
||||
private class FileManagerContext implements JavacFileManager.Context {
|
||||
|
||||
private final StandardJavaFileManager myStdManager;
|
||||
private final OutputConsumer myOutConsumer;
|
||||
|
||||
public FileManagerContext(OutputConsumer outConsumer) {
|
||||
myOutConsumer = outConsumer;
|
||||
myStdManager = myCompiler.getStandardFileManager(outConsumer, Locale.US, null);
|
||||
}
|
||||
|
||||
public StandardJavaFileManager getStandardFileManager() {
|
||||
return myStdManager;
|
||||
}
|
||||
|
||||
public void reportMessage(final Diagnostic.Kind kind, String message) {
|
||||
myOutConsumer.report(new PlainMessageDiagnostic(kind, message));
|
||||
}
|
||||
|
||||
public void consumeOutputFile(final OutputFileObject cls) {
|
||||
myTaskRunner.submit(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
for (ClassPostProcessor processor : myClassProcessors) {
|
||||
processor.process(cls);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
mySequentialTaskExecutor.submit(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
final File file = cls.getFile();
|
||||
final OutputFileObject.Content content = cls.getContent();
|
||||
if (content != null) {
|
||||
writeToFile(file, content.getBuffer(), content.getOffset(), content.getLength(), false);
|
||||
}
|
||||
else {
|
||||
myOutConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Missing content for file " + file));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
myOutConsumer.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeToFile(@NotNull File file, @NotNull byte[] text, final int off, final int len, boolean append) throws IOException {
|
||||
createParentDirs(file);
|
||||
OutputStream stream = new BufferedOutputStream(new FileOutputStream(file, append));
|
||||
try {
|
||||
stream.write(text, off, len);
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean createParentDirs(@NotNull File file) {
|
||||
if (!file.exists()) {
|
||||
String parentDirPath = file.getParent();
|
||||
if (parentDirPath != null) {
|
||||
final File parentFile = new File(parentDirPath);
|
||||
return parentFile.exists() && parentFile.isDirectory() || parentFile.mkdirs();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.incremental.Builder;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.FilesCollector;
|
||||
import org.jetbrains.jps.incremental.ProjectBuildException;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/21/11
|
||||
*/
|
||||
public class JavaBuilder extends Builder{
|
||||
private static final String JAVA_EXTENSION = ".java";
|
||||
|
||||
private static final FileFilter JAVA_SOURCES_FILTER = new FileFilter() {
|
||||
public boolean accept(File file) {
|
||||
return file.getName().endsWith(JAVA_EXTENSION);
|
||||
}
|
||||
};
|
||||
|
||||
public ExitCode build(CompileContext context, ModuleChunk chunk) throws ProjectBuildException {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
context.processFiles(chunk, new FilesCollector(files, JAVA_SOURCES_FILTER));
|
||||
compile(chunk, files);
|
||||
return ExitCode.FINISHED;
|
||||
}
|
||||
|
||||
private void compile(ModuleChunk chunk, List<File> files) {
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return "Java Builder";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
final ExecutorService taskRunner = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
final EmbeddedJavac javac = new EmbeddedJavac(taskRunner);
|
||||
|
||||
final File srcRoot = new File("C:/tmp/MoveClassProblem/util/src");
|
||||
final List<File> sources = new ArrayList<File>();
|
||||
collectFiles(srcRoot, sources, new FileFilter() {
|
||||
public boolean accept(File pathname) {
|
||||
return pathname.getName().endsWith(".java");
|
||||
}
|
||||
});
|
||||
final File outputDir = new File("C:/tmp/MoveClassProblem/util/_out_");
|
||||
outputDir.mkdirs();
|
||||
|
||||
final List<String> options = Arrays.asList(new String[] {
|
||||
//"-d",
|
||||
//outputDir.getAbsolutePath()
|
||||
});
|
||||
javac.compile(sources, options, outputDir, new EmbeddedJavac.OutputConsumer() {
|
||||
public void outputLineAvailable(String line) {
|
||||
System.out.println("OUTPUT: " + line);
|
||||
}
|
||||
|
||||
public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
|
||||
System.out.println("DIAGNOSTIC: " + diagnostic.getKind().name() + "/" + diagnostic.getMessage(Locale.US));
|
||||
}
|
||||
});
|
||||
|
||||
taskRunner.shutdownNow();
|
||||
}
|
||||
|
||||
private static void collectFiles(File root, Collection<File> container, FileFilter filter) {
|
||||
final File[] files = root.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
collectFiles(file, container, filter);
|
||||
}
|
||||
else {
|
||||
if (filter.accept(file)) {
|
||||
container.add(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import static javax.tools.StandardLocation.CLASS_OUTPUT;
|
||||
import static javax.tools.StandardLocation.SOURCE_OUTPUT;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/24/11
|
||||
*/
|
||||
class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {
|
||||
|
||||
private final Context myContext;
|
||||
|
||||
public static interface Context {
|
||||
StandardJavaFileManager getStandardFileManager();
|
||||
|
||||
void consumeOutputFile(OutputFileObject obj);
|
||||
|
||||
void reportMessage(final Diagnostic.Kind kind, String message);
|
||||
}
|
||||
|
||||
public JavacFileManager(Context context) {
|
||||
super(context.getStandardFileManager());
|
||||
myContext = context;
|
||||
}
|
||||
|
||||
// todo: check if reading source files can be optimized
|
||||
|
||||
public boolean setLocation(Location location, Iterable<? extends File> path) {
|
||||
try {
|
||||
getStdManager().setLocation(location, path);
|
||||
}
|
||||
catch (IOException e) {
|
||||
myContext.reportMessage(Diagnostic.Kind.ERROR, e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isSameFile(FileObject a, FileObject b) {
|
||||
if (a instanceof OutputFileObject && b instanceof OutputFileObject) {
|
||||
return a.equals(b);
|
||||
}
|
||||
return super.isSameFile(a, b);
|
||||
}
|
||||
|
||||
public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
|
||||
return super.list(location, packageName, kinds, recurse);
|
||||
}
|
||||
|
||||
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
|
||||
if (kind != JavaFileObject.Kind.SOURCE && kind != JavaFileObject.Kind.CLASS) {
|
||||
throw new IllegalArgumentException("Invalid kind " + kind);
|
||||
}
|
||||
return getFileForOutput(location, kind, externalizeFileName(className, kind), sibling);
|
||||
}
|
||||
|
||||
public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
|
||||
final StringBuilder name = new StringBuilder();
|
||||
if (packageName.isEmpty()) {
|
||||
name.append(relativeName);
|
||||
}
|
||||
else {
|
||||
name.append(externalizeFileName(packageName)).append(File.separatorChar).append(relativeName);
|
||||
}
|
||||
final String fileName = name.toString();
|
||||
return getFileForOutput(location, getKind(fileName), fileName, sibling);
|
||||
}
|
||||
|
||||
private JavaFileObject getFileForOutput(Location location, JavaFileObject.Kind kind, String fileName, FileObject sibling) throws IOException {
|
||||
File dir = null;
|
||||
if (location == CLASS_OUTPUT) {
|
||||
final File classOutDir = getSingleOutputDirectory(CLASS_OUTPUT);
|
||||
if (classOutDir == null) {
|
||||
throw new IOException("Output directory is not specified");
|
||||
}
|
||||
dir = classOutDir;
|
||||
}
|
||||
else if (location == SOURCE_OUTPUT) {
|
||||
final File sourcesOutput = getSingleOutputDirectory(StandardLocation.SOURCE_OUTPUT);
|
||||
dir = (sourcesOutput != null ? sourcesOutput : getSingleOutputDirectory(CLASS_OUTPUT));
|
||||
}
|
||||
else {
|
||||
Iterable<? extends File> path = getStdManager().getLocation(location);
|
||||
final Iterator<? extends File> it = path.iterator();
|
||||
if (it.hasNext()) {
|
||||
dir = it.next();
|
||||
}
|
||||
}
|
||||
final File file = (dir == null ? new File(fileName) : new File(dir, fileName));
|
||||
return new OutputFileObject(myContext, file, kind);
|
||||
}
|
||||
|
||||
private File getSingleOutputDirectory(final Location kind) {
|
||||
final Iterable<? extends File> location = getStdManager().getLocation(kind);
|
||||
if (location != null) {
|
||||
final Iterator<? extends File> it = location.iterator();
|
||||
if (it.hasNext()) {
|
||||
return it.next();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public StandardJavaFileManager getStdManager() {
|
||||
return fileManager;
|
||||
}
|
||||
|
||||
public Iterable<? extends JavaFileObject> toJavaFileObjects(Iterable<? extends File> files) {
|
||||
return getStdManager().getJavaFileObjectsFromFiles(files);
|
||||
}
|
||||
|
||||
private static URI toURI(String outputDir, String name, JavaFileObject.Kind kind) {
|
||||
return createUri("file:///" + outputDir.replace('\\','/') + "/" + name.replace('.', '/') + kind.extension);
|
||||
}
|
||||
|
||||
private static URI createUri(String url) {
|
||||
return URI.create(url.replaceAll(" ","%20"));
|
||||
}
|
||||
|
||||
private static JavaFileObject.Kind getKind(String name) {
|
||||
if (name.endsWith(JavaFileObject.Kind.CLASS.extension)){
|
||||
return JavaFileObject.Kind.CLASS;
|
||||
}
|
||||
if (name.endsWith(JavaFileObject.Kind.SOURCE.extension)) {
|
||||
return JavaFileObject.Kind.SOURCE;
|
||||
}
|
||||
if (name.endsWith(JavaFileObject.Kind.HTML.extension)) {
|
||||
return JavaFileObject.Kind.HTML;
|
||||
}
|
||||
return JavaFileObject.Kind.OTHER;
|
||||
}
|
||||
|
||||
private static String externalizeFileName(CharSequence cs, JavaFileObject.Kind kind) {
|
||||
return externalizeFileName(cs) + kind.extension;
|
||||
}
|
||||
|
||||
private static String externalizeFileName(CharSequence name) {
|
||||
return name.toString().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/24/11
|
||||
*/
|
||||
abstract class LineOutputWriter extends Writer {
|
||||
private final LineParser myLineParser = new LineParser();
|
||||
|
||||
public void write(int c) throws IOException {
|
||||
processData(new CharSequenceIterator(c));
|
||||
}
|
||||
|
||||
public void write(char[] cbuf) throws IOException {
|
||||
processData(new CharSequenceIterator(cbuf));
|
||||
}
|
||||
|
||||
public void write(String str) throws IOException {
|
||||
processData(new CharSequenceIterator(str));
|
||||
}
|
||||
|
||||
public void write(String str, int off, int len) throws IOException {
|
||||
processData(new CharSequenceIterator(str.subSequence(off, off + len)));
|
||||
}
|
||||
|
||||
public Writer append(CharSequence csq) throws IOException {
|
||||
processData(new CharSequenceIterator(csq));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Writer append(CharSequence csq, int start, int end) throws IOException {
|
||||
processData(new CharSequenceIterator(csq.subSequence(start, end)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Writer append(char c) throws IOException {
|
||||
processData(new CharSequenceIterator(c));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void write(char[] cbuf, int off, int len) throws IOException {
|
||||
processData(new CharSequenceIterator(cbuf, off, len));
|
||||
}
|
||||
|
||||
private void processData(CharIterator data) {
|
||||
while (myLineParser.parse(data)) {
|
||||
final String line = myLineParser.getResult();
|
||||
myLineParser.reset();
|
||||
lineAvailable(line);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
if (myLineParser.hasData()) {
|
||||
lineAvailable(myLineParser.getResult());
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myLineParser.reset();
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void lineAvailable(String line);
|
||||
|
||||
private static interface CharIterator {
|
||||
char nextChar();
|
||||
boolean hasData();
|
||||
}
|
||||
|
||||
private static class LineParser {
|
||||
private final StringBuilder myData = new StringBuilder();
|
||||
private boolean myFoundCR = false;
|
||||
|
||||
public boolean parse(CharIterator it) {
|
||||
while (it.hasData()) {
|
||||
final char ch = it.nextChar();
|
||||
if (ch == '\r') {
|
||||
myFoundCR = true;
|
||||
}
|
||||
else if (ch == '\n') {
|
||||
myFoundCR = false;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (myFoundCR) {
|
||||
myData.append('\r');
|
||||
myFoundCR = false;
|
||||
}
|
||||
myData.append(ch);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return myData.length() > 0;
|
||||
}
|
||||
|
||||
public String getResult() {
|
||||
return myData.toString();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
myFoundCR = false;
|
||||
myData.setLength(0);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CharSequenceIterator implements CharIterator {
|
||||
private final CharSequence myChars;
|
||||
private int myCursor = 0;
|
||||
|
||||
CharSequenceIterator(final int ch) {
|
||||
this((char)ch);
|
||||
}
|
||||
|
||||
CharSequenceIterator(final char ch) {
|
||||
this(new SingleCharSequence(ch));
|
||||
}
|
||||
|
||||
CharSequenceIterator(char[] chars) {
|
||||
this(chars, 0, chars.length);
|
||||
}
|
||||
|
||||
CharSequenceIterator(final char[] chars, final int offset, final int length) {
|
||||
this(new ArrayCharSequence(chars, offset, length));
|
||||
}
|
||||
|
||||
CharSequenceIterator(CharSequence sequence) {
|
||||
myChars = sequence;
|
||||
}
|
||||
|
||||
public char nextChar() {
|
||||
return myChars.charAt(myCursor++);
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return myCursor < myChars.length();
|
||||
}
|
||||
}
|
||||
|
||||
private static class SingleCharSequence implements CharSequence {
|
||||
private final char myCh;
|
||||
|
||||
public SingleCharSequence(char ch) {
|
||||
myCh = ch;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public char charAt(int index) {
|
||||
if (index != 0) {
|
||||
throw new IndexOutOfBoundsException("Index out of bounds: " + index);
|
||||
}
|
||||
return myCh;
|
||||
}
|
||||
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
throw new RuntimeException("Method subSequence not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ArrayCharSequence implements CharSequence {
|
||||
private final char[] myChars;
|
||||
private final int myOffset;
|
||||
private final int myLength;
|
||||
|
||||
public ArrayCharSequence(char[] chars, int offset, int length) {
|
||||
myChars = chars;
|
||||
myOffset = offset;
|
||||
myLength = length;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return myLength;
|
||||
}
|
||||
|
||||
public char charAt(int index) {
|
||||
return myChars[index];
|
||||
}
|
||||
|
||||
public CharSequence subSequence(int start, int end) {
|
||||
return new ArrayCharSequence(myChars, start, end - start);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new String(myChars, myOffset, myLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/24/11
|
||||
*/
|
||||
public class OutputFileObject extends SimpleJavaFileObject {
|
||||
|
||||
private final JavacFileManager.Context myContext;
|
||||
private final File myFile;
|
||||
private volatile Content myContent;
|
||||
|
||||
public OutputFileObject(JavacFileManager.Context context, File file, Kind kind) {
|
||||
super(file.toURI(), kind);
|
||||
myContext = context;
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteArrayOutputStream openOutputStream() {
|
||||
return new ByteArrayOutputStream() {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
super.close();
|
||||
}
|
||||
finally {
|
||||
myContent = new Content(buf, 0, size());
|
||||
myContext.consumeOutputFile(OutputFileObject.this);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openInputStream() throws IOException {
|
||||
final Content bytes = myContent;
|
||||
if (bytes == null) {
|
||||
throw new FileNotFoundException(toUri().getPath());
|
||||
}
|
||||
return new ByteArrayInputStream(bytes.getBuffer(), bytes.getOffset(), bytes.getLength());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
|
||||
final Content content = myContent;
|
||||
if (content == null) {
|
||||
throw null;
|
||||
}
|
||||
return new String(content.getBuffer(), content.getOffset(), content.getLength());
|
||||
}
|
||||
|
||||
public Content getContent() {
|
||||
return myContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toUri().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof JavaFileObject && toUri().equals(((JavaFileObject)obj).toUri());
|
||||
}
|
||||
|
||||
public static final class Content {
|
||||
private final byte[] myBuffer;
|
||||
private final int myOffset;
|
||||
private final int myLength;
|
||||
|
||||
private Content(byte[] buf, int off, int len) {
|
||||
myBuffer = buf;
|
||||
myOffset = off;
|
||||
myLength = len;
|
||||
}
|
||||
|
||||
public byte[] getBuffer() {
|
||||
return myBuffer;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return myOffset;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return myLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/24/11
|
||||
*/
|
||||
public class PlainMessageDiagnostic implements Diagnostic<JavaFileObject>{
|
||||
|
||||
private final Kind myKind;
|
||||
private final String myMessage;
|
||||
|
||||
public PlainMessageDiagnostic(Kind kind, String message) {
|
||||
myKind = kind;
|
||||
myMessage = message;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myKind;
|
||||
}
|
||||
|
||||
public JavaFileObject getSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public long getPosition() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getStartPosition() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getEndPosition() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getLineNumber() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getColumnNumber() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getMessage(Locale locale) {
|
||||
return myMessage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.jetbrains.jps.incremental.impl;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 9/24/11
|
||||
*/
|
||||
public class SequentialTaskExecutor {
|
||||
|
||||
private final ExecutorService myExecutor;
|
||||
private final Queue<Runnable> myTaskQueue = new LinkedBlockingQueue<Runnable>();
|
||||
private final AtomicBoolean myInProgress = new AtomicBoolean(false);
|
||||
private final Runnable USER_TASK_RUNNER = new Runnable() {
|
||||
public void run() {
|
||||
final Runnable task = myTaskQueue.poll();
|
||||
try {
|
||||
if (task != null) {
|
||||
task.run();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myInProgress.set(false);
|
||||
if (!myTaskQueue.isEmpty()) {
|
||||
processQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public SequentialTaskExecutor(ExecutorService executor) {
|
||||
myExecutor = executor;
|
||||
}
|
||||
|
||||
public void submit(Runnable task) {
|
||||
if (myTaskQueue.offer(task)) {
|
||||
processQueue();
|
||||
}
|
||||
else {
|
||||
throw new RuntimeException("Failed to queue task: " + task);
|
||||
}
|
||||
}
|
||||
|
||||
private void processQueue() {
|
||||
if (!myInProgress.getAndSet(true)) {
|
||||
myExecutor.submit(USER_TASK_RUNNER);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user