WEB-38925 support file watchers and external tools in WSL

We evaluate an executable path first and if it is in WSL, evaluate all
subsequent macro with a converter transforming windows paths into wsl
paths and run the command in wsl instead of windows.

(cherry picked from commit 4ffaa5443a8ac8509537d771eb97c37d43bb2272)

IJ-CR-15447

GitOrigin-RevId: e6b492dcd4ffad54bb572ddab49a94562a724592
This commit is contained in:
Dmitry Neverov
2021-10-18 14:11:00 +02:00
committed by intellij-monorepo-bot
parent 30d0fd71ad
commit 46d7d180f1
6 changed files with 142 additions and 7 deletions

View File

@@ -0,0 +1,43 @@
// 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.
package com.intellij.execution.wsl;
import com.intellij.ide.macro.MacroPathConverter;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.Strings;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.List;
@ApiStatus.Internal
public class WslMacroPathConverter implements MacroPathConverter {
private static final Logger LOG = Logger.getInstance(WslMacroPathConverter.class);
private final WSLDistribution myWsl;
public WslMacroPathConverter(@NotNull WSLDistribution wsl) {
myWsl = wsl;
}
@Override
public @NotNull String convertPath(@NotNull String path) {
try {
String converted = myWsl.getWslPath(path);
return converted != null ? converted : path;
}
catch (IllegalArgumentException e) {
LOG.warn("Failed to convert to path: " + path, e);
return path;
}
}
@Override
public @NotNull String convertPathList(@NotNull String pathList) {
List<String> paths = StringUtil.split(pathList, File.pathSeparator);
return Strings.join(ContainerUtil.map(paths, p -> convertPath(p)), ":");
}
}

View File

@@ -12,11 +12,17 @@ import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.util.ExecutionErrorDialog;
import com.intellij.execution.wsl.WSLCommandLineOptions;
import com.intellij.execution.wsl.WSLDistribution;
import com.intellij.execution.wsl.WslMacroPathConverter;
import com.intellij.execution.wsl.WslPath;
import com.intellij.ide.macro.Macro;
import com.intellij.ide.macro.MacroManager;
import com.intellij.ide.macro.MacroPathConverter;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.options.SchemeElement;
@@ -25,15 +31,14 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.execution.ParametersListUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Objects;
import java.util.*;
public class Tool implements SchemeElement {
private static final Logger LOG = Logger.getInstance(Tool.class);
@@ -334,9 +339,19 @@ public class Tool implements SchemeElement {
? new PtyCommandLine().withConsoleMode(true)
: new GeneralCommandLine();
try {
String exePath = MacroManager.getInstance().expandMacrosInString(getProgram(), true, dataContext);
exePath = MacroManager.getInstance().expandMacrosInString(exePath, false, dataContext);
if (exePath == null) return null;
WSLDistribution wsl = WslPath.getDistributionByWindowsUncPath(exePath);
MacroPathConverter pathConverter = null;
if (wsl != null) {
pathConverter = new WslMacroPathConverter(wsl);
dataContext = SimpleDataContext.getSimpleContext(MacroManager.PATH_CONVERTER_KEY, pathConverter, dataContext);
}
String paramString = MacroManager.getInstance().expandMacrosInString(getParameters(), true, dataContext);
String workingDir = MacroManager.getInstance().expandMacrosInString(getWorkingDirectory(), true, dataContext);
String exePath = MacroManager.getInstance().expandMacrosInString(getProgram(), true, dataContext);
commandLine.getParametersList().addParametersString(
MacroManager.getInstance().expandMacrosInString(paramString, false, dataContext));
@@ -344,14 +359,21 @@ public class Tool implements SchemeElement {
if (!StringUtil.isEmpty(workDirExpanded)) {
commandLine.setWorkDirectory(workDirExpanded);
}
exePath = MacroManager.getInstance().expandMacrosInString(exePath, false, dataContext);
if (exePath == null) return null;
File exeFile = new File(exePath);
if (exeFile.isDirectory() && exeFile.getName().endsWith(".app")) {
commandLine.setExePath("open");
commandLine.getParametersList().prependAll("-a", exePath);
}
else if (wsl != null) {
try {
commandLine = createWslCommandLine(CommonDataKeys.PROJECT.getData(dataContext), wsl, commandLine, workDirExpanded,
pathConverter.convertPath(exePath));
}
catch (ExecutionException e) {
LOG.error("Failed to create wsl command line", e);
}
}
else {
commandLine.setExePath(exePath);
}
@@ -388,4 +410,22 @@ public class Tool implements SchemeElement {
public String getActionIdPrefix() {
return ACTION_ID_PREFIX;
}
@NotNull
public static GeneralCommandLine createWslCommandLine(@Nullable Project project,
@NotNull WSLDistribution wsl,
@NotNull GeneralCommandLine cmd,
@Nullable String linuxWorkingDir,
@NotNull String windowsExePath) throws ExecutionException {
cmd.setExePath(windowsExePath);
WSLCommandLineOptions wslOptions = new WSLCommandLineOptions();
if (StringUtil.isNotEmpty(linuxWorkingDir)) {
wslOptions.setRemoteWorkingDirectory(linuxWorkingDir);
}
// Working directory as well as all parameters were computed with MacroPathConverter, so they are
// paths in linux. Reset working directory in command line, because linux directory is not valid
// in windows, and we will fail to start process with it.
cmd.setWorkDirectory((String)null);
return wsl.patchCommandLine(cmd, project, wslOptions);
}
}

View File

@@ -5,6 +5,7 @@ import com.intellij.ide.DataManager;
import com.intellij.ide.macro.Macro.ExecutionCancelledException;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.PlatformCoreDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditor;
@@ -27,6 +28,8 @@ public final class MacroManager {
private static final Pattern MACRO_PATTERN = Pattern.compile("\\$.+\\$");
public static final DataKey<MacroPathConverter> PATH_CONVERTER_KEY = DataKey.create("MacroPathConverter");
public static MacroManager getInstance() {
return ApplicationManager.getApplication().getService(MacroManager.class);
}
@@ -180,6 +183,7 @@ public final class MacroManager {
return null;
}
MacroPathConverter converter = dataContext.getData(PATH_CONVERTER_KEY);
while (macros.hasNext()) {
Macro macro = macros.next();
if (macro instanceof SecondQueueExpandMacro && firstQueueExpand) continue;
@@ -199,6 +203,7 @@ public final class MacroManager {
if (expanded == null) {
return null;
}
expanded = convertPathIfNeeded(converter, macro, expanded);
str = str.substring(0, index) + expanded + str.substring(index + name.length());
//noinspection AssignmentToForLoopParameter
index += expanded.length();
@@ -220,6 +225,7 @@ public final class MacroManager {
if (expanded == null) {
return null;
}
expanded = convertPathIfNeeded(converter, macro, expanded);
toReplace.put(macroNameWithParamStart + param + macroNameWithParamEnd, expanded);
i = j + macroNameWithParamEnd.length();
}
@@ -236,4 +242,17 @@ public final class MacroManager {
}
return str;
}
private static String convertPathIfNeeded(@Nullable MacroPathConverter converter, @NotNull Macro macro, @NotNull String expandedValue) {
if (converter == null) {
return expandedValue;
}
if (macro instanceof PathMacro) {
return converter.convertPath(expandedValue);
}
if (macro instanceof PathListMacro) {
return converter.convertPathList(expandedValue);
}
return expandedValue;
}
}

View File

@@ -0,0 +1,17 @@
// 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.
package com.intellij.ide.macro;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Converts paths and path lists produced by macros.
*/
@ApiStatus.Internal
public interface MacroPathConverter {
@NotNull
String convertPath(@NotNull String path);
@NotNull
String convertPathList(@NotNull String pathList);
}

View File

@@ -0,0 +1,8 @@
// 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.
package com.intellij.ide.macro;
/**
* Marker interface for {@link Macro} returning a list of paths concatenated with {@link java.io.File#pathSeparator}
*/
public interface PathListMacro {
}

View File

@@ -0,0 +1,8 @@
// 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.
package com.intellij.ide.macro;
/**
* Marker interface for {@link Macro} returning a file path
*/
public interface PathMacro {
}