mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[platform] replacing PathExecLazyValue (IJPL-7387 prerequisite)
GitOrigin-RevId: edc1f4884790a873780346c3d6e7e7540ea3d9d6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
30cb09e0c9
commit
6e9bacb07e
@@ -1,18 +1,18 @@
|
||||
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.fileTypes;
|
||||
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.IdeCoreBundle;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.system.OS;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class NativeFileType implements INativeFileType {
|
||||
public static final NativeFileType INSTANCE = new NativeFileType();
|
||||
@@ -64,16 +64,16 @@ public final class NativeFileType implements INativeFileType {
|
||||
throw new IllegalArgumentException("Non-local file: " + file + "; FS=" + file.getFileSystem());
|
||||
}
|
||||
|
||||
List<String> commands = new ArrayList<>();
|
||||
if (SystemInfo.isWindows) {
|
||||
var commands = new ArrayList<String>();
|
||||
if (OS.CURRENT == OS.Windows) {
|
||||
//noinspection SpellCheckingInspection
|
||||
commands.add("rundll32.exe");
|
||||
commands.add("url.dll,FileProtocolHandler");
|
||||
}
|
||||
else if (SystemInfo.isMac) {
|
||||
else if (OS.CURRENT == OS.macOS) {
|
||||
commands.add("/usr/bin/open");
|
||||
}
|
||||
else if (SystemInfo.hasXdgOpen()) {
|
||||
else if (PathEnvironmentVariableUtil.isOnPath("xdg-open")) {
|
||||
commands.add("xdg-open");
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -4,6 +4,7 @@ package com.intellij.ide.browsers
|
||||
import com.intellij.execution.CommandLineUtil
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
import com.intellij.execution.process.CapturingProcessHandler
|
||||
import com.intellij.execution.util.ExecUtil
|
||||
import com.intellij.ide.BrowserUtil
|
||||
@@ -17,11 +18,11 @@ import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.NlsContexts.NotificationContent
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.io.URLUtil
|
||||
import com.intellij.util.system.OS
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.awt.Desktop
|
||||
@@ -36,7 +37,7 @@ open class BrowserLauncherAppless : BrowserLauncher() {
|
||||
|
||||
@JvmStatic
|
||||
fun canUseSystemDefaultBrowserPolicy(): Boolean =
|
||||
isDesktopActionSupported(Desktop.Action.BROWSE) || SystemInfo.isWindows || SystemInfo.isMac || SystemInfo.hasXdgOpen()
|
||||
isDesktopActionSupported(Desktop.Action.BROWSE) || OS.CURRENT == OS.Windows || OS.CURRENT == OS.macOS || PathEnvironmentVariableUtil.isOnPath("xdg-open")
|
||||
|
||||
private fun isDesktopActionSupported(action: Desktop.Action): Boolean =
|
||||
Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(action)
|
||||
@@ -77,13 +78,13 @@ open class BrowserLauncherAppless : BrowserLauncher() {
|
||||
@Suppress("UsagesOfObsoleteApi")
|
||||
override fun browse(file: java.io.File) {
|
||||
val path = file.absolutePath
|
||||
val absPath = if (SystemInfo.isWindows && path[0] != '/') "/${path}" else path
|
||||
val absPath = if (OS.CURRENT == OS.Windows && path[0] != '/') "/${path}" else path
|
||||
browse("${StandardFileSystems.FILE_PROTOCOL_PREFIX}${absPath}", browser = null, project = null)
|
||||
}
|
||||
|
||||
override fun browse(file: Path) {
|
||||
val path = file.toAbsolutePath().toString()
|
||||
val absPath = if (SystemInfo.isWindows && path[0] != '/') "/${path}" else path
|
||||
val absPath = if (OS.CURRENT == OS.Windows && path[0] != '/') "/${path}" else path
|
||||
browse("${StandardFileSystems.FILE_PROTOCOL_PREFIX}${absPath}", browser = null, project = null)
|
||||
}
|
||||
|
||||
@@ -189,7 +190,7 @@ open class BrowserLauncherAppless : BrowserLauncher() {
|
||||
}
|
||||
catch (e: Exception) {
|
||||
LOG.warn("[${uri}]", e)
|
||||
if (SystemInfo.isMac && e.message!!.contains("Error code: -10814")) {
|
||||
if (OS.CURRENT == OS.macOS && e.message!!.contains("Error code: -10814")) {
|
||||
// if "No application knows how to open" the URL, there is no sense in retrying with the 'open' command
|
||||
return@launch
|
||||
}
|
||||
@@ -260,9 +261,9 @@ open class BrowserLauncherAppless : BrowserLauncher() {
|
||||
|
||||
private val defaultBrowserCommand: List<String>?
|
||||
get() = when {
|
||||
SystemInfo.isWindows -> listOf(CommandLineUtil.getWinShellName(), "/c", "start", GeneralCommandLine.inescapableQuote(""))
|
||||
SystemInfo.isMac -> listOf(ExecUtil.openCommandPath)
|
||||
SystemInfo.hasXdgOpen() -> listOf("xdg-open")
|
||||
OS.CURRENT == OS.Windows -> listOf(CommandLineUtil.getWinShellName(), "/c", "start", GeneralCommandLine.inescapableQuote(""))
|
||||
OS.CURRENT == OS.macOS -> listOf(ExecUtil.openCommandPath)
|
||||
PathEnvironmentVariableUtil.isOnPath("xdg-open") -> listOf("xdg-open")
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
|
||||
import com.intellij.execution.process.CapturingProcessHandler;
|
||||
import com.intellij.execution.util.ExecUtil;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
@@ -22,12 +23,12 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.updateSettings.impl.ExternalUpdateManager;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.AppUIUtil;
|
||||
import com.intellij.ui.AppUIUtilKt;
|
||||
import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.Restarter;
|
||||
import com.intellij.util.system.OS;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -44,7 +45,7 @@ public final class CreateDesktopEntryAction extends DumbAwareAction implements A
|
||||
private static final Logger LOG = Logger.getInstance(CreateDesktopEntryAction.class);
|
||||
|
||||
public static boolean isAvailable() {
|
||||
return SystemInfo.isUnix && !SystemInfo.isMac && !ExternalUpdateManager.isCreatingDesktopEntries() && SystemInfo.hasXdgOpen();
|
||||
return OS.isGenericUnix() &&!ExternalUpdateManager.isCreatingDesktopEntries() && PathEnvironmentVariableUtil.isOnPath("xdg-desktop-menu");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.actions;
|
||||
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
|
||||
import com.intellij.execution.process.CapturingProcessHandler;
|
||||
import com.intellij.execution.process.ProcessIOExecutorService;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
@@ -22,10 +23,10 @@ import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.NlsActions.ActionText;
|
||||
import com.intellij.openapi.util.NlsContexts;
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.ArchiveFileSystem;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.system.OS;
|
||||
import com.sun.jna.Native;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.platform.win32.*;
|
||||
@@ -107,12 +108,12 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
|
||||
/** Whether a system is able to open a directory in a file manager and highlight a file in it. */
|
||||
public static boolean isSupported() {
|
||||
return SystemInfo.isWindows || SystemInfo.isMac || Holder.fileManagerApp != null;
|
||||
return OS.CURRENT == OS.Windows || OS.CURRENT == OS.macOS || Holder.fileManagerApp != null;
|
||||
}
|
||||
|
||||
/** Whether a system is able to open a directory in a file manager. */
|
||||
public static boolean isDirectoryOpenSupported() {
|
||||
return SystemInfo.isWindows || SystemInfo.isMac || Holder.fileManagerApp != null;
|
||||
return OS.CURRENT == OS.Windows || OS.CURRENT == OS.macOS || Holder.fileManagerApp != null;
|
||||
}
|
||||
|
||||
public static @ActionText @NotNull String getActionName() {
|
||||
@@ -125,7 +126,7 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
}
|
||||
|
||||
private static @ActionText String getActionName(boolean skipDetection) {
|
||||
return SystemInfo.isMac ? ActionsBundle.message("action.RevealIn.name.mac") : ActionsBundle.message("action.RevealIn.name.other", getFileManagerName(skipDetection));
|
||||
return OS.CURRENT == OS.macOS ? ActionsBundle.message("action.RevealIn.name.mac") : ActionsBundle.message("action.RevealIn.name.other", getFileManagerName(skipDetection));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,8 +144,8 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
}
|
||||
|
||||
public static @NotNull @ActionText String getFileManagerName(boolean skipDetection) {
|
||||
return SystemInfo.isMac ? IdeBundle.message("action.finder.text") :
|
||||
SystemInfo.isWindows ? IdeBundle.message("action.explorer.text") :
|
||||
return OS.CURRENT == OS.Windows ? IdeBundle.message("action.explorer.text") :
|
||||
OS.CURRENT == OS.macOS ? IdeBundle.message("action.finder.text") :
|
||||
skipDetection ? IdeBundle.message("action.file.manager.text") :
|
||||
requireNonNullElseGet(Holder.fileManagerName, () -> IdeBundle.message("action.file.manager.text"));
|
||||
}
|
||||
@@ -202,7 +203,7 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
var toSelect = _toSelect != null ? canonicalize(_toSelect).normalize().toString() : null;
|
||||
String fmApp;
|
||||
|
||||
if (SystemInfo.isWindows) {
|
||||
if (OS.CURRENT == OS.Windows) {
|
||||
if (JnaLoader.isLoaded()) {
|
||||
openViaShellApi(dir, toSelect);
|
||||
}
|
||||
@@ -210,7 +211,7 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
openViaExplorerCall(dir, toSelect);
|
||||
}
|
||||
}
|
||||
else if (SystemInfo.isMac) {
|
||||
else if (OS.CURRENT == OS.macOS) {
|
||||
if (toSelect != null) {
|
||||
spawn("open", "-R", toSelect);
|
||||
}
|
||||
@@ -229,7 +230,7 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
spawn(fmApp, toSelect != null ? toSelect : dir);
|
||||
}
|
||||
}
|
||||
else if (toSelect == null && SystemInfo.hasXdgOpen()) {
|
||||
else if (toSelect == null && PathEnvironmentVariableUtil.isOnPath("xdg-open")) {
|
||||
spawn("xdg-open", dir);
|
||||
}
|
||||
else {
|
||||
@@ -298,7 +299,7 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
|
||||
ProcessIOExecutorService.INSTANCE.execute(() -> {
|
||||
try {
|
||||
var process = SystemInfo.isWindows ? Runtime.getRuntime().exec(command[0]) : new ProcessBuilder(command).start();
|
||||
var process = OS.CURRENT == OS.Windows ? Runtime.getRuntime().exec(command[0]) : new ProcessBuilder(command).start();
|
||||
new CapturingProcessHandler.Silent(process, null, command[0])
|
||||
.runProcess(10000, false)
|
||||
.checkSuccess(LOG);
|
||||
@@ -315,7 +316,7 @@ public class RevealFileAction extends DumbAwareAction implements LightEditCompat
|
||||
|
||||
static {
|
||||
String fmApp = null, fmName = null;
|
||||
if (SystemInfo.hasXdgMime()) {
|
||||
if (PathEnvironmentVariableUtil.isOnPath("xdg-mime")) {
|
||||
try (var reader = new ProcessBuilder("xdg-mime", "query", "default", "inode/directory").start().inputReader()) {
|
||||
var desktopEntryName = reader.readLine();
|
||||
if (desktopEntryName != null && desktopEntryName.endsWith(".desktop")) {
|
||||
|
||||
+7
-7
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.fileChooser.actions;
|
||||
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
|
||||
import com.intellij.execution.wsl.WSLDistribution;
|
||||
import com.intellij.execution.wsl.WSLUtil;
|
||||
import com.intellij.execution.wsl.WslDistributionManager;
|
||||
@@ -18,7 +19,6 @@ import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.ui.popup.util.PopupUtil;
|
||||
import com.intellij.openapi.util.io.NioFiles;
|
||||
import com.intellij.openapi.util.io.PathExecLazyValue;
|
||||
import com.intellij.ui.UIBundle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -26,15 +26,15 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
final class GoToWslHomeAction extends FileChooserAction implements LightEditCompatible {
|
||||
private static final Supplier<Boolean> ourHasWsl = PathExecLazyValue.create("wsl.exe");
|
||||
|
||||
@Override
|
||||
protected void update(@NotNull FileChooserPanel panel, @NotNull AnActionEvent e) {
|
||||
var allowed = WSLUtil.isSystemCompatible() && ourHasWsl.get() && Experiments.getInstance().isFeatureEnabled("wsl.p9.show.roots.in.file.chooser");
|
||||
e.getPresentation().setEnabledAndVisible(allowed);
|
||||
e.getPresentation().setEnabledAndVisible(
|
||||
WSLUtil.isSystemCompatible() &&
|
||||
Experiments.getInstance().isFeatureEnabled("wsl.p9.show.roots.in.file.chooser") &&
|
||||
PathEnvironmentVariableUtil.isOnPath("wsl.exe")
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-6
@@ -1,7 +1,8 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.fileChooser.actions;
|
||||
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
|
||||
import com.intellij.execution.util.ExecUtil;
|
||||
import com.intellij.ide.lightEdit.LightEditCompatible;
|
||||
import com.intellij.jna.JnaLoader;
|
||||
@@ -10,12 +11,12 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileChooser.FileChooserPanel;
|
||||
import com.intellij.openapi.fileChooser.FileSystemTree;
|
||||
import com.intellij.openapi.util.NullableLazyValue;
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import com.intellij.openapi.vfs.LocalFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.mac.foundation.Foundation;
|
||||
import com.intellij.ui.mac.foundation.ID;
|
||||
import com.intellij.util.SystemProperties;
|
||||
import com.intellij.util.system.OS;
|
||||
import com.sun.jna.platform.win32.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -65,7 +66,7 @@ final class GotoDesktopDirAction extends FileChooserAction implements LightEditC
|
||||
}
|
||||
|
||||
private static Path getDesktopDirectory() {
|
||||
if (SystemInfo.isWindows && JnaLoader.isLoaded()) {
|
||||
if (OS.CURRENT == OS.Windows && JnaLoader.isLoaded()) {
|
||||
char[] path = new char[WinDef.MAX_PATH];
|
||||
WinNT.HRESULT res = Shell32.INSTANCE.SHGetFolderPath(null, ShlObj.CSIDL_DESKTOP, null, ShlObj.SHGFP_TYPE_CURRENT, path);
|
||||
if (WinError.S_OK.equals(res)) {
|
||||
@@ -74,7 +75,7 @@ final class GotoDesktopDirAction extends FileChooserAction implements LightEditC
|
||||
return Path.of(new String(path, 0, len));
|
||||
}
|
||||
}
|
||||
else if (SystemInfo.isMac && JnaLoader.isLoaded()) {
|
||||
else if (OS.CURRENT == OS.macOS && JnaLoader.isLoaded()) {
|
||||
ID manager = Foundation.invoke(Foundation.getObjcClass("NSFileManager"), "defaultManager");
|
||||
ID url = Foundation.invoke(manager, "URLForDirectory:inDomain:appropriateForURL:create:error:",
|
||||
12 /*NSDesktopDirectory*/, 1 /*NSUserDomainMask*/, null, false, null);
|
||||
@@ -83,8 +84,8 @@ final class GotoDesktopDirAction extends FileChooserAction implements LightEditC
|
||||
return Path.of(path);
|
||||
}
|
||||
}
|
||||
else if (SystemInfo.hasXdgOpen()) {
|
||||
String path = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-user-dir", "DESKTOP"));
|
||||
else if (PathEnvironmentVariableUtil.isOnPath("xdg-user-dir")) {
|
||||
var path = ExecUtil.execAndReadLine(new GeneralCommandLine("xdg-user-dir", "DESKTOP"));
|
||||
if (path != null && !path.isBlank()) {
|
||||
try {
|
||||
return Path.of(path);
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.configurations;
|
||||
|
||||
import com.intellij.util.system.OS;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeTrue;
|
||||
|
||||
class PathEnvironmentVariableUtilTest {
|
||||
@Test void isOnPathContract() {
|
||||
assertThatCode(() -> PathEnvironmentVariableUtil.isOnPath("bad\\path")).isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test void isOnPathPositive() {
|
||||
var shell = Path.of(OS.CURRENT == OS.Windows ? "C:\\Windows\\System32\\cmd.exe" : "/bin/sh");
|
||||
assumeTrue(Files.isExecutable(shell));
|
||||
assertThat(PathEnvironmentVariableUtil.isOnPath(shell.getFileName().toString())).isTrue();
|
||||
}
|
||||
|
||||
@Test void isOnPathNegative() {
|
||||
assertThat(PathEnvironmentVariableUtil.isOnPath("no-one-in-his-right-mind-names-an-exec-like-this")).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -151,6 +151,7 @@ f:com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
- s:getPathDirs(java.lang.String):java.util.List
|
||||
- s:getPathVariableValue():java.lang.String
|
||||
- s:getWindowsExecutableFileExtensions():java.util.List
|
||||
- s:isOnPath(java.lang.String):Z
|
||||
c:com.intellij.execution.configurations.PtyCommandLine
|
||||
- com.intellij.execution.configurations.GeneralCommandLine
|
||||
- com.intellij.execution.configurations.CommandLineWithSuspendedProcessCallback
|
||||
|
||||
+33
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.configurations;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
@@ -10,15 +10,19 @@ import org.jetbrains.annotations.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A collection of utility methods for working with PATH environment variable.
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
public final class PathEnvironmentVariableUtil {
|
||||
|
||||
private static final String PATH = "PATH";
|
||||
private static final Map<String, Boolean> ourOnPathCache = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
private PathEnvironmentVariableUtil() { }
|
||||
|
||||
@@ -143,7 +147,7 @@ public final class PathEnvironmentVariableUtil {
|
||||
* Retrieves the value of PATH environment variable
|
||||
*/
|
||||
public static @Nullable String getPathVariableValue() {
|
||||
return EnvironmentUtil.getValue(PATH);
|
||||
return EnvironmentUtil.getValue("PATH");
|
||||
}
|
||||
|
||||
public static @Nullable File findExecutableInPathOnAnyOS(@NotNull @NonNls String fileBaseName) {
|
||||
@@ -157,4 +161,29 @@ public final class PathEnvironmentVariableUtil {
|
||||
return findInPath(fileBaseName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given file is in one of the directories listed in the PATH environment variable.
|
||||
* The first call might be slow, but the result is cached.
|
||||
*
|
||||
* @since 2025.3
|
||||
*/
|
||||
public static boolean isOnPath(@NotNull String name) {
|
||||
if (name.indexOf('\\') >= 0 || name.indexOf('/') >= 0) throw new IllegalArgumentException(name);
|
||||
var result = ourOnPathCache.get(name);
|
||||
if (result == null) {
|
||||
result = Boolean.FALSE;
|
||||
var path = getPathVariableValue();
|
||||
if (path != null) {
|
||||
for (var dir : StringUtil.tokenize(path, File.pathSeparator)) {
|
||||
if (Files.isExecutable(Path.of(dir, name))) {
|
||||
result = Boolean.TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ourOnPathCache.put(name, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-9
@@ -1,11 +1,11 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.execution.sudo
|
||||
|
||||
import com.intellij.execution.CommandLineUtil
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
import com.intellij.execution.util.ExecUtil
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.util.io.PathExecLazyValue
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.io.IdeUtilIoBundle
|
||||
import com.intellij.util.system.OS
|
||||
@@ -14,10 +14,6 @@ import org.jetbrains.annotations.Nls
|
||||
|
||||
@ApiStatus.Internal
|
||||
open class LocalSudoCommandProvider : SudoCommandProvider {
|
||||
private val hasGkSudo = PathExecLazyValue.create("gksudo")
|
||||
private val hasKdeSudo = PathExecLazyValue.create("kdesudo")
|
||||
private val hasPkExec = PathExecLazyValue.create("pkexec")
|
||||
|
||||
override fun isAvailable(): Boolean = true
|
||||
|
||||
override fun sudoCommand(wrappedCommand: GeneralCommandLine, prompt: @Nls String): GeneralCommandLine? {
|
||||
@@ -37,13 +33,13 @@ open class LocalSudoCommandProvider : SudoCommandProvider {
|
||||
do shell script ${escapedCommand} with prompt "${escapedPrompt}" with administrator privileges without altering line endings
|
||||
end tell""".trimIndent())
|
||||
}
|
||||
hasGkSudo.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("gksudo") -> {
|
||||
GeneralCommandLine(listOf("gksudo", "--message", prompt, "--") + envCommand(wrappedCommand) + command)
|
||||
}
|
||||
hasKdeSudo.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("kdesudo") -> {
|
||||
GeneralCommandLine(listOf("kdesudo", "--comment", prompt, "--") + envCommand(wrappedCommand) + command)
|
||||
}
|
||||
hasPkExec.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("pkexec") -> {
|
||||
GeneralCommandLine(listOf("pkexec") + envCommand(wrappedCommand) + command)
|
||||
}
|
||||
ExecUtil.hasTerminalApp() -> {
|
||||
|
||||
@@ -4,21 +4,21 @@ package com.intellij.execution.util
|
||||
import com.intellij.execution.CommandLineUtil
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
import com.intellij.execution.process.*
|
||||
import com.intellij.execution.sudo.SudoCommandProvider
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.progress.runBlockingMaybeCancellable
|
||||
import com.intellij.openapi.util.NlsSafe
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.PathExecLazyValue
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.provider.asEelPath
|
||||
import com.intellij.platform.eel.spawnProcess
|
||||
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
|
||||
import com.intellij.util.io.IdeUtilIoBundle
|
||||
import com.intellij.util.io.SuperUserStatus
|
||||
import com.intellij.util.system.OS
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.io.BufferedReader
|
||||
@@ -27,20 +27,19 @@ import java.io.InputStreamReader
|
||||
import java.nio.file.Path
|
||||
|
||||
object ExecUtil {
|
||||
private val hasGnomeTerminal = PathExecLazyValue.create("gnome-terminal")
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val hasKdeTerminal = PathExecLazyValue.create("konsole")
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private val hasUrxvt = PathExecLazyValue.create("urxvt")
|
||||
private val hasXTerm = PathExecLazyValue.create("xterm")
|
||||
private val hasSupportedTerminals = lazy {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
PathEnvironmentVariableUtil.isOnPath("konsole") ||
|
||||
PathEnvironmentVariableUtil.isOnPath("gnome-terminal") ||
|
||||
PathEnvironmentVariableUtil.isOnPath("urxvt") ||
|
||||
PathEnvironmentVariableUtil.isOnPath("xterm")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val osascriptPath: @NlsSafe String
|
||||
get() = "/usr/bin/osascript"
|
||||
val osascriptPath: @NlsSafe String get() = "/usr/bin/osascript"
|
||||
|
||||
@JvmStatic
|
||||
val openCommandPath: @NlsSafe String
|
||||
get() = "/usr/bin/open"
|
||||
val openCommandPath: @NlsSafe String get() = "/usr/bin/open"
|
||||
|
||||
@ApiStatus.Internal
|
||||
@JvmStatic
|
||||
@@ -167,17 +166,16 @@ object ExecUtil {
|
||||
|
||||
@ApiStatus.Internal
|
||||
@JvmStatic
|
||||
fun hasTerminalApp(): Boolean =
|
||||
SystemInfoRt.isWindows || SystemInfoRt.isMac || hasKdeTerminal.get() || hasGnomeTerminal.get() || hasUrxvt.get() || hasXTerm.get()
|
||||
fun hasTerminalApp(): Boolean = OS.CURRENT == OS.Windows || OS.CURRENT == OS.macOS || hasSupportedTerminals.value
|
||||
|
||||
@ApiStatus.Internal
|
||||
@JvmStatic
|
||||
@Suppress("SpellCheckingInspection")
|
||||
fun getTerminalCommand(@Nls(capitalization = Nls.Capitalization.Title) title: String?, command: String): List<@NlsSafe String> = when {
|
||||
SystemInfoRt.isWindows -> {
|
||||
OS.CURRENT == OS.Windows -> {
|
||||
listOf(CommandLineUtil.getWinShellName(), "/c", "start", GeneralCommandLine.inescapableQuote(title?.replace('"', '\'') ?: ""), command)
|
||||
}
|
||||
SystemInfoRt.isMac -> {
|
||||
OS.CURRENT == OS.macOS -> {
|
||||
val prefix = if (title != null) "\"echo -n \" & " + escapeAppleScriptArgument("\\0033]0;${title}\\007") + " & \" ; \" & " else ""
|
||||
val script = prefix + "\"clear ; exec \" & " + escapeAppleScriptArgument(command)
|
||||
listOf(osascriptPath, "-e", """
|
||||
@@ -187,24 +185,24 @@ object ExecUtil {
|
||||
|end tell
|
||||
""".trimMargin())
|
||||
}
|
||||
hasKdeTerminal.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("konsole") -> {
|
||||
if (title != null) listOf("konsole", "-p", "tabtitle=\"${title.replace('"', '\'')}\"", "-e", command)
|
||||
else listOf("konsole", "-e", command)
|
||||
}
|
||||
hasGnomeTerminal.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("gnome-terminal") -> {
|
||||
if (title != null) listOf("gnome-terminal", "-t", title, "-x", command)
|
||||
else listOf("gnome-terminal", "-x", command)
|
||||
}
|
||||
hasUrxvt.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("urxvt") -> {
|
||||
if (title != null) listOf("urxvt", "-title", title, "-e", command)
|
||||
else listOf("urxvt", "-e", command)
|
||||
}
|
||||
hasXTerm.get() -> {
|
||||
PathEnvironmentVariableUtil.isOnPath("xterm") -> {
|
||||
if (title != null) listOf("xterm", "-T", title, "-e", command)
|
||||
else listOf("xterm", "-e", command)
|
||||
}
|
||||
else -> {
|
||||
throw UnsupportedOperationException("Unsupported OS/desktop: ${SystemInfoRt.OS_NAME}/${System.getenv("XDG_CURRENT_DESKTOP")}")
|
||||
throw UnsupportedOperationException("Unsupported OS/desktop: ${OS.CURRENT.name}/${System.getenv("XDG_CURRENT_DESKTOP")}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -423,6 +423,8 @@ com.intellij.util.keyFMap.KeyFMap
|
||||
- a:minus(com.intellij.openapi.util.Key):com.intellij.util.keyFMap.KeyFMap
|
||||
- a:plus(com.intellij.openapi.util.Key,java.lang.Object):com.intellij.util.keyFMap.KeyFMap
|
||||
- a:size():I
|
||||
e:com.intellij.util.system.OS
|
||||
- s:isGenericUnix():Z
|
||||
com.intellij.util.xmlb.Accessor
|
||||
- a:getAnnotation(java.lang.Class):java.lang.annotation.Annotation
|
||||
- a:getGenericType():java.lang.reflect.Type
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.util;
|
||||
|
||||
import com.intellij.openapi.util.io.PathExecLazyValue;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.util.text.Strings;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -12,8 +11,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.intellij.openapi.util.NotNullLazyValue.lazy;
|
||||
|
||||
/**
|
||||
* Provides information about operating system, system-wide settings, and Java Runtime.
|
||||
@@ -68,18 +70,16 @@ public final class SystemInfo {
|
||||
public static final boolean isWin11OrNewer = isWindows && isOsVersionAtLeast("11.0");
|
||||
|
||||
/**
|
||||
* Set to true if we are running in a Wayland environment, either through
|
||||
* XWayland or using Wayland directly.
|
||||
* Set to true if we are running in a Wayland environment, either through XWayland or using Wayland directly.
|
||||
*/
|
||||
public static final boolean isWayland;
|
||||
public static final boolean isXWindow = SystemInfoRt.isUnix && !SystemInfoRt.isMac;
|
||||
public static final boolean isGNOME, isKDE, isXfce, isI3;
|
||||
static {
|
||||
// http://askubuntu.com/questions/72549/how-to-determine-which-window-manager-is-running/227669#227669
|
||||
// https://userbase.kde.org/KDE_System_Administration/Environment_Variables#KDE_FULL_SESSION
|
||||
if (SystemInfoRt.isUnix && !SystemInfoRt.isMac) {
|
||||
if (!isWindows && !isMac) {
|
||||
isWayland = System.getenv("WAYLAND_DISPLAY") != null;
|
||||
@SuppressWarnings("SpellCheckingInspection") String desktop = System.getenv("XDG_CURRENT_DESKTOP"), gdmSession = System.getenv("GDMSESSION");
|
||||
@SuppressWarnings({"SpellCheckingInspection", "RedundantSuppression"}) String desktop = System.getenv("XDG_CURRENT_DESKTOP"), gdmSession = System.getenv("GDMSESSION");
|
||||
isGNOME = desktop != null && desktop.contains("GNOME") || gdmSession != null && gdmSession.contains("gnome");
|
||||
isKDE = !isGNOME && (desktop != null && desktop.contains("KDE") || System.getenv("KDE_FULL_SESSION") != null);
|
||||
isXfce = !isGNOME && !isKDE && (desktop != null && desktop.contains("XFCE"));
|
||||
@@ -94,14 +94,16 @@ public final class SystemInfo {
|
||||
|
||||
public static final boolean isFileSystemCaseSensitive = SystemInfoRt.isFileSystemCaseSensitive;
|
||||
|
||||
private static final Supplier<Boolean> ourHasXdgOpen = SystemInfoRt.isUnix && !SystemInfoRt.isMac
|
||||
? PathExecLazyValue.create("xdg-open") : () -> false;
|
||||
/** @deprecated use {@link com.intellij.execution.configurations.PathEnvironmentVariableUtil#isOnPath} instead */
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval
|
||||
public static boolean hasXdgOpen() {
|
||||
return ourHasXdgOpen.get();
|
||||
}
|
||||
|
||||
private static final Supplier<Boolean> ourHasXdgMime = SystemInfoRt.isUnix && !SystemInfoRt.isMac
|
||||
? PathExecLazyValue.create("xdg-mime") : () -> false;
|
||||
/** @deprecated use {@link com.intellij.execution.configurations.PathEnvironmentVariableUtil#isOnPath} instead */
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval
|
||||
public static boolean hasXdgMime() {
|
||||
return ourHasXdgMime.get();
|
||||
}
|
||||
@@ -203,5 +205,25 @@ public final class SystemInfo {
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval
|
||||
public static final boolean is64Bit = CpuArch.CURRENT.width == 64;
|
||||
|
||||
/** @deprecated misleading; consider using {@link com.intellij.util.system.OS#isGenericUnix} instead, if appropriate */
|
||||
@Deprecated
|
||||
@ApiStatus.ScheduledForRemoval
|
||||
public static final boolean isXWindow = SystemInfoRt.isUnix && !SystemInfoRt.isMac;
|
||||
|
||||
private static final NotNullLazyValue<Boolean> ourHasXdgOpen = isUnix && !isMac ? lazy(() -> isOnPath("xdg-open")) : NotNullLazyValue.createConstantValue(false);
|
||||
private static final NotNullLazyValue<Boolean> ourHasXdgMime = isUnix && !isMac ? lazy(() -> isOnPath("xdg-mime")) : NotNullLazyValue.createConstantValue(false);
|
||||
|
||||
private static boolean isOnPath(String name) {
|
||||
String path = System.getenv("PATH");
|
||||
if (path != null) {
|
||||
for (String dir : StringUtil.tokenize(path, ":")) {
|
||||
if (Files.isExecutable(Paths.get(dir, name))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//</editor-fold>
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.openapi.util.io;
|
||||
|
||||
import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.util.text.Strings;
|
||||
import com.intellij.util.EnvironmentUtil;
|
||||
import com.intellij.util.concurrency.SynchronizedClearableLazy;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public final class PathExecLazyValue {
|
||||
private PathExecLazyValue() { }
|
||||
|
||||
public static @NotNull Supplier<Boolean> create(@NlsSafe @NotNull String name) {
|
||||
if (Strings.containsAnyChar(name, "/\\")) {
|
||||
throw new IllegalArgumentException(name);
|
||||
}
|
||||
|
||||
return new SynchronizedClearableLazy<>(() -> {
|
||||
String path = EnvironmentUtil.getValue("PATH");
|
||||
if (path != null) {
|
||||
for (String dir : StringUtil.tokenize(path, File.pathSeparator)) {
|
||||
if (new File(dir, name).canExecute()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.util.system;
|
||||
|
||||
import com.intellij.execution.Platform;
|
||||
@@ -49,4 +49,11 @@ public enum OS {
|
||||
public @NotNull Platform getPlatform() {
|
||||
return this == Windows ? Platform.WINDOWS : Platform.UNIX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the current operating system is a generic Unix-like system (not Windows or macOS).
|
||||
*/
|
||||
public static boolean isGenericUnix() {
|
||||
return CURRENT != Windows && CURRENT != macOS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// 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.intellij.openapi.util.io
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
class PathExecLazyValueTest {
|
||||
@Test fun positive() {
|
||||
val shell = File(if (SystemInfo.isWindows) "C:\\Windows\\System32\\cmd.exe" else "/bin/sh")
|
||||
assertTrue(shell.canExecute())
|
||||
assertTrue(PathExecLazyValue.create(shell.name).get())
|
||||
}
|
||||
|
||||
@Test fun negative() {
|
||||
assertFalse(PathExecLazyValue.create("no-one-in-his-right-mind-names-an-exec-like-this").get())
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class) fun contract() {
|
||||
PathExecLazyValue.create("bad\\path")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user