From 306c9f6bae8650db3d1b2b0dc042caf0278844fd Mon Sep 17 00:00:00 2001 From: nik Date: Wed, 15 Aug 2012 10:10:01 +0400 Subject: [PATCH] running new JPS builder from gant scripts --- .../projectRoots/impl/JavaSdkImpl.java | 82 +-------- .../openapi/projectRoots/JavaSdk.java | 2 +- ...Pool.java => SharedBuilderThreadPool.java} | 28 +-- .../org/jetbrains/jps/cmdline/BuildMain.java | 6 +- .../jetbrains/jps/cmdline/BuildRunner.java | 85 +-------- .../jetbrains/jps/cmdline/BuildSession.java | 6 +- .../jetbrains/jps/cmdline/JpsModelLoader.java | 13 ++ .../jps/cmdline/JpsModelLoaderImpl.java | 96 +++++++++++ .../jps/incremental/IncProjectBuilder.java | 7 +- .../jps/incremental/JavaBuilderService.java | 4 +- .../org/jetbrains/jps/incremental/Utils.java | 2 +- .../org/jetbrains/jps/javac/JavacServer.java | 9 +- .../jps/javac/JavacServerClient.java | 4 +- .../jps/model/java/JdkVersionDetector.java | 30 ++++ .../model/java/JpsJavaExtensionService.java | 7 + .../jps/model/library/JpsLibrary.java | 2 + .../jps/service/SharedThreadPool.java | 15 ++ ...etbrains.jps.model.java.JdkVersionDetector | 1 + ...org.jetbrains.jps.service.SharedThreadPool | 1 + .../src/org/jetbrains/jps/JpsPathUtil.java | 8 + .../jps/model/java/impl/JavaSdkUtil.java | 83 +++++++++ .../java/impl/JdkVersionDetectorImpl.java | 163 ++++++++++++++++++ .../impl/JpsJavaExtensionServiceImpl.java | 19 ++ .../model/library/impl/JpsLibraryImpl.java | 5 + .../service/impl/SharedThreadPoolImpl.java | 34 ++++ .../model/serialization/JpsProjectLoader.java | 2 +- .../jps-standalone-builder.iml | 1 + .../jps/gant/JpsGantProjectBuilder.java | 72 ++++++++ .../org/jetbrains/jps/gant/JpsGantTool.groovy | 103 +++++++++++ .../org/jetbrains/jps/gant/LayoutInfo.java | 15 ++ .../projectRoots/SimpleJavaSdkType.java | 2 +- .../projectRoots/impl/SdkVersionUtil.java | 137 ++------------- .../projectModel-api/projectModel-api.iml | 1 + .../projectModel-impl/projectModel-impl.iml | 2 +- 34 files changed, 716 insertions(+), 331 deletions(-) rename jps/jps-builders/src/org/jetbrains/jps/api/{SharedThreadPool.java => SharedBuilderThreadPool.java} (63%) create mode 100644 jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoader.java create mode 100644 jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoaderImpl.java create mode 100644 jps/model-api/src/org/jetbrains/jps/model/java/JdkVersionDetector.java create mode 100644 jps/model-api/src/org/jetbrains/jps/service/SharedThreadPool.java create mode 100644 jps/model-impl/src/META-INF/services/org.jetbrains.jps.model.java.JdkVersionDetector create mode 100644 jps/model-impl/src/META-INF/services/org.jetbrains.jps.service.SharedThreadPool create mode 100644 jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaSdkUtil.java create mode 100644 jps/model-impl/src/org/jetbrains/jps/model/java/impl/JdkVersionDetectorImpl.java create mode 100644 jps/model-impl/src/org/jetbrains/jps/service/impl/SharedThreadPoolImpl.java create mode 100644 jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java create mode 100644 jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantTool.groovy create mode 100644 jps/standalone-builder/src/org/jetbrains/jps/gant/LayoutInfo.java diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java index 5e8b6dbf65e9..c4f18de6a09c 100644 --- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java +++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaSdkImpl.java @@ -24,18 +24,16 @@ import com.intellij.openapi.roots.AnnotationOrderRootType; import com.intellij.openapi.roots.JavadocOrderRootType; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.*; import com.intellij.util.containers.HashMap; import org.jdom.Element; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.impl.JavaSdkUtil; import javax.swing.*; import java.io.File; -import java.io.FileFilter; -import java.io.IOException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -453,88 +451,16 @@ public class JavaSdkImpl extends JavaSdk { } private static VirtualFile[] findClasses(File file, boolean isJre) { - FileFilter jarFileFilter = new FileFilter() { - @Override - @SuppressWarnings({"HardCodedStringLiteral"}) - public boolean accept(File f) { - return !f.isDirectory() && f.getName().endsWith(".jar"); - } - }; - - File[] jarDirs; - if (SystemInfo.isMac && !file.getName().startsWith("mockJDK")) { - final File openJdkRtJar = new File(new File(new File(file, "jre"), "lib"), "rt.jar"); - if (openJdkRtJar.exists() && !openJdkRtJar.isDirectory()) { - // OpenJDK - File libFile = new File(file, "lib"); - @NonNls File classesFile = openJdkRtJar.getParentFile(); - @NonNls File libExtFile = new File(openJdkRtJar.getParentFile(), "ext"); - @NonNls File libEndorsedFile = new File(libFile, "endorsed"); - jarDirs = new File[]{libEndorsedFile, libFile, classesFile, libExtFile}; - } - else { - File libFile = new File(file, "lib"); - @NonNls File classesFile = new File(file, "../Classes"); - @NonNls File libExtFile = new File(libFile, "ext"); - @NonNls File libEndorsedFile = new File(libFile, "endorsed"); - jarDirs = new File[]{libEndorsedFile, libFile, classesFile, libExtFile}; - } - } - else { - @NonNls final String jre = "jre"; - File jreLibFile = isJre ? new File(file, "lib") : new File(new File(file, jre), "lib"); - @NonNls File jreLibExtFile = new File(jreLibFile, "ext"); - @NonNls File jreLibEndorsedFile = new File(jreLibFile, "endorsed"); - jarDirs = new File[]{jreLibEndorsedFile, jreLibFile, jreLibExtFile}; - } - - Set filter = new LinkedHashSet(); - List children = new ArrayList(); - for (File jarDir : jarDirs) { - if (jarDir != null && jarDir.isDirectory()) { - File[] jarFiles = jarDir.listFiles(jarFileFilter); - for (File jarFile : jarFiles) { - final String jarFileName = jarFile.getName(); - if (jarFileName.equals("alt-rt.jar") || jarFileName.equals("alt-string.jar")) continue; - try { - // File.getCanonicalFile() allows us to filter out duplicate (symbolically linked) jar files, - // commonly found in osx JDK distributions - if (filter.add(jarFile.getCanonicalFile())) children.add(jarFile); - } - catch (IOException e) { - // Symbolic links may fail to resolve. Just skip those jars as we won't be able to find virtual file in this case anyway. - } - } - } - } + List rootFiles = JavaSdkUtil.getJdkClassesRoots(file, isJre); ArrayList result = new ArrayList(); - for (File child : children) { - String url = JarFileSystem.PROTOCOL_PREFIX + FileUtil.toSystemIndependentName(child.getAbsolutePath()) + JarFileSystem.JAR_SEPARATOR; + for (File child : rootFiles) { + String url = VfsUtil.getUrlForLibraryRoot(child); VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url); if (vFile != null) { result.add(vFile); } } - - File classesZip = new File(new File(file, "lib"), "classes.zip"); - if (classesZip.isFile()) { - String url = JarFileSystem.PROTOCOL_PREFIX + FileUtil.toSystemIndependentName(classesZip.getAbsolutePath()) + JarFileSystem.JAR_SEPARATOR; - VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url); - if (vFile != null) { - result.add(vFile); - } - } - - File classesDir = new File(file, "classes"); - if (result.isEmpty() && classesDir.isDirectory()) { - String url = LocalFileSystem.PROTOCOL_PREFIX + FileUtil.toSystemIndependentName(classesDir.getAbsolutePath()); - VirtualFile vFile = VirtualFileManager.getInstance().findFileByUrl(url); - if (vFile != null) { - result.add(vFile); - } - } - return VfsUtil.toVirtualFileArray(result); } diff --git a/java/openapi/src/com/intellij/openapi/projectRoots/JavaSdk.java b/java/openapi/src/com/intellij/openapi/projectRoots/JavaSdk.java index 5e7d644cc79d..c0fe5fc92dc2 100644 --- a/java/openapi/src/com/intellij/openapi/projectRoots/JavaSdk.java +++ b/java/openapi/src/com/intellij/openapi/projectRoots/JavaSdk.java @@ -62,6 +62,6 @@ public abstract class JavaSdk extends SdkType implements JavaSdkType, Applicatio @Nullable public static String getJdkVersion(final String sdkHome) { - return SdkVersionUtil.readVersionFromProcessOutput(sdkHome, new String[] {sdkHome + File.separator + "bin" + File.separator + "java", "-version"}, "version"); + return SdkVersionUtil.detectJdkVersion(sdkHome); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/SharedThreadPool.java b/jps/jps-builders/src/org/jetbrains/jps/api/SharedBuilderThreadPool.java similarity index 63% rename from jps/jps-builders/src/org/jetbrains/jps/api/SharedThreadPool.java rename to jps/jps-builders/src/org/jetbrains/jps/api/SharedBuilderThreadPool.java index 659de6b354d2..c7d8c5541429 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/SharedThreadPool.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/SharedBuilderThreadPool.java @@ -1,6 +1,5 @@ package org.jetbrains.jps.api; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -9,9 +8,7 @@ import java.util.concurrent.Future; * @author Eugene Zhuravlev * Date: 3/29/12 */ -public class SharedThreadPool implements Executor { - private static final ExecutorService ourService = Executors.newCachedThreadPool(); - +public class SharedBuilderThreadPool { private static final int MAX_BUILDER_THREADS; static { int maxThreads = 4; @@ -24,15 +21,10 @@ public class SharedThreadPool implements Executor { } private static final ExecutorService ourBuilderPool = Executors.newFixedThreadPool(Math.min(MAX_BUILDER_THREADS, Math.max(2, Runtime.getRuntime().availableProcessors()))); - public static final SharedThreadPool INSTANCE = new SharedThreadPool(); + public static final SharedBuilderThreadPool INSTANCE = new SharedBuilderThreadPool(); - private SharedThreadPool() { - } - - /** @noinspection MethodMayBeStatic*/ - public Future submit(final Runnable task) { - return _submit(task, ourService); + private SharedBuilderThreadPool() { } /** @noinspection MethodMayBeStatic*/ @@ -52,18 +44,4 @@ public class SharedThreadPool implements Executor { } }); } - - public void execute(final Runnable task) { - ourService.execute(new Runnable() { - public void run() { - try { - task.run(); - } - finally { - Thread.interrupted(); // reset interrupted status - } - } - }); - } - } diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java index 2eca2156c382..d9b65ade351a 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java @@ -15,8 +15,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.api.CmdlineProtoUtil; import org.jetbrains.jps.api.CmdlineRemoteProto; -import org.jetbrains.jps.api.SharedThreadPool; import org.jetbrains.jps.incremental.Utils; +import org.jetbrains.jps.service.SharedThreadPool; import java.io.File; import java.net.InetSocketAddress; @@ -41,7 +41,7 @@ public class BuildMain { initLoggers(); - ourChannelFactory = new NioClientSocketChannelFactory(SharedThreadPool.INSTANCE, SharedThreadPool.INSTANCE, 1); + ourChannelFactory = new NioClientSocketChannelFactory(SharedThreadPool.getInstance(), SharedThreadPool.getInstance(), 1); final ClientBootstrap bootstrap = new ClientBootstrap(ourChannelFactory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { @@ -99,7 +99,7 @@ public class BuildMain { final CmdlineRemoteProto.Message.ControllerMessage.FSEvent delta = controllerMessage.hasFsEvent()? controllerMessage.getFsEvent() : null; final BuildSession session = new BuildSession(mySessionId, channel, controllerMessage.getParamsMessage(), delta); mySession = session; - SharedThreadPool.INSTANCE.submit(new Runnable() { + SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() { public void run() { try { session.run(); diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java index 5c5cd2154c21..ca88bbdc6617 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildRunner.java @@ -3,15 +3,12 @@ package org.jetbrains.jps.cmdline; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.util.ParameterizedRunnable; import org.jetbrains.annotations.Nullable; import org.jetbrains.ether.dependencyView.Callbacks; import org.jetbrains.jps.Project; import org.jetbrains.jps.api.BuildType; import org.jetbrains.jps.api.CanceledStatus; import org.jetbrains.jps.api.GlobalOptions; -import org.jetbrains.jps.idea.IdeaProjectLoader; -import org.jetbrains.jps.idea.SystemOutErrorReporter; import org.jetbrains.jps.incremental.*; import org.jetbrains.jps.incremental.artifacts.JpsBuilderArtifactService; import org.jetbrains.jps.incremental.fs.BuildFSState; @@ -21,12 +18,9 @@ import org.jetbrains.jps.incremental.messages.CompilerMessage; import org.jetbrains.jps.incremental.storage.BuildDataManager; import org.jetbrains.jps.incremental.storage.ProjectTimestamps; import org.jetbrains.jps.incremental.storage.Timestamps; -import org.jetbrains.jps.model.JpsElementFactory; import org.jetbrains.jps.model.JpsModel; import org.jetbrains.jps.model.artifact.JpsArtifact; import org.jetbrains.jps.model.module.JpsModule; -import org.jetbrains.jps.model.serialization.JpsGlobalLoader; -import org.jetbrains.jps.model.serialization.JpsProjectLoader; import java.io.File; import java.io.IOException; @@ -36,34 +30,20 @@ import java.util.*; * @author nik */ public class BuildRunner { - public static final String IDEA_PROJECT_DIRNAME = ".idea"; private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.BuildRunner"); - private final String myProjectPath; - // globals - private final Map myPathVars; - private final String myGlobalEncoding; - private final String myIgnorePatterns; - // build params + private final JpsModelLoader myModelLoader; private final Set myModules; private BuildType myBuildType; private final List myArtifacts; private final List myFilePaths; private final Map myBuilderParams; - private final String myGlobalOptionsPath; private boolean myForceCleanCaches; - private ParameterizedRunnable myModelInitializer; - public BuildRunner(String projectPath, String globalOptionsPath, Map pathVars, - String globalEncoding, - String ignorePatterns, + public BuildRunner(JpsModelLoader modelLoader, Set modules, BuildType buildType, List artifacts, List filePaths, Map builderParams) { - myProjectPath = projectPath; - myGlobalOptionsPath = globalOptionsPath; - myPathVars = pathVars; - myGlobalEncoding = globalEncoding; - myIgnorePatterns = ignorePatterns; + myModelLoader = modelLoader; myModules = modules; myBuildType = buildType; myArtifacts = artifacts; @@ -71,10 +51,6 @@ public class BuildRunner { myBuilderParams = builderParams; } - public void setModelInitializer(ParameterizedRunnable modelInitializer) { - myModelInitializer = modelInitializer; - } - public ProjectDescriptor load(MessageHandler msgHandler, File dataStorageRoot, BuildFSState fsState) throws IOException { if (!dataStorageRoot.exists()) { // invoked the very first time for this project. Force full rebuild @@ -109,58 +85,11 @@ public class BuildRunner { msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.INFO, "Project rebuild forced: " + e.getMessage())); } - final JpsModel jpsModel = loadJpsModel(); - final Project project = loadProject(); + final JpsModel jpsModel = myModelLoader.loadModel(); + final Project project = myModelLoader.loadOldProject(); return new ProjectDescriptor(project, jpsModel, fsState, projectTimestamps, dataManager, BuildLoggingManager.DEFAULT); } - private JpsModel loadJpsModel() { - final long start = System.currentTimeMillis(); - try { - final JpsModel model = JpsElementFactory.getInstance().createModel(); - try { - if (myGlobalOptionsPath != null) { - JpsGlobalLoader.loadGlobalSettings(model.getGlobal(), myPathVars, myGlobalOptionsPath); - } - JpsProjectLoader.loadProject(model.getProject(), myPathVars, myProjectPath); - if (myModelInitializer != null) { - myModelInitializer.run(model); - } - LOG.info("New JPS model: " + model.getProject().getModules().size() + " modules, " + model.getProject().getLibraryCollection().getLibraries().size() + " libraries"); - } - catch (IOException e) { - LOG.info(e); - } - return model; - } - finally { - final long loadTime = System.currentTimeMillis() - start; - LOG.info("New JPS model: project " + myProjectPath + " loaded in " + loadTime + " ms"); - } - } - - private Project loadProject() { - final long start = System.currentTimeMillis(); - try { - final Project project = new Project(); - - final File projectFile = new File(myProjectPath); - - final String loadPath = isDirectoryBased(projectFile) ? new File(projectFile, IDEA_PROJECT_DIRNAME).getPath() : myProjectPath; - IdeaProjectLoader.loadFromPath(project, loadPath, myPathVars, null, new SystemOutErrorReporter(false)); - final String globalEncoding = myGlobalEncoding; - if (!StringUtil.isEmpty(globalEncoding) && project.getProjectCharset() == null) { - project.setProjectCharset(globalEncoding); - } - project.getIgnoredFilePatterns().loadFromString(myIgnorePatterns); - return project; - } - finally { - final long loadTime = System.currentTimeMillis() - start; - LOG.info("Project " + myProjectPath + " loaded in " + loadTime + " ms"); - } - } - public void runBuild(ProjectDescriptor pd, CanceledStatus cs, @Nullable Callbacks.ConstantAffectionResolver constantSearch, MessageHandler msgHandler) throws Exception { for (int attempt = 0; attempt < 2; attempt++) { @@ -209,10 +138,6 @@ public class BuildRunner { return myBuildType; } - private static boolean isDirectoryBased(File projectFile) { - return !(projectFile.isFile() && projectFile.getName().endsWith(".ipr")); - } - private static CompileScope createCompilationScope(BuildType buildType, ProjectDescriptor pd, Set modules, diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java index 3274384d6cce..910bd4937203 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildSession.java @@ -19,6 +19,7 @@ import org.jetbrains.jps.incremental.fs.BuildFSState; import org.jetbrains.jps.incremental.fs.RootDescriptor; import org.jetbrains.jps.incremental.messages.*; import org.jetbrains.jps.incremental.storage.Timestamps; +import org.jetbrains.jps.service.SharedThreadPool; import java.io.*; import java.util.*; @@ -77,7 +78,8 @@ final class BuildSession implements Runnable, CanceledStatus { builderParams.put(pair.getKey(), pair.getValue()); } myInitialFSDelta = delta; - myBuildRunner = new BuildRunner(myProjectPath, globalOptionsPath, pathVars, globalEncoding, ignorePatterns, modules, myBuildType, artifacts, filePaths, builderParams); + JpsModelLoaderImpl loader = new JpsModelLoaderImpl(myProjectPath, globalOptionsPath, pathVars, globalEncoding, ignorePatterns, null); + myBuildRunner = new BuildRunner(loader, modules, myBuildType, artifacts, filePaths, builderParams); } public void run() { @@ -428,7 +430,7 @@ final class BuildSession implements Runnable, CanceledStatus { private final AtomicBoolean myProcessingEnabled = new AtomicBoolean(false); EventsProcessor() { - super(SharedThreadPool.INSTANCE); + super(SharedThreadPool.getInstance()); } public void startProcessing() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoader.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoader.java new file mode 100644 index 000000000000..fed3536d5051 --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoader.java @@ -0,0 +1,13 @@ +package org.jetbrains.jps.cmdline; + +import org.jetbrains.jps.Project; +import org.jetbrains.jps.model.JpsModel; + +/** + * @author nik + */ +public interface JpsModelLoader { + JpsModel loadModel(); + + Project loadOldProject(); +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoaderImpl.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoaderImpl.java new file mode 100644 index 000000000000..a9537185898d --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/JpsModelLoaderImpl.java @@ -0,0 +1,96 @@ +package org.jetbrains.jps.cmdline; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.ParameterizedRunnable; +import org.jetbrains.jps.Project; +import org.jetbrains.jps.idea.IdeaProjectLoader; +import org.jetbrains.jps.idea.SystemOutErrorReporter; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.jps.model.serialization.JpsGlobalLoader; +import org.jetbrains.jps.model.serialization.JpsProjectLoader; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +/** + * @author nik + */ +public class JpsModelLoaderImpl implements JpsModelLoader { + public static final String IDEA_PROJECT_DIRNAME = ".idea"; + private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.cmdline.JpsModelLoaderImpl"); + private final String myProjectPath; + private final String myGlobalOptionsPath; + private final Map myPathVars; + private final String myGlobalEncoding; + private final String myIgnorePatterns; + private final ParameterizedRunnable myModelInitializer; + + public JpsModelLoaderImpl(String projectPath, + String globalOptionsPath, + Map pathVars, + String globalEncoding, + String ignorePatterns, ParameterizedRunnable initializer) { + myProjectPath = projectPath; + myGlobalOptionsPath = globalOptionsPath; + myPathVars = pathVars; + myGlobalEncoding = globalEncoding; + myIgnorePatterns = ignorePatterns; + myModelInitializer = initializer; + } + + @Override + public JpsModel loadModel() { + final long start = System.currentTimeMillis(); + try { + final JpsModel model = JpsElementFactory.getInstance().createModel(); + try { + if (myGlobalOptionsPath != null) { + JpsGlobalLoader.loadGlobalSettings(model.getGlobal(), myPathVars, myGlobalOptionsPath); + } + JpsProjectLoader.loadProject(model.getProject(), myPathVars, myProjectPath); + if (myModelInitializer != null) { + myModelInitializer.run(model); + } + LOG.info("New JPS model: " + model.getProject().getModules().size() + " modules, " + model.getProject().getLibraryCollection().getLibraries().size() + " libraries"); + } + catch (IOException e) { + LOG.info(e); + } + return model; + } + finally { + final long loadTime = System.currentTimeMillis() - start; + LOG.info("New JPS model: project " + myProjectPath + " loaded in " + loadTime + " ms"); + } + } + + @Override + public Project loadOldProject() { + final long start = System.currentTimeMillis(); + try { + final Project project = new Project(); + + final File projectFile = new File(myProjectPath); + + final String loadPath = isDirectoryBased(projectFile) ? new File(projectFile, IDEA_PROJECT_DIRNAME).getPath() : myProjectPath; + IdeaProjectLoader.loadFromPath(project, loadPath, myPathVars, null, new SystemOutErrorReporter(false)); + final String globalEncoding = myGlobalEncoding; + if (!StringUtil.isEmpty(globalEncoding) && project.getProjectCharset() == null) { + project.setProjectCharset(globalEncoding); + } + project.getIgnoredFilePatterns().loadFromString(myIgnorePatterns); + return project; + } + finally { + final long loadTime = System.currentTimeMillis() - start; + LOG.info("Project " + myProjectPath + " loaded in " + loadTime + " ms"); + } + } + + private static boolean isDirectoryBased(File projectFile) { + return !(projectFile.isFile() && projectFile.getName().endsWith(".ipr")); + } +} diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 5899be97d1b2..0f1fecc4ad44 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -14,7 +14,7 @@ import org.jetbrains.jps.*; import org.jetbrains.jps.api.CanceledStatus; import org.jetbrains.jps.api.GlobalOptions; import org.jetbrains.jps.api.RequestFuture; -import org.jetbrains.jps.api.SharedThreadPool; +import org.jetbrains.jps.api.SharedBuilderThreadPool; import org.jetbrains.jps.cmdline.ProjectDescriptor; import org.jetbrains.jps.incremental.fs.BuildFSState; import org.jetbrains.jps.incremental.fs.RootDescriptor; @@ -26,6 +26,7 @@ import org.jetbrains.jps.incremental.storage.*; import org.jetbrains.jps.model.java.JpsJavaClasspathKind; import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.service.SharedThreadPool; import java.io.BufferedWriter; import java.io.File; @@ -439,7 +440,7 @@ public class IncProjectBuilder { for (final ModuleChunk chunk : groupChunks) { final CompileContext chunkLocalContext = createContextWrapper(context); - SharedThreadPool.INSTANCE.submitBuildTask(new Runnable() { + SharedBuilderThreadPool.INSTANCE.submitBuildTask(new Runnable() { @Override public void run() { try { @@ -584,7 +585,7 @@ public class IncProjectBuilder { if (doneSomething && GENERATE_CLASSPATH_INDEX) { final boolean forTests = context.isCompilingTests(); - final Future future = SharedThreadPool.INSTANCE.submit(new Runnable() { + final Future future = SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() { @Override public void run() { createClasspathIndex(chunk, forTests); diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java index 5c47fb4cdfd6..57cdbaab216f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/JavaBuilderService.java @@ -1,9 +1,9 @@ package org.jetbrains.jps.incremental; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jps.api.SharedThreadPool; import org.jetbrains.jps.incremental.java.JavaBuilder; import org.jetbrains.jps.incremental.resources.ResourcesBuilder; +import org.jetbrains.jps.service.SharedThreadPool; import java.util.Arrays; import java.util.List; @@ -15,6 +15,6 @@ public class JavaBuilderService extends BuilderService { @NotNull @Override public List createModuleLevelBuilders() { - return Arrays.asList(new JavaBuilder(SharedThreadPool.INSTANCE), new ResourcesBuilder()); + return Arrays.asList(new JavaBuilder(SharedThreadPool.getInstance()), new ResourcesBuilder()); } } diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java index 87259ee4d508..6f08f01bf27f 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/Utils.java @@ -21,7 +21,7 @@ public class Utils { public static final Key>> REMOVED_SOURCES_KEY = Key.create("_removed_sources_"); public static final Key PROCEED_ON_ERROR_KEY = Key.create("_proceed_on_error_"); public static final Key ERRORS_DETECTED_KEY = Key.create("_errors_detected_"); - private static volatile File ourSystemRoot = new File(System.getProperty("user.home", ".idea-build")); + private static volatile File ourSystemRoot = new File(System.getProperty("user.home"), ".idea-build"); public static final boolean IS_TEST_MODE = Boolean.parseBoolean(System.getProperty("test.mode", "false")); private Utils() { diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java index 42ccd4c525e9..5fcb30bf786c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java @@ -12,10 +12,9 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.api.CanceledStatus; -import org.jetbrains.jps.api.SharedThreadPool; +import org.jetbrains.jps.service.SharedThreadPool; -import javax.tools.Diagnostic; -import javax.tools.JavaFileObject; +import javax.tools.*; import java.io.File; import java.net.InetSocketAddress; import java.util.*; @@ -34,7 +33,7 @@ public class JavacServer { private final ChannelPipelineFactory myPipelineFactory; public JavacServer() { - myChannelFactory = new NioServerSocketChannelFactory(SharedThreadPool.INSTANCE, SharedThreadPool.INSTANCE, 1); + myChannelFactory = new NioServerSocketChannelFactory(SharedThreadPool.getInstance(), SharedThreadPool.getInstance(), 1); final ChannelRegistrar channelRegistrar = new ChannelRegistrar(); final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler(); myPipelineFactory = new ChannelPipelineFactory() { @@ -196,7 +195,7 @@ public class JavacServer { final CancelHandler cancelHandler = new CancelHandler(); myCancelHandlers.add(cancelHandler); - SharedThreadPool.INSTANCE.submit(new Runnable() { + SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() { public void run() { try { final JavacRemoteProto.Message exitMsg = diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java index c32e27d5fe5e..84ba369f20cf 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java +++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java @@ -3,9 +3,9 @@ package org.jetbrains.jps.javac; import org.jboss.netty.channel.MessageEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.jps.api.RequestFuture; -import org.jetbrains.jps.api.SharedThreadPool; import org.jetbrains.jps.client.SimpleProtobufClient; import org.jetbrains.jps.client.UUIDGetter; +import org.jetbrains.jps.service.SharedThreadPool; import java.io.File; import java.util.*; @@ -17,7 +17,7 @@ import java.util.*; public class JavacServerClient extends SimpleProtobufClient{ public JavacServerClient() { - super(JavacRemoteProto.Message.getDefaultInstance(), SharedThreadPool.INSTANCE, new UUIDGetter() { + super(JavacRemoteProto.Message.getDefaultInstance(), SharedThreadPool.getInstance(), new UUIDGetter() { @NotNull public UUID getSessionUUID(@NotNull MessageEvent e) { final JavacRemoteProto.Message message = (JavacRemoteProto.Message)e.getMessage(); diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JdkVersionDetector.java b/jps/model-api/src/org/jetbrains/jps/model/java/JdkVersionDetector.java new file mode 100644 index 000000000000..2df25864fa02 --- /dev/null +++ b/jps/model-api/src/org/jetbrains/jps/model/java/JdkVersionDetector.java @@ -0,0 +1,30 @@ +package org.jetbrains.jps.model.java; + +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.service.JpsServiceManager; + +import java.util.concurrent.Future; + +/** + * @author nik + */ +public abstract class JdkVersionDetector { + public static JdkVersionDetector getInstance() { + return JpsServiceManager.getInstance().getService(JdkVersionDetector.class); + } + + @Nullable + public abstract String detectJdkVersion(String homePath); + + @Nullable + public abstract String detectJdkVersion(String homePath, ActionRunner actionRunner); + + @Nullable + public abstract String readVersionFromProcessOutput(String homePath, String[] command, String versionLineMarker, + ActionRunner actionRunner); + + //todo[nik] replace with a service with difference implementation for IDEA and for JPS process (need to exclude jps-builders module from IDEA classpath) + public interface ActionRunner { + Future run(Runnable runnable); + } +} diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaExtensionService.java b/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaExtensionService.java index 6609a760c49e..b3a500b1253b 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaExtensionService.java +++ b/jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaExtensionService.java @@ -2,7 +2,11 @@ package org.jetbrains.jps.model.java; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsDummyElement; +import org.jetbrains.jps.model.JpsGlobal; import org.jetbrains.jps.model.JpsProject; +import org.jetbrains.jps.model.library.JpsTypedLibrary; +import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.module.JpsDependencyElement; import org.jetbrains.jps.model.module.JpsModule; import org.jetbrains.jps.model.module.JpsModuleReference; @@ -66,4 +70,7 @@ public abstract class JpsJavaExtensionService { @Nullable public abstract String getSourcePrefix(JpsModule module, String rootUrl); + + public abstract JpsTypedLibrary> addJavaSdk(@NotNull JpsGlobal global, @NotNull String name, + @NotNull String homePath); } diff --git a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java index ace2c9985ff2..eea17445f7cb 100644 --- a/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java +++ b/jps/model-api/src/org/jetbrains/jps/model/library/JpsLibrary.java @@ -18,6 +18,8 @@ public interface JpsLibrary extends JpsNamedElement, JpsReferenceableElement executeOnPooledThread(Runnable action); +} diff --git a/jps/model-impl/src/META-INF/services/org.jetbrains.jps.model.java.JdkVersionDetector b/jps/model-impl/src/META-INF/services/org.jetbrains.jps.model.java.JdkVersionDetector new file mode 100644 index 000000000000..86310023aac4 --- /dev/null +++ b/jps/model-impl/src/META-INF/services/org.jetbrains.jps.model.java.JdkVersionDetector @@ -0,0 +1 @@ +org.jetbrains.jps.model.java.impl.JdkVersionDetectorImpl \ No newline at end of file diff --git a/jps/model-impl/src/META-INF/services/org.jetbrains.jps.service.SharedThreadPool b/jps/model-impl/src/META-INF/services/org.jetbrains.jps.service.SharedThreadPool new file mode 100644 index 000000000000..ee4528a7664f --- /dev/null +++ b/jps/model-impl/src/META-INF/services/org.jetbrains.jps.service.SharedThreadPool @@ -0,0 +1 @@ +org.jetbrains.jps.service.impl.SharedThreadPoolImpl \ No newline at end of file diff --git a/jps/model-impl/src/org/jetbrains/jps/JpsPathUtil.java b/jps/model-impl/src/org/jetbrains/jps/JpsPathUtil.java index 39b45108f72d..93d6926bdea5 100644 --- a/jps/model-impl/src/org/jetbrains/jps/JpsPathUtil.java +++ b/jps/model-impl/src/org/jetbrains/jps/JpsPathUtil.java @@ -80,4 +80,12 @@ public class JpsPathUtil { public static String pathToUrl(String path) { return "file://" + path; } + + public static String getLibraryRootUrl(File file) { + String path = FileUtilRt.toSystemIndependentName(file.getAbsolutePath()); + if (file.isDirectory()) { + return "file://" + path; + } + return "jar://" + path + "!/"; + } } diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaSdkUtil.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaSdkUtil.java new file mode 100644 index 000000000000..58fe0ede67ad --- /dev/null +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JavaSdkUtil.java @@ -0,0 +1,83 @@ +package org.jetbrains.jps.model.java.impl; + +import com.intellij.openapi.util.SystemInfo; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * @author nik + */ +public class JavaSdkUtil { + public static List getJdkClassesRoots(File file, boolean isJre) { + FileFilter jarFileFilter = new FileFilter() { + @Override + @SuppressWarnings({"HardCodedStringLiteral"}) + public boolean accept(File f) { + return !f.isDirectory() && f.getName().endsWith(".jar"); + } + }; + + File[] jarDirs; + if (SystemInfo.isMac && !file.getName().startsWith("mockJDK")) { + final File openJdkRtJar = new File(new File(new File(file, "jre"), "lib"), "rt.jar"); + if (openJdkRtJar.exists() && !openJdkRtJar.isDirectory()) { + // OpenJDK + File libFile = new File(file, "lib"); + File classesFile = openJdkRtJar.getParentFile(); + File libExtFile = new File(openJdkRtJar.getParentFile(), "ext"); + File libEndorsedFile = new File(libFile, "endorsed"); + jarDirs = new File[]{libEndorsedFile, libFile, classesFile, libExtFile}; + } + else { + File libFile = new File(file, "lib"); + File classesFile = new File(file, "../Classes"); + File libExtFile = new File(libFile, "ext"); + File libEndorsedFile = new File(libFile, "endorsed"); + jarDirs = new File[]{libEndorsedFile, libFile, classesFile, libExtFile}; + } + } + else { + File jreLibFile = isJre ? new File(file, "lib") : new File(new File(file, "jre"), "lib"); + File jreLibExtFile = new File(jreLibFile, "ext"); + File jreLibEndorsedFile = new File(jreLibFile, "endorsed"); + jarDirs = new File[]{jreLibEndorsedFile, jreLibFile, jreLibExtFile}; + } + + Set filter = new LinkedHashSet(); + List rootFiles = new ArrayList(); + for (File jarDir : jarDirs) { + if (jarDir != null && jarDir.isDirectory()) { + File[] jarFiles = jarDir.listFiles(jarFileFilter); + for (File jarFile : jarFiles) { + final String jarFileName = jarFile.getName(); + if (jarFileName.equals("alt-rt.jar") || jarFileName.equals("alt-string.jar")) continue; + try { + // File.getCanonicalFile() allows us to filter out duplicate (symbolically linked) jar files, + // commonly found in osx JDK distributions + if (filter.add(jarFile.getCanonicalFile())) rootFiles.add(jarFile); + } + catch (IOException e) { + // Symbolic links may fail to resolve. Just skip those jars as we won't be able to find virtual file in this case anyway. + } + } + } + } + + File classesZip = new File(new File(file, "lib"), "classes.zip"); + if (classesZip.isFile()) { + rootFiles.add(classesZip); + } + + File classesDir = new File(file, "classes"); + if (rootFiles.isEmpty() && classesDir.isDirectory()) { + rootFiles.add(classesDir); + } + return rootFiles; + } +} diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JdkVersionDetectorImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JdkVersionDetectorImpl.java new file mode 100644 index 000000000000..12ab6b5a2d80 --- /dev/null +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JdkVersionDetectorImpl.java @@ -0,0 +1,163 @@ +package org.jetbrains.jps.model.java.impl; + +import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.JdkVersionDetector; +import org.jetbrains.jps.service.SharedThreadPool; + +import java.io.*; +import java.util.concurrent.Future; + +/** + * @author nik + */ +public class JdkVersionDetectorImpl extends JdkVersionDetector { + private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.SdkVersionUtil"); + private static final ActionRunner ACTION_RUNNER = new ActionRunner() { + @Override + public Future run(Runnable runnable) { + return SharedThreadPool.getInstance().executeOnPooledThread(runnable); + } + }; + + @Override + @Nullable + public String detectJdkVersion(String homePath) { + return detectJdkVersion(homePath, ACTION_RUNNER); + } + + @Nullable + public String detectJdkVersion(String homePath, final ActionRunner actionRunner) { + String[] command = {homePath + File.separator + "bin" + File.separator + "java", "-version"}; + return readVersionFromProcessOutput(homePath, command, "version", actionRunner); + } + + public String readVersionFromProcessOutput(String homePath, String[] command, String versionLineMarker, + ActionRunner actionRunner) { + if (homePath == null || !new File(homePath).exists()) { + return null; + } + final String[] versionString = new String[1]; + try { + //noinspection HardCodedStringLiteral + Process process = Runtime.getRuntime().exec(command); + VersionParsingThread parsingThread = new VersionParsingThread(process.getErrorStream(), versionString, versionLineMarker); + final Future parsingThreadFuture = actionRunner.run(parsingThread); + ReadStreamThread readThread = new ReadStreamThread(process.getInputStream()); + actionRunner.run(readThread); + + try { + try { + process.waitFor(); + } + catch (InterruptedException e) { + LOG.info(e); + process.destroy(); + } + } + finally { + try { + parsingThreadFuture.get(); + } + catch (Exception e) { + LOG.info(e); + } + } + } + catch (IOException ex) { + LOG.info(ex); + } + return versionString[0]; + } + + public static class ReadStreamThread implements Runnable { + private final InputStream myStream; + + protected ReadStreamThread(InputStream stream) { + myStream = stream; + } + + public void run() { + try { + while (true) { + int b = myStream.read(); + if (b == -1) break; + } + } + catch (IOException e) { + LOG.info(e); + } + } + } + + public static class VersionParsingThread implements Runnable { + private Reader myReader; + private final InputStream myStream; + private boolean mySkipLF = false; + private final String[] myVersionString; + private final String myVersionLineMarker; + + protected VersionParsingThread(InputStream input, String[] versionString, String versionLineMarker) { + myStream = input; + myVersionString = versionString; + myVersionLineMarker = versionLineMarker; + } + + public void run() { + try { + myReader = new InputStreamReader(myStream); + while (true) { + String line = readLine(); + if (line == null) return; + if (line.contains(myVersionLineMarker)) { + myVersionString[0] = line; + } + } + } + catch (IOException e) { + LOG.info(e); + } + finally { + if (myReader != null){ + try { + myReader.close(); + } + catch (IOException e) { + LOG.info(e); + } + } + } + } + + private String readLine() throws IOException { + boolean first = true; + StringBuilder buffer = new StringBuilder(); + while (true) { + int c = myReader.read(); + if (c == -1) break; + first = false; + if (c == '\n') { + if (mySkipLF) { + mySkipLF = false; + continue; + } + break; + } + else if (c == '\r') { + mySkipLF = true; + break; + } + else { + mySkipLF = false; + buffer.append((char)c); + } + } + if (first) return null; + String s = buffer.toString(); + //if (Diagnostic.TRACE_ENABLED){ + // Diagnostic.trace(s); + //} + return s; + } + } +} diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java index 0cc32ab528e3..d2e364ccb6be 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java @@ -1,12 +1,19 @@ package org.jetbrains.jps.model.java.impl; +import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.JpsDummyElement; +import org.jetbrains.jps.model.JpsGlobal; import org.jetbrains.jps.model.JpsProject; import org.jetbrains.jps.model.JpsSimpleElement; import org.jetbrains.jps.model.java.*; +import org.jetbrains.jps.model.library.JpsOrderRootType; +import org.jetbrains.jps.model.library.JpsTypedLibrary; +import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.model.module.*; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -115,6 +122,18 @@ public class JpsJavaExtensionServiceImpl extends JpsJavaExtensionService { return null; } + @Override + public JpsTypedLibrary> addJavaSdk(@NotNull JpsGlobal global, @NotNull String name, @NotNull String homePath) { + String version = JdkVersionDetector.getInstance().detectJdkVersion(homePath); + JpsTypedLibrary> sdk = global.addSdk(name, homePath, version, JpsJavaSdkType.INSTANCE); + File homeDir = new File(FileUtil.toSystemDependentName(homePath)); + List roots = JavaSdkUtil.getJdkClassesRoots(homeDir, false); + for (File root : roots) { + sdk.addRoot(root, JpsOrderRootType.COMPILED); + } + return sdk; + } + @Override @NotNull public JpsProductionModuleOutputPackagingElement createProductionModuleOutput(@NotNull JpsModuleReference moduleReference) { diff --git a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java index 8a3aa9f414df..659bcbd70c0e 100644 --- a/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java +++ b/jps/model-impl/src/org/jetbrains/jps/model/library/impl/JpsLibraryImpl.java @@ -54,6 +54,11 @@ public class JpsLibraryImpl

extends JpsNamedCompositeEleme addRoot(url, rootType, JpsLibraryRoot.InclusionOptions.ROOT_ITSELF); } + @Override + public void addRoot(@NotNull File file, @NotNull JpsOrderRootType rootType) { + addRoot(JpsPathUtil.getLibraryRootUrl(file), rootType); + } + @Override public void addRoot(@NotNull final String url, @NotNull final JpsOrderRootType rootType, @NotNull JpsLibraryRoot.InclusionOptions options) { diff --git a/jps/model-impl/src/org/jetbrains/jps/service/impl/SharedThreadPoolImpl.java b/jps/model-impl/src/org/jetbrains/jps/service/impl/SharedThreadPoolImpl.java new file mode 100644 index 000000000000..05643cd6e519 --- /dev/null +++ b/jps/model-impl/src/org/jetbrains/jps/service/impl/SharedThreadPoolImpl.java @@ -0,0 +1,34 @@ +package org.jetbrains.jps.service.impl; + +import org.jetbrains.jps.service.SharedThreadPool; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * @author nik + */ +public class SharedThreadPoolImpl extends SharedThreadPool { + private final ExecutorService myService = Executors.newCachedThreadPool(); + + @Override + public void execute(Runnable command) { + executeOnPooledThread(command); + } + + @Override + public Future executeOnPooledThread(final Runnable action) { + return myService.submit(new Runnable() { + @Override + public void run() { + try { + action.run(); + } + finally { + Thread.interrupted(); // reset interrupted status + } + } + }); + } +} diff --git a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java index ab0c95112cab..0c4f71e91363 100644 --- a/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java +++ b/jps/model-serialization/src/org/jetbrains/jps/model/serialization/JpsProjectLoader.java @@ -32,7 +32,7 @@ public class JpsProjectLoader extends JpsLoaderBase { private final JpsProject myProject; private final Map myPathVariables; - public JpsProjectLoader(JpsProject project, Map pathVariables, File baseDir) { + private JpsProjectLoader(JpsProject project, Map pathVariables, File baseDir) { super(createProjectMacroExpander(pathVariables, baseDir)); myProject = project; myPathVariables = pathVariables; diff --git a/jps/standalone-builder/jps-standalone-builder.iml b/jps/standalone-builder/jps-standalone-builder.iml index e71427745e89..186ddc1271c6 100644 --- a/jps/standalone-builder/jps-standalone-builder.iml +++ b/jps/standalone-builder/jps-standalone-builder.iml @@ -21,6 +21,7 @@ + diff --git a/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java b/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java new file mode 100644 index 000000000000..66a26df0343d --- /dev/null +++ b/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantProjectBuilder.java @@ -0,0 +1,72 @@ +package org.jetbrains.jps.gant; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.jetbrains.jps.api.BuildType; +import org.jetbrains.jps.build.Standalone; +import org.jetbrains.jps.cmdline.JpsModelLoader; +import org.jetbrains.jps.model.JpsModel; + +import java.io.File; +import java.util.Collections; + +/** + * @author nik + */ +public class JpsGantProjectBuilder { + private final Project myProject; + private final JpsModel myModel; + private final org.jetbrains.jps.Project myOldProject; + private boolean myCompressJars; + private File myDataStorageRoot; + private JpsModelLoader myModelLoader; + + public JpsGantProjectBuilder(Project project, JpsModel model, org.jetbrains.jps.Project oldProject) { + myProject = project; + myModel = model; + myOldProject = oldProject; + myModelLoader = new JpsModelLoader() { + @Override + public JpsModel loadModel() { + return myModel; + } + + @Override + public org.jetbrains.jps.Project loadOldProject() { + return myOldProject; + } + }; + } + + public boolean isCompressJars() { + return myCompressJars; + } + + public void setCompressJars(boolean compressJars) { + myCompressJars = compressJars; + } + + public void error(String message) { + throw new BuildException(message); + } + + public void warning(String message) { + myProject.log(message, Project.MSG_WARN); + } + + public void info(String message) { + myProject.log(message, Project.MSG_INFO); + } + + public void stage(String message) { + myProject.log(message, Project.MSG_INFO); + } + + public void setDataStorageRoot(File dataStorageRoot) { + myDataStorageRoot = dataStorageRoot; + } + + public void rebuildModules() { + Standalone.runBuild(myModelLoader, myDataStorageRoot, BuildType.PROJECT_REBUILD, Collections.emptySet(), Collections.emptyList()); + } +} diff --git a/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantTool.groovy b/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantTool.groovy new file mode 100644 index 000000000000..a131d97af271 --- /dev/null +++ b/jps/standalone-builder/src/org/jetbrains/jps/gant/JpsGantTool.groovy @@ -0,0 +1,103 @@ +package org.jetbrains.jps.gant +import org.codehaus.gant.GantBinding +import org.jetbrains.jps.Project +import org.jetbrains.jps.idea.IdeaProjectLoader +import org.jetbrains.jps.incremental.Utils +import org.jetbrains.jps.model.JpsElementFactory +import org.jetbrains.jps.model.JpsGlobal +import org.jetbrains.jps.model.JpsModel +import org.jetbrains.jps.model.JpsProject +import org.jetbrains.jps.model.java.JpsJavaExtensionService +import org.jetbrains.jps.model.library.JpsOrderRootType +import org.jetbrains.jps.model.serialization.JpsProjectLoader +/** + * @author nik + */ +final class JpsGantTool { + JpsGantTool(GantBinding binding) { + JpsModel model = JpsElementFactory.getInstance().createModel(); + JpsProject project = model.project + def oldProject = new Project() + binding.setVariable("project", project) + binding.setVariable("oldProject", oldProject) + binding.setVariable("global", model.global) + def builder = new JpsGantProjectBuilder(binding.ant.project, model, oldProject) + binding.setVariable("builder", builder) + binding.setVariable("loadProject", {String path -> + loadProject(path, model, oldProject, builder); + }) + + binding.setVariable("jdk", {Object[] args -> + if (!(args.length in [2,3])) { + builder.error("expected 2 to 3 parameters for jdk() but ${args.length} found") + } + Closure initializer = args.length > 2 ? (Closure)args[2] : {} + return createJavaSdk(model.global, (String)args[0], (String)args[1], initializer) + }) + + binding.setVariable("layout", {String dir, Closure body -> + def layoutInfo = new LayoutInfo() + + ["module", "moduleTests", "zip", "dir"].each {tag -> + binding.setVariable(tag, {Object[] args -> + if (args.length == 1) { + binding.ant."$tag"(name: args[0]) + } + else if (args.length == 2) { + binding.ant."$tag"(name: args[0], args[1]) + } + else { + builder.error("unexpected number of parameters for $tag") + } + if (tag == "module") { + layoutInfo.usedModules << args[0].toString() + } + }) + } + binding.setVariable("jar", {Object[] args -> + if (args.length == 2) { + def param0 = args[0] + String name; + String duplicate = null; + if (param0 instanceof Map) { + name = param0.name; + duplicate = param0.duplicate; + } + else { + name = (String)param0; + } + if (duplicate == null) { + duplicate = "fail" + } + binding.ant.jar(name: name, compress: builder.compressJars, duplicate: duplicate, args[1]) + } + else { + builder.error("unexpected number of parameters for 'jar' task: $args.length") + } + }) + + def meta = new Expando() + body.delegate = meta + binding.ant.layout(toDir: dir, body) + return layoutInfo + }) + + binding.ant.taskdef(name: "layout", classname: "jetbrains.antlayout.tasks.LayoutTask") + } + + private void loadProject(String path, JpsModel model, Project oldProject, JpsGantProjectBuilder builder) { + IdeaProjectLoader.loadFromPath(oldProject, path, [:]) + JpsProjectLoader.loadProject(model.project, [:], path) + builder.setDataStorageRoot(Utils.getDataStorageRoot(path)) + } + + private void createJavaSdk(JpsGlobal global, String name, String homePath, Closure initializer) { + def sdk = JpsJavaExtensionService.getInstance().addJavaSdk(global, name, homePath) + def meta = new Expando() + meta.classpath = {String path -> + sdk.addRoot(new File(path), JpsOrderRootType.COMPILED) + } + initializer.delegate = meta + initializer.call() + } +} diff --git a/jps/standalone-builder/src/org/jetbrains/jps/gant/LayoutInfo.java b/jps/standalone-builder/src/org/jetbrains/jps/gant/LayoutInfo.java new file mode 100644 index 000000000000..61224a44e69e --- /dev/null +++ b/jps/standalone-builder/src/org/jetbrains/jps/gant/LayoutInfo.java @@ -0,0 +1,15 @@ +package org.jetbrains.jps.gant; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author nik + */ +public class LayoutInfo { + private Set myUsedModules = new HashSet(); + + public Set getUsedModules() { + return myUsedModules; + } +} diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java index 39e720cc5aaa..7e4b1f2640b9 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/SimpleJavaSdkType.java @@ -92,7 +92,7 @@ public class SimpleJavaSdkType extends SdkType implements JavaSdkType { public final String getVersionString(final String sdkHome) { - return SdkVersionUtil.readVersionFromProcessOutput(sdkHome, new String[] {sdkHome + File.separator + "bin" + File.separator + "java", "-version"}, "version"); + return SdkVersionUtil.detectJdkVersion(sdkHome); } } diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/impl/SdkVersionUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/impl/SdkVersionUtil.java index 228129b60393..8e61cd45eb87 100644 --- a/platform/lang-api/src/com/intellij/openapi/projectRoots/impl/SdkVersionUtil.java +++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/impl/SdkVersionUtil.java @@ -23,145 +23,30 @@ package com.intellij.openapi.projectRoots.impl; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.model.java.JdkVersionDetector; -import java.io.*; import java.util.concurrent.Future; public class SdkVersionUtil { - private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.SdkVersionUtil"); + private static final JdkVersionDetector.ActionRunner ACTION_RUNNER = new JdkVersionDetector.ActionRunner() { + @Override + public Future run(Runnable runnable) { + return ApplicationManager.getApplication().executeOnPooledThread(runnable); + } + }; private SdkVersionUtil() { } @Nullable public static String readVersionFromProcessOutput(String homePath, @NonNls String[] command, @NonNls String versionLineMarker) { - if (homePath == null || !new File(homePath).exists()) { - return null; - } - final String[] versionString = new String[1]; - try { - //noinspection HardCodedStringLiteral - Process process = Runtime.getRuntime().exec(command); - VersionParsingThread parsingThread = new VersionParsingThread(process.getErrorStream(), versionString, versionLineMarker); - final Future parsingThreadFuture = ApplicationManager.getApplication().executeOnPooledThread(parsingThread); - ReadStreamThread readThread = new ReadStreamThread(process.getInputStream()); - ApplicationManager.getApplication().executeOnPooledThread(readThread); - - try { - try { - process.waitFor(); - } - catch (InterruptedException e) { - LOG.info(e); - process.destroy(); - } - } - finally { - try { - parsingThreadFuture.get(); - } - catch (Exception e) { - LOG.info(e); - } - } - } - catch (IOException ex) { - LOG.info(ex); - } - return versionString[0]; + return JdkVersionDetector.getInstance().readVersionFromProcessOutput(homePath, command, versionLineMarker, ACTION_RUNNER); } - public static class ReadStreamThread implements Runnable { - private final InputStream myStream; - - protected ReadStreamThread(InputStream stream) { - myStream = stream; - } - - public void run() { - try { - while (true) { - int b = myStream.read(); - if (b == -1) break; - } - } - catch (IOException e) { - LOG.info(e); - } - } - } - - public static class VersionParsingThread implements Runnable { - private Reader myReader; - private final InputStream myStream; - private boolean mySkipLF = false; - private final String[] myVersionString; - private final String myVersionLineMarker; - - protected VersionParsingThread(InputStream input, String[] versionString, String versionLineMarker) { - myStream = input; - myVersionString = versionString; - myVersionLineMarker = versionLineMarker; - } - - public void run() { - try { - myReader = new InputStreamReader(myStream); - while (true) { - String line = readLine(); - if (line == null) return; - if (line.contains(myVersionLineMarker)) { - myVersionString[0] = line; - } - } - } - catch (IOException e) { - LOG.info(e); - } - finally { - if (myReader != null){ - try { - myReader.close(); - } - catch (IOException e) { - LOG.info(e); - } - } - } - } - - private String readLine() throws IOException { - boolean first = true; - StringBuilder buffer = new StringBuilder(); - while (true) { - int c = myReader.read(); - if (c == -1) break; - first = false; - if (c == '\n') { - if (mySkipLF) { - mySkipLF = false; - continue; - } - break; - } - else if (c == '\r') { - mySkipLF = true; - break; - } - else { - mySkipLF = false; - buffer.append((char)c); - } - } - if (first) return null; - String s = buffer.toString(); - //if (Diagnostic.TRACE_ENABLED){ - // Diagnostic.trace(s); - //} - return s; - } + @Nullable + public static String detectJdkVersion(String homePath) { + return JdkVersionDetector.getInstance().detectJdkVersion(homePath, ACTION_RUNNER); } } diff --git a/platform/projectModel-api/projectModel-api.iml b/platform/projectModel-api/projectModel-api.iml index caff682b4a06..c0265a8dfada 100644 --- a/platform/projectModel-api/projectModel-api.iml +++ b/platform/projectModel-api/projectModel-api.iml @@ -8,6 +8,7 @@ + diff --git a/platform/projectModel-impl/projectModel-impl.iml b/platform/projectModel-impl/projectModel-impl.iml index 3bde48255eb4..d2af9138feee 100644 --- a/platform/projectModel-impl/projectModel-impl.iml +++ b/platform/projectModel-impl/projectModel-impl.iml @@ -10,7 +10,7 @@ - +