1. jps incremental builders, initial

2. set one project JDK and have modules use it
This commit is contained in:
Eugene Zhuravlev
2011-09-26 17:53:46 +02:00
parent 28a9e5e9c5
commit 7d4f3f5a96
26 changed files with 1145 additions and 9 deletions
+1 -1
View File
@@ -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">
+1 -1
View File
@@ -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
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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);
}
}
}