Skip to content

Commit acfd0fa

Browse files
authored
Add notification for test and run if config warning (#5430)
* Add notification for test if config warning * Change utility fn name and add TODO * Show notification for run as well * WIP * Read config warning directly and move test check * Fix doc about config warning
1 parent 3a16f12 commit acfd0fa

File tree

12 files changed

+162
-21
lines changed

12 files changed

+162
-21
lines changed

src/io/flutter/FlutterMessages.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package io.flutter;
77

88
import com.intellij.notification.Notification;
9+
import com.intellij.notification.NotificationListener;
910
import com.intellij.notification.NotificationType;
1011
import com.intellij.notification.Notifications;
1112
import com.intellij.openapi.project.Project;
@@ -37,7 +38,7 @@ public static void showWarning(String title, String message, @Nullable Project p
3738
FLUTTER_NOTIFICATION_GROUP_ID,
3839
title,
3940
message,
40-
NotificationType.WARNING), project);
41+
NotificationType.WARNING, NotificationListener.URL_OPENING_LISTENER), project);
4142
}
4243

4344
public static void showInfo(String title, String message, @Nullable Project project) {

src/io/flutter/bazel/PluginConfig.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ String getRequiredIJPluginMessage() {
7979
return fields.requiredIJPluginMessage;
8080
}
8181

82+
@Nullable
83+
String getConfigWarningPrefix() {
84+
return fields.configWarningPrefix;
85+
}
86+
8287
@Override
8388
public boolean equals(Object obj) {
8489
if (!(obj instanceof PluginConfig)) return false;
@@ -137,7 +142,8 @@ public static PluginConfig forTest(
137142
@Nullable String sdkHome,
138143
@Nullable String versionFile,
139144
@Nullable String requiredIJPluginID,
140-
@Nullable String requiredIJPluginMessage
145+
@Nullable String requiredIJPluginMessage,
146+
@Nullable String configWarningPrefix
141147
) {
142148
final Fields fields = new Fields(
143149
daemonScript,
@@ -148,7 +154,8 @@ public static PluginConfig forTest(
148154
sdkHome,
149155
versionFile,
150156
requiredIJPluginID,
151-
requiredIJPluginMessage
157+
requiredIJPluginMessage,
158+
configWarningPrefix
152159
);
153160
return new PluginConfig(fields);
154161
}
@@ -211,6 +218,12 @@ private static class Fields {
211218
@SerializedName("requiredIJPluginMessage")
212219
private String requiredIJPluginMessage;
213220

221+
/**
222+
* The prefix that indicates a configuration warning message.
223+
*/
224+
@SerializedName("configWarningPrefix")
225+
private String configWarningPrefix;
226+
214227
Fields() {
215228
}
216229

@@ -225,7 +238,8 @@ private static class Fields {
225238
String sdkHome,
226239
String versionFile,
227240
String requiredIJPluginID,
228-
String requiredIJPluginMessage) {
241+
String requiredIJPluginMessage,
242+
String configWarningPrefix) {
229243
this.daemonScript = daemonScript;
230244
this.doctorScript = doctorScript;
231245
this.testScript = testScript;
@@ -235,6 +249,7 @@ private static class Fields {
235249
this.versionFile = versionFile;
236250
this.requiredIJPluginID = requiredIJPluginID;
237251
this.requiredIJPluginMessage = requiredIJPluginMessage;
252+
this.configWarningPrefix = configWarningPrefix;
238253
}
239254

240255
@Override
@@ -249,13 +264,14 @@ public boolean equals(Object obj) {
249264
&& Objects.equal(sdkHome, other.sdkHome)
250265
&& Objects.equal(versionFile, other.versionFile)
251266
&& Objects.equal(requiredIJPluginID, other.requiredIJPluginID)
252-
&& Objects.equal(requiredIJPluginMessage, other.requiredIJPluginMessage);
267+
&& Objects.equal(requiredIJPluginMessage, other.requiredIJPluginMessage)
268+
&& Objects.equal(configWarningPrefix, other.configWarningPrefix);
253269
}
254270

255271
@Override
256272
public int hashCode() {
257273
return Objects.hashCode(daemonScript, doctorScript, testScript, runScript, syncScript, sdkHome, versionFile, requiredIJPluginID,
258-
requiredIJPluginMessage);
274+
requiredIJPluginMessage, configWarningPrefix);
259275
}
260276
}
261277

src/io/flutter/bazel/Workspace.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class Workspace {
4747
@Nullable private final String versionFile;
4848
@Nullable private final String requiredIJPluginID;
4949
@Nullable private final String requiredIJPluginMessage;
50+
@Nullable private final String configWarningPrefix;
5051

5152
private Workspace(@NotNull VirtualFile root,
5253
@Nullable PluginConfig config,
@@ -58,7 +59,8 @@ private Workspace(@NotNull VirtualFile root,
5859
@Nullable String sdkHome,
5960
@Nullable String versionFile,
6061
@Nullable String requiredIJPluginID,
61-
@Nullable String requiredIJPluginMessage) {
62+
@Nullable String requiredIJPluginMessage,
63+
@Nullable String configWarningPrefix) {
6264
this.root = root;
6365
this.config = config;
6466
this.daemonScript = daemonScript;
@@ -70,6 +72,7 @@ private Workspace(@NotNull VirtualFile root,
7072
this.versionFile = versionFile;
7173
this.requiredIJPluginID = requiredIJPluginID;
7274
this.requiredIJPluginMessage = requiredIJPluginMessage;
75+
this.configWarningPrefix = configWarningPrefix;
7376
}
7477

7578
/**
@@ -193,6 +196,14 @@ public String getRequiredIJPluginMessage() {
193196
return requiredIJPluginMessage;
194197
}
195198

199+
/**
200+
* Returns the prefix associated with configuration warnings.
201+
*/
202+
@Nullable
203+
public String getConfigWarningPrefix() {
204+
return configWarningPrefix;
205+
}
206+
196207
/**
197208
* Returns true if the plugin config was loaded.
198209
*/
@@ -270,7 +281,9 @@ static Workspace loadUncached(@NotNull Project project) {
270281

271282
final String requiredIJPluginMessage = config == null ? null : getScriptFromPath(root, readonlyPath, config.getRequiredIJPluginMessage());
272283

273-
return new Workspace(root, config, daemonScript, doctorScript, testScript, runScript, syncScript, sdkHome, versionFile, requiredIJPluginID, requiredIJPluginMessage);
284+
final String configWarningPrefix = config == null ? null : config.getConfigWarningPrefix();
285+
286+
return new Workspace(root, config, daemonScript, doctorScript, testScript, runScript, syncScript, sdkHome, versionFile, requiredIJPluginID, requiredIJPluginMessage, configWarningPrefix);
274287
}
275288

276289
@VisibleForTesting
@@ -286,7 +299,8 @@ public static Workspace forTest(VirtualFile workspaceRoot, PluginConfig pluginCo
286299
pluginConfig.getSdkHome(),
287300
pluginConfig.getVersionFile(),
288301
pluginConfig.getRequiredIJPluginID(),
289-
pluginConfig.getRequiredIJPluginMessage());
302+
pluginConfig.getRequiredIJPluginMessage(),
303+
pluginConfig.getConfigWarningPrefix());
290304
}
291305

292306
/**

src/io/flutter/run/bazelTest/BazelTestRunner.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,18 @@
3535
import com.intellij.xdebugger.XDebuggerManager;
3636
import com.jetbrains.lang.dart.sdk.DartSdkLibUtil;
3737
import com.jetbrains.lang.dart.util.DartUrlResolver;
38+
import io.flutter.FlutterMessages;
3839
import io.flutter.FlutterUtils;
3940
import io.flutter.ObservatoryConnector;
41+
import io.flutter.bazel.Workspace;
42+
import io.flutter.bazel.WorkspaceCache;
4043
import io.flutter.run.FlutterPositionMapper;
4144
import io.flutter.run.common.CommonTestConfigUtils;
4245
import io.flutter.run.test.FlutterTestRunner;
4346
import io.flutter.settings.FlutterSettings;
4447
import io.flutter.utils.JsonUtils;
4548
import io.flutter.utils.StdoutJsonParser;
49+
import io.flutter.utils.UrlUtils;
4650
import org.apache.commons.lang.StringUtils;
4751
import org.jetbrains.annotations.NotNull;
4852
import org.jetbrains.annotations.Nullable;
@@ -81,7 +85,7 @@ protected RunContentDescriptor runInDebugger(@NotNull BazelTestLaunchState launc
8185
throws ExecutionException {
8286
// Start process and create console.
8387
final ExecutionResult executionResult = launcher.execute(env.getExecutor(), this);
84-
final Connector connector = new Connector(executionResult.getProcessHandler());
88+
final Connector connector = new Connector(executionResult.getProcessHandler(), env.getProject());
8589

8690
// Set up source file mapping.
8791
final DartUrlResolver resolver = DartUrlResolver.getInstance(env.getProject(), launcher.getTestFile());
@@ -118,15 +122,26 @@ private static final class Connector implements ObservatoryConnector {
118122
private static final String RUNFILES_DIR_KEY = "runfilesDir";
119123
private static final String WORKSPACE_DIR_NAME_KEY = "workspaceDirName";
120124

121-
public Connector(ProcessHandler handler) {
125+
public Connector(ProcessHandler handler, Project project) {
126+
Workspace workspace = WorkspaceCache.getInstance(project).get();
127+
assert(workspace != null);
128+
String configWarningPrefix = workspace.getConfigWarningPrefix();
122129
listener = new ProcessAdapter() {
123130
@Override
124131
public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
132+
final String text = event.getText();
133+
if (configWarningPrefix != null && text.startsWith(configWarningPrefix)) {
134+
FlutterMessages.showWarning(
135+
"Configuration warning",
136+
UrlUtils.generateHtmlFragmentWithHrefTags(text.substring(configWarningPrefix.length())),
137+
null
138+
);
139+
}
140+
125141
if (!outputType.equals(ProcessOutputTypes.STDOUT)) {
126142
return;
127143
}
128144

129-
final String text = event.getText();
130145
if (FlutterSettings.getInstance().isVerboseLogging()) {
131146
LOG.info("[<-- " + text.trim() + "]");
132147
}

src/io/flutter/run/daemon/FlutterApp.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@
2929
import com.intellij.util.EventDispatcher;
3030
import com.intellij.util.concurrency.AppExecutorUtil;
3131
import io.flutter.FlutterInitializer;
32+
import io.flutter.FlutterMessages;
3233
import io.flutter.FlutterUtils;
3334
import io.flutter.ObservatoryConnector;
35+
import io.flutter.bazel.Workspace;
36+
import io.flutter.bazel.WorkspaceCache;
3437
import io.flutter.logging.FlutterConsoleLogManager;
3538
import io.flutter.pub.PubRoot;
3639
import io.flutter.pub.PubRoots;
@@ -42,6 +45,7 @@
4245
import io.flutter.utils.MostlySilentColoredProcessHandler;
4346
import io.flutter.utils.ProgressHelper;
4447
import io.flutter.utils.StreamSubscription;
48+
import io.flutter.utils.UrlUtils;
4549
import io.flutter.utils.VmServiceListenerAdapter;
4650
import io.flutter.vmService.DisplayRefreshRateManager;
4751
import io.flutter.vmService.ServiceExtensions;
@@ -242,7 +246,26 @@ public static FlutterApp start(@NotNull ExecutionEnvironment env,
242246
LOG.info(analyticsStart + " " + project.getName() + " (" + mode.mode() + ")");
243247
LOG.info(command.toString());
244248

245-
final ProcessHandler process = new MostlySilentColoredProcessHandler(command);
249+
Consumer<String> onTextAvailable = null;
250+
251+
if (WorkspaceCache.getInstance(project).isBazel()) {
252+
Workspace workspace = WorkspaceCache.getInstance(project).get();
253+
assert(workspace != null);
254+
String configWarningPrefix = workspace.getConfigWarningPrefix();
255+
if (configWarningPrefix != null) {
256+
onTextAvailable = text -> {
257+
if (text.startsWith(configWarningPrefix)) {
258+
FlutterMessages.showWarning(
259+
"Configuration warning",
260+
UrlUtils.generateHtmlFragmentWithHrefTags(text.substring(configWarningPrefix.length())),
261+
null
262+
);
263+
}
264+
};
265+
}
266+
}
267+
268+
final ProcessHandler process = new MostlySilentColoredProcessHandler(command, false, onTextAvailable);
246269
Disposer.register(project, process::destroyProcess);
247270

248271
// Send analytics for the start and stop events.

src/io/flutter/utils/MostlySilentColoredProcessHandler.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@
1010
import com.intellij.execution.process.BaseOSProcessHandler;
1111
import com.intellij.execution.process.ColoredProcessHandler;
1212
import com.intellij.execution.process.UnixProcessManager;
13+
import com.intellij.openapi.util.Key;
1314
import com.intellij.openapi.util.SystemInfo;
1415
import com.intellij.util.io.BaseOutputReader;
1516
import io.flutter.FlutterInitializer;
1617
import org.jetbrains.annotations.NotNull;
1718

19+
import java.util.function.Consumer;
20+
1821
/**
1922
* An {@link ColoredProcessHandler} that uses {@code BaseOutputReader.Options.forMostlySilentProcess}
2023
* in order to reduce cpu usage of the process it runs.
@@ -39,6 +42,7 @@ This determines whether a soft kill (SIGINT) is sent to the process on destroy,
3942
*/
4043
private boolean softKill;
4144
private GeneralCommandLine commandLine;
45+
private Consumer<String> onTextAvailable;
4246

4347
public MostlySilentColoredProcessHandler(@NotNull GeneralCommandLine commandLine)
4448
throws ExecutionException {
@@ -47,9 +51,15 @@ public MostlySilentColoredProcessHandler(@NotNull GeneralCommandLine commandLine
4751

4852
public MostlySilentColoredProcessHandler(@NotNull GeneralCommandLine commandLine, boolean softKill)
4953
throws ExecutionException {
54+
this(commandLine, softKill, null);
55+
}
56+
57+
public MostlySilentColoredProcessHandler(@NotNull GeneralCommandLine commandLine, boolean softKill, Consumer<String> onTextAvailable)
58+
throws ExecutionException {
5059
super(commandLine);
5160
this.softKill = softKill;
5261
this.commandLine = commandLine;
62+
this.onTextAvailable = onTextAvailable;
5363
}
5464

5565
@NotNull
@@ -72,4 +82,13 @@ protected void doDestroyProcess() {
7282
super.doDestroyProcess();
7383
}
7484
}
85+
86+
@Override
87+
public void coloredTextAvailable(@NotNull String text, @NotNull Key outputType) {
88+
super.coloredTextAvailable(text, outputType);
89+
90+
if (onTextAvailable != null) {
91+
onTextAvailable.accept(text);
92+
}
93+
}
7594
}

src/io/flutter/utils/UrlUtils.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.flutter.utils;
2+
3+
import java.net.MalformedURLException;
4+
import java.net.URL;
5+
6+
public class UrlUtils {
7+
public static String generateHtmlFragmentWithHrefTags(String input) {
8+
StringBuilder builder = new StringBuilder();
9+
for (String token : input.split(" ")) {
10+
if (builder.length() > 0) {
11+
builder.append(" ");
12+
}
13+
try {
14+
URL url = new URL(token);
15+
builder.append("<a href=\"").append(url).append("\">").append(url).append("</a>");
16+
} catch(MalformedURLException e) {
17+
builder.append(token);
18+
}
19+
}
20+
return builder.toString();
21+
}
22+
}

testSrc/unit/io/flutter/bazel/FakeWorkspaceFactory.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ public static Pair.NonNull<MockVirtualFileSystem, Workspace> createWorkspaceAndF
2424
@Nullable String sdkHome,
2525
@Nullable String versionFile,
2626
@Nullable String requiredIJPluginID,
27-
@Nullable String requiredIJPluginMessage
27+
@Nullable String requiredIJPluginMessage,
28+
@Nullable String configWarningMessage
2829
) {
2930
final MockVirtualFileSystem fs = new MockVirtualFileSystem();
3031
fs.file("/workspace/WORKSPACE", "");
@@ -55,6 +56,9 @@ public static Pair.NonNull<MockVirtualFileSystem, Workspace> createWorkspaceAndF
5556
if (requiredIJPluginMessage != null) {
5657
fs.file("/workspace/" + requiredIJPluginMessage, "");
5758
}
59+
if (configWarningMessage != null) {
60+
fs.file("/workspace/" + configWarningMessage, "");
61+
}
5862
return Pair.createNonNull(
5963
fs,
6064
Workspace.forTest(
@@ -68,7 +72,8 @@ public static Pair.NonNull<MockVirtualFileSystem, Workspace> createWorkspaceAndF
6872
sdkHome,
6973
versionFile,
7074
requiredIJPluginID,
71-
requiredIJPluginMessage
75+
requiredIJPluginMessage,
76+
configWarningMessage
7277
)
7378
)
7479
);
@@ -90,7 +95,8 @@ public static Pair.NonNull<MockVirtualFileSystem, Workspace> createWorkspaceAndF
9095
"scripts/",
9196
"flutter-version",
9297
"some.ij.plugin.id",
93-
"Some IJ Plugin ID Message"
98+
"Some IJ Plugin ID Message",
99+
"Config warning message"
94100
);
95101
}
96102
}

testSrc/unit/io/flutter/run/bazel/LaunchCommandsTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,12 @@ private static class FakeBazelFields extends BazelFields {
383383
@Nullable String sdkHome,
384384
@Nullable String versionFile,
385385
@Nullable String requiredIJPluginID,
386-
@Nullable String requiredIJPluginMessage) {
386+
@Nullable String requiredIJPluginMessage,
387+
@Nullable String configWarningMessage) {
387388
super(template);
388389
final Pair.NonNull<MockVirtualFileSystem, Workspace> pair = FakeWorkspaceFactory
389390
.createWorkspaceAndFilesystem(daemonScript, doctorScript, testScript, runScript, syncScript, sdkHome, versionFile,
390-
requiredIJPluginID, requiredIJPluginMessage);
391+
requiredIJPluginID, requiredIJPluginMessage, configWarningMessage);
391392
fs = pair.first;
392393
fakeWorkspace = pair.second;
393394
}

0 commit comments

Comments
 (0)