mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
move WinAppxTools to sdk to make it usable by sdk validation, add test
GitOrigin-RevId: 01db8da280be654313cb78aa8d4b8ee9d52b7fa5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
09d3f7e6ee
commit
45dd3dd86e
@@ -5,6 +5,7 @@
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
@@ -25,5 +26,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.execution" />
|
||||
<orderEntry type="module" module-name="intellij.platform.remote.core" />
|
||||
<orderEntry type="library" name="commons-collections" level="project" />
|
||||
<orderEntry type="library" name="jna" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+18
-13
@@ -1,16 +1,17 @@
|
||||
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.python.sdk.flavors
|
||||
package com.jetbrains.python.sdk
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.util.io.isAncestor
|
||||
import com.sun.jna.platform.win32.Kernel32
|
||||
import com.sun.jna.platform.win32.Kernel32.*
|
||||
import com.sun.jna.platform.win32.Ntifs
|
||||
import com.sun.jna.platform.win32.WinioctlUtil
|
||||
import com.sun.jna.ptr.IntByReference
|
||||
import java.io.File
|
||||
import java.io.FilenameFilter
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
|
||||
/**
|
||||
* AppX packages installed to AppX volume (see ``Get-AppxDefaultVolume``, ``Get-AppxPackage``).
|
||||
@@ -26,6 +27,8 @@ import java.nio.ByteBuffer
|
||||
* There is no Java API to see reparse point destination, so we use JNA.
|
||||
* This tool returns AppX name (either ``PythonSoftwareFoundation...`` or ``DesktopAppInstaller..``).
|
||||
* We use it to check if ``python.exe`` is real python or WindowsStore mock.
|
||||
*
|
||||
* See [WinAppxTest]
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -39,22 +42,24 @@ private const val storeMarker = "DesktopAppInstaller"
|
||||
* There may be several files linked to this product, we need only first.
|
||||
* And for 3.7 there could be ``PythonSoftwareFoundation.Python.3.7_(SOME_OTHER_UID)``.
|
||||
*/
|
||||
fun getAppxFiles(expectedProduct: String, filePattern: Regex): Collection<File> =
|
||||
userAppxFolder?.listFiles(FilenameFilter { _, name -> filePattern.matches(name) })
|
||||
fun getAppxFiles(expectedProduct: String?, filePattern: Regex): Collection<Path> =
|
||||
userAppxFolder?.listDirectoryEntries()
|
||||
?.filter { filePattern.matches(it.name) }
|
||||
?.sortedBy { it.nameWithoutExtension }
|
||||
?.mapNotNull { file -> file.appxProduct?.let { product -> Pair(product, file) } }
|
||||
?.toMap()
|
||||
?.filterKeys { expectedProduct in it }
|
||||
?.filterKeys { expectedProduct == null || expectedProduct in it }
|
||||
?.values ?: emptyList()
|
||||
|
||||
|
||||
/**
|
||||
* If file is AppX reparse point link -- return its product name
|
||||
*/
|
||||
val File.appxProduct: String?
|
||||
val Path.appxProduct: String?
|
||||
get() {
|
||||
if (parentFile?.equals(userAppxFolder) != true) return null
|
||||
return getAppxTag(absolutePath)?.let {
|
||||
val userAppxFolder = userAppxFolder ?: return null
|
||||
if (!userAppxFolder.isAncestor(this)) return null
|
||||
return getAppxTag(this)?.let {
|
||||
if (storeMarker !in it) it else null
|
||||
}
|
||||
}
|
||||
@@ -63,13 +68,13 @@ val File.appxProduct: String?
|
||||
/**
|
||||
* Path to ``%LOCALAPPDATA%\Microsoft\WindowsApps``
|
||||
*/
|
||||
private val userAppxFolder =
|
||||
private val userAppxFolder: Path? =
|
||||
if (!SystemInfo.isWin10OrNewer) {
|
||||
null
|
||||
}
|
||||
else {
|
||||
System.getenv("LOCALAPPDATA")?.let { localappdata ->
|
||||
val appsPath = File(localappdata, "Microsoft//WindowsApps")
|
||||
val appsPath = Path.of(localappdata, "Microsoft//WindowsApps")
|
||||
if (appsPath.exists()) appsPath else null
|
||||
}
|
||||
}
|
||||
@@ -99,11 +104,11 @@ See https://youtrack.jetbrains.com/issue/PY-43082
|
||||
|
||||
Output is unicode 16-LE
|
||||
*/
|
||||
private fun getAppxTag(path: String): String? {
|
||||
private fun getAppxTag(path: Path): String? {
|
||||
if (!SystemInfo.isWin10OrNewer) return null
|
||||
val kernel = INSTANCE
|
||||
val logger = Logger.getInstance(Kernel32::class.java)
|
||||
val file = kernel.CreateFile(path, GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, null)
|
||||
val file = kernel.CreateFile(path.pathString, GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, null)
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
logger.warn("Invalid handle for $path")
|
||||
return null
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.jetbrains.python.tests
|
||||
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.jetbrains.python.sdk.appxProduct
|
||||
import com.jetbrains.python.sdk.getAppxFiles
|
||||
import org.junit.Assert
|
||||
import org.junit.Assume
|
||||
import org.junit.Test
|
||||
|
||||
class WinAppxTest {
|
||||
@Test
|
||||
fun testAppx() {
|
||||
Assume.assumeTrue("Win only", SystemInfoRt.isWindows)
|
||||
val appxFiles = getAppxFiles(null, Regex(".+"))
|
||||
Assume.assumeTrue("No appx apps found", appxFiles.isNotEmpty())
|
||||
for (appxFile in appxFiles) {
|
||||
Assert.assertNotNull("No appx product product for $appxFile", appxFile.appxProduct)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,8 @@ import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
import static com.jetbrains.python.sdk.flavors.WinAppxToolsKt.getAppxFiles;
|
||||
import static com.jetbrains.python.sdk.flavors.WinAppxToolsKt.getAppxProduct;
|
||||
import static com.jetbrains.python.sdk.WinAppxToolsKt.getAppxFiles;
|
||||
import static com.jetbrains.python.sdk.WinAppxToolsKt.getAppxProduct;
|
||||
|
||||
/**
|
||||
* This class knows how to find python in Windows Registry according to
|
||||
@@ -100,7 +100,6 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
|
||||
}
|
||||
var path = sdk.getHomePath();
|
||||
return path != null && isLocalPathValidPython(Path.of(path));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,8 +116,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
|
||||
return true;
|
||||
}
|
||||
|
||||
final File file = path.toFile();
|
||||
return StringUtils.contains(getAppxProduct(file), APPX_PRODUCT) && isValidSdkPath(file);
|
||||
return StringUtils.contains(getAppxProduct(path), APPX_PRODUCT) && isValidSdkPath(path.toFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -160,7 +158,7 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor<PyFlavorData.Empty> {
|
||||
|
||||
@NotNull
|
||||
private static Set<String> getPythonsFromStore() {
|
||||
return ContainerUtil.map2Set(getAppxFiles(APPX_PRODUCT, PYTHON_EXE), file -> file.getAbsolutePath());
|
||||
return ContainerUtil.map2Set(getAppxFiles(APPX_PRODUCT, PYTHON_EXE), file -> file.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user