From ac01e7301c623ab498dd7547749e406574a42fef Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Fri, 18 Aug 2017 20:56:15 +0200 Subject: [PATCH] Move python tools code to community --- .idea/modules.xml | 1 + python/testSrc/python-community-tests.iml | 2 +- python/tools/python-community-tools.iml | 19 +++ python/tools/setup-envs/build.gradle | 16 ++ .../python/tools/BuildZippedSkeletons.kt | 57 ++++++++ .../src/com/jetbrains/python/tools/Utils.kt | 54 +++++++ .../jetbrains/python/tools/package-info.java | 6 + .../python/tools/sdkTools/PySdkTools.java | 137 ++++++++++++++++++ .../tools/sdkTools/SdkCreationType.java | 20 +++ .../python/tools/sdkTools/package-info.java | 6 + 10 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 python/tools/python-community-tools.iml create mode 100644 python/tools/setup-envs/build.gradle create mode 100644 python/tools/src/com/jetbrains/python/tools/BuildZippedSkeletons.kt create mode 100644 python/tools/src/com/jetbrains/python/tools/Utils.kt create mode 100644 python/tools/src/com/jetbrains/python/tools/package-info.java create mode 100644 python/tools/src/com/jetbrains/python/tools/sdkTools/PySdkTools.java create mode 100644 python/tools/src/com/jetbrains/python/tools/sdkTools/SdkCreationType.java create mode 100644 python/tools/src/com/jetbrains/python/tools/sdkTools/package-info.java diff --git a/.idea/modules.xml b/.idea/modules.xml index babe46bc8362..75f20ff89883 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -232,6 +232,7 @@ + diff --git a/python/testSrc/python-community-tests.iml b/python/testSrc/python-community-tests.iml index e842dc9895da..24a998f78039 100644 --- a/python/testSrc/python-community-tests.iml +++ b/python/testSrc/python-community-tests.iml @@ -24,6 +24,6 @@ - + \ No newline at end of file diff --git a/python/tools/python-community-tools.iml b/python/tools/python-community-tools.iml new file mode 100644 index 000000000000..bc4f05f78905 --- /dev/null +++ b/python/tools/python-community-tools.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/python/tools/setup-envs/build.gradle b/python/tools/setup-envs/build.gradle new file mode 100644 index 000000000000..30ff2a60c4f8 --- /dev/null +++ b/python/tools/setup-envs/build.gradle @@ -0,0 +1,16 @@ +import org.apache.tools.ant.taskdefs.condition.Os + +plugins { + id "com.jetbrains.python.envs" version "0.0.17" +} + + +envs { + bootstrapDirectory = new File(System.getenv().getOrDefault("PYCHARM_PYTHONS", new File(buildDir, 'pythons').path)) + envsDirectory = new File(System.getenv().getOrDefault("PYCHARM_PYTHON_VIRTUAL_ENVS", new File(buildDir, 'envs').path)) + minicondaVersion = 'latest' + _64Bits = true + + python "python27", "2.7.13", "64", [] + python "python36", "3.6.2", "64", [] +} diff --git a/python/tools/src/com/jetbrains/python/tools/BuildZippedSkeletons.kt b/python/tools/src/com/jetbrains/python/tools/BuildZippedSkeletons.kt new file mode 100644 index 000000000000..e410b711f659 --- /dev/null +++ b/python/tools/src/com/jetbrains/python/tools/BuildZippedSkeletons.kt @@ -0,0 +1,57 @@ +package com.jetbrains.python.tools + +import com.intellij.idea.IdeaTestApplication +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.util.io.ZipUtil +import com.jetbrains.python.sdk.PythonSdkType +import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher +import com.jetbrains.python.sdk.skeletons.SkeletonVersionChecker +import com.jetbrains.python.tools.sdkTools.PySdkTools +import com.jetbrains.python.tools.sdkTools.SdkCreationType +import java.io.File +import java.io.FileOutputStream +import java.util.zip.ZipOutputStream + +/** + * @author traff + */ + +val PYCHARM_PYTHONS = "PYCHARM_PYTHONS" + +fun main(args: Array) { + val app = IdeaTestApplication.getInstance() + try { + + val root = System.getenv(PYCHARM_PYTHONS) + + for (python in File(root).listFiles()) { + + println("Running on $python") + + val sdk = PySdkTools.createTempSdk(VfsUtil.findFileByIoFile(File(PythonSdkType.getPythonExecutable(python.absolutePath)!!), true)!!, + SdkCreationType.SDK_PACKAGES_AND_SKELETONS, null) + + val skeletonsDir = File(System.getProperty("user.dir"), "skeletons-${sdk.versionString!!.replace(" ", "_")}_" + +Math.abs(sdk.homePath!!.hashCode())) + + println("Generating skeletons in ${skeletonsDir.absolutePath}") + + val refresher = PySkeletonRefresher(null, null, sdk, skeletonsDir.absolutePath, null, null) + + + refresher.regenerateSkeletons(SkeletonVersionChecker(0)) + + + val dirPacked = File(skeletonsDir.parent, refresher.pregeneratedSkeletonsName) + val zip = ZipOutputStream(FileOutputStream(dirPacked)) + ZipUtil.addDirToZipRecursively(zip, dirPacked, skeletonsDir, "", null, null) + zip.close() + } + } + catch (e: Exception) { + e.printStackTrace() + System.exit(1) + } + finally { + System.exit(0) //TODO: graceful exit? + } +} \ No newline at end of file diff --git a/python/tools/src/com/jetbrains/python/tools/Utils.kt b/python/tools/src/com/jetbrains/python/tools/Utils.kt new file mode 100644 index 000000000000..1a1e06f1d423 --- /dev/null +++ b/python/tools/src/com/jetbrains/python/tools/Utils.kt @@ -0,0 +1,54 @@ +package com.jetbrains.python.tools + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.impl.ApplicationInfoImpl +import com.intellij.openapi.module.Module +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.util.ui.UIUtil +import com.jetbrains.python.sdk.PythonSdkType +import com.jetbrains.python.sdk.PythonSdkUpdater +import com.jetbrains.python.tools.sdkTools.PySdkTools +import com.jetbrains.python.tools.sdkTools.SdkCreationType +import java.io.File + +internal val TestPath = System.getenv("PYCHARM_PERF_ENVS") + +@JvmOverloads +fun createSdkForPerformance(module: Module, + sdkCreationType: SdkCreationType, + sdkHome: String = File(TestPath, "envs/py36_64").absolutePath): Sdk { + ApplicationInfoImpl.setInStressTest(true) // To disable slow debugging + val executable = File(PythonSdkType.getPythonExecutable(sdkHome) ?: throw AssertionError("No python on $sdkHome")) + println("Running on $sdkHome") + return PySdkTools.createTempSdk(VfsUtil.findFileByIoFile(executable, true)!!, sdkCreationType, module) +} + + +fun openProjectWithSdk(projectPath: String, sdkHome: String): Pair { + val project: Project? = ProjectManager.getInstance().loadAndOpenProject(projectPath) + + val module = ModuleManager.getInstance(project!!).modules[0] + + val sdk = createSdkForPerformance(module, SdkCreationType.SDK_PACKAGES_AND_SKELETONS, sdkHome) + + UIUtil.invokeAndWaitIfNeeded(Runnable { + ApplicationManager.getApplication().runWriteAction({ + PythonSdkUpdater.update(sdk, null, project, null) + }) + }) + + if (module != null) { + ModuleRootModificationUtil.setModuleSdk(module, sdk) + } + + assert(ModuleRootManager.getInstance(module).orderEntries().classesRoots.size > 5) + assert(ModuleManager.getInstance(project).modules.size == 1) + + return Pair(project, sdk) +} \ No newline at end of file diff --git a/python/tools/src/com/jetbrains/python/tools/package-info.java b/python/tools/src/com/jetbrains/python/tools/package-info.java new file mode 100644 index 000000000000..8b8fb74b9167 --- /dev/null +++ b/python/tools/src/com/jetbrains/python/tools/package-info.java @@ -0,0 +1,6 @@ +/** + * Engine to create SDK in tests. + * See {@link com.jetbrains.python.sdkTools.PyTestSdkTools} + * @author Ilya.Kazakevich + */ +package com.jetbrains.python.sdkTools; \ No newline at end of file diff --git a/python/tools/src/com/jetbrains/python/tools/sdkTools/PySdkTools.java b/python/tools/src/com/jetbrains/python/tools/sdkTools/PySdkTools.java new file mode 100644 index 000000000000..923cda15216b --- /dev/null +++ b/python/tools/src/com/jetbrains/python/tools/sdkTools/PySdkTools.java @@ -0,0 +1,137 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.tools.sdkTools; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.SdkModificator; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.intellij.openapi.roots.ModuleRootModificationUtil; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.jetbrains.python.sdk.InvalidSdkException; +import com.jetbrains.python.sdk.PythonSdkAdditionalData; +import com.jetbrains.python.sdk.PythonSdkType; +import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; +import com.jetbrains.python.sdk.skeletons.PySkeletonRefresher; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.junit.Assert; + +import java.io.IOException; + +/** + * Engine to create SDK for tests. + * See {@link #createTempSdk(com.intellij.openapi.vfs.VirtualFile, SdkCreationType, com.intellij.openapi.module.Module)} + * + * @author Ilya.Kazakevich + */ +public final class PySdkTools { + + private static final Sdk[] NO_SDK = new Sdk[0]; + + private PySdkTools() { + + } + + /** + * Creates SDK by its path and associates it with module (if module provided) + * + * @param sdkHome path to sdk + * @param sdkCreationType SDK creation strategy (see {@link SdkCreationType} doc) + * @return sdk + */ + @NotNull + public static Sdk createTempSdk(@NotNull final VirtualFile sdkHome, + @NotNull final SdkCreationType sdkCreationType, + @Nullable final Module module + ) + throws InvalidSdkException { + final Ref ref = Ref.create(); + ApplicationManager.getApplication().invokeAndWait(() -> { + final Sdk sdk = SdkConfigurationUtil.setupSdk(NO_SDK, sdkHome, PythonSdkType.getInstance(), true, null, null); + Assert.assertNotNull("Failed to create SDK on " + sdkHome, sdk); + ref.set(sdk); + }); + final Sdk sdk = ref.get(); + if (sdkCreationType != SdkCreationType.EMPTY_SDK) { + generateTempSkeletonsOrPackages(sdk, sdkCreationType == SdkCreationType.SDK_PACKAGES_AND_SKELETONS, module); + } + ApplicationManager.getApplication().invokeAndWait(() -> SdkConfigurationUtil.addSdk(sdk)); + return sdk; + } + + + /** + * Adds installed eggs to SDK, generates skeletons (optionally) and associates it with module. + * + * @param sdk sdk to process + * @param addSkeletons add skeletons or only packages + * @param module module to associate with (if provided) + * @throws InvalidSdkException bas sdk + * @throws IOException failed to read eggs + */ + public static void generateTempSkeletonsOrPackages(@NotNull final Sdk sdk, + final boolean addSkeletons, + @Nullable final Module module) + throws InvalidSdkException { + Project project = null; + + if (module != null) { + project = module.getProject(); + final Project finalProject = project; + // Associate with module + ModuleRootModificationUtil.setModuleSdk(module, sdk); + + ApplicationManager.getApplication().invokeAndWait(() -> ApplicationManager.getApplication() + .runWriteAction(() -> ProjectRootManager.getInstance(finalProject).setProjectSdk(sdk))); + } + + + final SdkModificator modificator = sdk.getSdkModificator(); + + modificator.setSdkAdditionalData(new PythonSdkAdditionalData(PythonSdkFlavor.getFlavor(sdk))); + + for (final String path : PythonSdkType.getSysPathsFromScript(sdk.getHomePath())) { + addTestSdkRoot(modificator, path); + } + if (!addSkeletons) { + ApplicationManager.getApplication().invokeAndWait(modificator::commitChanges); + return; + } + + final String skeletonsPath = PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), sdk.getHomePath()); + addTestSdkRoot(modificator, skeletonsPath); + + ApplicationManager.getApplication().invokeAndWait(modificator::commitChanges); + + PySkeletonRefresher + .refreshSkeletonsOfSdk(project, null, skeletonsPath, sdk); + } + + public static void addTestSdkRoot(@NotNull SdkModificator sdkModificator, @NotNull String path) { + final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByPath(path); + if (file != null) { + sdkModificator.addRoot(PythonSdkType.getSdkRootVirtualFile(file), OrderRootType.CLASSES); + } + } +} diff --git a/python/tools/src/com/jetbrains/python/tools/sdkTools/SdkCreationType.java b/python/tools/src/com/jetbrains/python/tools/sdkTools/SdkCreationType.java new file mode 100644 index 000000000000..430bb1b109f2 --- /dev/null +++ b/python/tools/src/com/jetbrains/python/tools/sdkTools/SdkCreationType.java @@ -0,0 +1,20 @@ +package com.jetbrains.python.tools.sdkTools; + +/** + * SDK creation type + * @author Ilya.Kazakevich + */ +public enum SdkCreationType { + /** + * SDK only (no packages nor skeletons) + */ + EMPTY_SDK, + /** + * SDK + installed packages from syspath + */ + SDK_PACKAGES_ONLY, + /** + * SDK + installed packages from syspath + skeletons + */ + SDK_PACKAGES_AND_SKELETONS +} diff --git a/python/tools/src/com/jetbrains/python/tools/sdkTools/package-info.java b/python/tools/src/com/jetbrains/python/tools/sdkTools/package-info.java new file mode 100644 index 000000000000..07c9c3b28b90 --- /dev/null +++ b/python/tools/src/com/jetbrains/python/tools/sdkTools/package-info.java @@ -0,0 +1,6 @@ +/** + * Engine to create SDK in tests. + * See {@link com.jetbrains.python.tools.PyTestSdkTools} + * @author Ilya.Kazakevich + */ +package com.jetbrains.python.tools.sdkTools; \ No newline at end of file