Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/io/flutter/run/LaunchState.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import io.flutter.dart.DartPlugin;
import io.flutter.logging.FlutterLog;
import io.flutter.logging.FlutterLogView;
import io.flutter.pub.PubRoot;
import io.flutter.run.bazel.BazelRunConfig;
import io.flutter.run.daemon.*;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -120,9 +121,21 @@ protected RunContentDescriptor launch(@NotNull ExecutionEnvironment env) throws
final Project project = getEnvironment().getProject();
final FlutterDevice device = DeviceService.getInstance(project).getSelectedDevice();

// If the device is null and the project is not a flutter web project, show a message that a device is required and return null.
if (device == null) {
showNoDeviceConnectedMessage(project);
return null;
boolean isFlutterWeb = false;
final String filePath = ((SdkRunConfig)runConfig).getFields().getFilePath();
if(filePath != null) {
final MainFile main = MainFile.verify(filePath, project).get();
final PubRoot root = PubRoot.forDirectory(main.getAppDir());
if (root != null) {
isFlutterWeb = FlutterUtils.declaresFlutterWeb(root.getPubspec());
}
}
if (!isFlutterWeb) {
showNoDeviceConnectedMessage(project);
return null;
}
}
final FlutterApp app = myCreateAppCallback.createApp(device);

Expand All @@ -147,7 +160,9 @@ protected RunContentDescriptor launch(@NotNull ExecutionEnvironment env) throws
}
}

device.bringToFront();
if (device != null) {
device.bringToFront();
}

// Check for and display any analysis errors when we launch an app.
if (env.getRunProfile() instanceof SdkRunConfig) {
Expand Down
10 changes: 7 additions & 3 deletions src/io/flutter/run/SdkFields.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.jetbrains.lang.dart.sdk.DartConfigurable;
import com.jetbrains.lang.dart.sdk.DartSdk;
import io.flutter.FlutterBundle;
import io.flutter.FlutterUtils;
import io.flutter.dart.DartPlugin;
import io.flutter.pub.PubRoot;
import io.flutter.run.daemon.FlutterDevice;
Expand Down Expand Up @@ -124,11 +125,14 @@ public GeneralCommandLine createFlutterSdkRunCommand(@NotNull Project project,
throw new ExecutionException("Entrypoint isn't within a Flutter pub root");
}

String[] args = additionalArgs == null ? new String[]{} : additionalArgs.split(" ");
String[] args = additionalArgs == null ? new String[]{ } : additionalArgs.split(" ");
if (buildFlavor != null) {
args = ArrayUtil.append(args, "--flavor=" + buildFlavor);
}
final FlutterCommand command = flutterSdk.flutterRun(root, main.getFile(), device, runMode, flutterLaunchMode, project, args);

final FlutterCommand command = FlutterUtils.declaresFlutterWeb(root.getPubspec()) ?
flutterSdk.flutterRunWeb(root, runMode) :
flutterSdk.flutterRun(root, main.getFile(), device, runMode, flutterLaunchMode, project, args);
return command.createGeneralCommandLine(project);
}

Expand All @@ -150,7 +154,7 @@ public GeneralCommandLine createFlutterSdkAttachCommand(@NotNull Project project
throw new ExecutionException("Entrypoint isn't within a Flutter pub root");
}

String[] args = additionalArgs == null ? new String[]{} : additionalArgs.split(" ");
String[] args = additionalArgs == null ? new String[]{ } : additionalArgs.split(" ");
if (buildFlavor != null) {
args = ArrayUtil.append(args, "--flavor=" + buildFlavor);
}
Expand Down
3 changes: 2 additions & 1 deletion src/io/flutter/run/SdkRunConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ public LaunchState getState(@NotNull Executor executor, @NotNull ExecutionEnviro
final RunMode mode = RunMode.fromEnv(env);
final Module module = ModuleUtilCore.findModuleForFile(mainFile.getFile(), env.getProject());
final LaunchState.CreateAppCallback createAppCallback = (device) -> {
if (device == null) return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does removing this check cause any problems for regular flutter apps?
An alternate that might be more robust is to create a mock ChromeBrowser Device to use for FlutterWeb.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it does not as it can't be null unless it is a FlutterWeb execution.

Adding a comment to this effect.

// Up until the FlutterWeb support, device was checked for null and returned. The device
// can only be null if this is a FlutterWeb execution, this expecation is checked elsewhere.

final GeneralCommandLine command = getCommand(env, device);
{
Expand Down
14 changes: 10 additions & 4 deletions src/io/flutter/run/daemon/FlutterApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ public class FlutterApp {
private final @NotNull Project myProject;
private final @Nullable Module myModule;
private final @NotNull RunMode myMode;
private final @NotNull FlutterDevice myDevice;
// TODO(github.com/flutter/flutter-intellij/issues/3293) myDevice is not-null for all run configurations except flutter web configurations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bug listed doesn't cover the issue. e.g. whether Device should be null for FlutterWeb.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the bug URL however is the searchable text that can be used to identify all locations in source that might want to be visited if this expectation switches (with a mocked Chrome device for instance.)

private final @Nullable FlutterDevice myDevice;
private final @NotNull ProcessHandler myProcessHandler;
private final @NotNull ExecutionEnvironment myExecutionEnvironment;
private final @NotNull DaemonApi myDaemonApi;
Expand Down Expand Up @@ -122,7 +123,7 @@ public static FlutterApp fromEnv(@NotNull ExecutionEnvironment env) {
FlutterApp(@NotNull Project project,
@Nullable Module module,
@NotNull RunMode mode,
@NotNull FlutterDevice device,
@Nullable FlutterDevice device,
@NotNull ProcessHandler processHandler,
@NotNull ExecutionEnvironment executionEnvironment,
@NotNull DaemonApi daemonApi,
Expand Down Expand Up @@ -237,7 +238,7 @@ public static FlutterApp start(@NotNull ExecutionEnvironment env,
@NotNull Project project,
@Nullable Module module,
@NotNull RunMode mode,
@NotNull FlutterDevice device,
@Nullable FlutterDevice device,
@NotNull GeneralCommandLine command,
@Nullable String analyticsStart,
@Nullable String analyticsStop)
Expand Down Expand Up @@ -593,7 +594,12 @@ public FlutterDevice device() {
}

public String deviceId() {
return myDevice.deviceId();
return myDevice != null ? myDevice.deviceId() : "";
}

// TODO this should be a temporary hack until there is some mocked out "browser" device
public boolean isWebDev() {
return myDevice == null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a TODO that this is a temp hack.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO added

}

public void setFlutterDebugProcess(FlutterDebugProcess flutterDebugProcess) {
Expand Down
67 changes: 59 additions & 8 deletions src/io/flutter/sdk/FlutterCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,28 @@ public class FlutterCommand {
@NotNull
private final List<String> args;

// TODO(github.com/flutter/flutter-intellij/issues/3293) This is a temporary "<pub-cache>/bin/webdev" that can be provided to test some
// webdev directly.
@Nullable
private final String localWebDevExe = "webdev";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this be removed before checkin?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is up to you and Devon. I'd like to land it to allow you to verify that things work as expected on someone elses' machine.

If your question is: should this be removed before users use it, then yes. This string only exists for line 267 below to change the generation of the command line from FlutterSdk (below) from flutter packages pub global run webdev serve [--debug] [--hot-reload] to webdev serve. After the appropriate Dart SDK lands in the Flutter SDK, this field should be removed.


private final boolean isFlutterWeb;

/**
* @see FlutterSdk for methods to create specific commands.
*/
FlutterCommand(@NotNull FlutterSdk sdk, @Nullable VirtualFile workDir, @NotNull Type type, String... args) {
this(sdk, workDir, type, false, args);
}

/**
* @see FlutterSdk for methods to create specific commands.
*/
FlutterCommand(@NotNull FlutterSdk sdk, @Nullable VirtualFile workDir, @NotNull Type type, boolean isFlutterWeb, String... args) {
this.sdk = sdk;
this.workDir = workDir;
this.type = type;
this.isFlutterWeb = isFlutterWeb;
this.args = ImmutableList.copyOf(args);
}

Expand Down Expand Up @@ -245,23 +260,59 @@ public OSProcessHandler startProcessOrShowError(@Nullable Project project) {
public GeneralCommandLine createGeneralCommandLine(@Nullable Project project) {
final GeneralCommandLine line = new GeneralCommandLine();
line.setCharset(CharsetToolkit.UTF8_CHARSET);
if (isFlutterWeb) {
if (workDir != null) {
line.setWorkDirectory(workDir.getPath());
}
if(localWebDevExe != null || !localWebDevExe.isEmpty()) {
line.setExePath(localWebDevExe);
line.addParameters("daemon");
if(args.contains("--debug")) {
line.addParameters("--debug");
}
if(args.contains("--hot-reload")) {
line.addParameters("--hot-reload");
}
} else {
line.setExePath(FileUtil.toSystemDependentName(sdk.getHomePath() + "/bin/" + FlutterSdkUtil.flutterScriptName()));
line.addParameters(args);
}
}
else {
line.withEnvironment(FlutterSdkUtil.FLUTTER_HOST_ENV, FlutterSdkUtil.getFlutterHostEnvValue());

line.withEnvironment(FlutterSdkUtil.FLUTTER_HOST_ENV, FlutterSdkUtil.getFlutterHostEnvValue());
final String androidHome = IntelliJAndroidSdk.chooseAndroidHome(project, false);
if (androidHome != null) {
line.withEnvironment("ANDROID_HOME", androidHome);
}

final String androidHome = IntelliJAndroidSdk.chooseAndroidHome(project, false);
if (androidHome != null) {
line.withEnvironment("ANDROID_HOME", androidHome);
line.setExePath(FileUtil.toSystemDependentName(sdk.getHomePath() + "/bin/" + FlutterSdkUtil.flutterScriptName()));
if (workDir != null) {
line.setWorkDirectory(workDir.getPath());
}
if (!isDoctorCommand()) {
line.addParameter("--no-color");
}
line.addParameters(type.subCommand);
line.addParameters(args);
}
return line;
}

/**
* Creates a FlutterWeb command line to run.
*/
@NotNull
public GeneralCommandLine createFlutterWebCommandLine(@Nullable Project project) {
final GeneralCommandLine line = new GeneralCommandLine();
line.setCharset(CharsetToolkit.UTF8_CHARSET);

line.setExePath(FileUtil.toSystemDependentName(sdk.getHomePath() + "/bin/" + FlutterSdkUtil.flutterScriptName()));
if (workDir != null) {
line.setWorkDirectory(workDir.getPath());
}
if (!isDoctorCommand()) {
line.addParameter("--no-color");
}
line.addParameters(type.subCommand);
line.addParameters(args);

return line;
}

Expand Down
12 changes: 12 additions & 0 deletions src/io/flutter/sdk/FlutterSdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,18 @@ else if (flutterLaunchMode == FlutterLaunchMode.RELEASE) {
return new FlutterCommand(this, root.getRoot(), FlutterCommand.Type.ATTACH, args.toArray(new String[]{ }));
}

public FlutterCommand flutterRunWeb(@NotNull PubRoot root, @NotNull RunMode mode) {
// flutter packages pub global run webdev serve [--debug] [--hot-reload]
final List<String> args = new ArrayList<>();
args.add("global");
args.add("run");
args.add("webdev");
args.add("daemon");
// TODO After debug is supported by webdev, this should be modified to check for debug and add any additional needed flags:
// i.e. if (mode == RunMode.DEBUG) { args.add("--debug"); }
return new FlutterCommand(this, root.getRoot(), FlutterCommand.Type.PACKAGES_PUB, true, args.toArray(new String[]{ }));
}

public FlutterCommand flutterRunOnTester(@NotNull PubRoot root, @NotNull String mainPath) {
final List<String> args = new ArrayList<>();
args.add("--machine");
Expand Down
32 changes: 19 additions & 13 deletions src/io/flutter/server/vmService/DartVmServiceDebugProcess.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import io.flutter.FlutterBundle;
import io.flutter.FlutterUtils;
import io.flutter.run.FlutterLaunchMode;
import io.flutter.run.daemon.FlutterApp;
import io.flutter.server.vmService.frame.DartVmServiceEvaluator;
import io.flutter.server.vmService.frame.DartVmServiceStackFrame;
import io.flutter.server.vmService.frame.DartVmServiceSuspendContext;
Expand Down Expand Up @@ -262,17 +263,22 @@ public void scheduleConnect() {
// because "flutter run" has already connected to it.
final VmService vmService;
final VmOpenSourceLocationListener vmOpenSourceLocationListener;
try {
vmService = VmService.connect(url);
vmOpenSourceLocationListener = VmOpenSourceLocationListener.connect(url);
}
catch (IOException | RuntimeException e) {
onConnectFailed("Failed to connect to the VM observatory service at: " + url + "\n"
+ e.toString() + "\n" +
formatStackTraces(e));
return;
// TODO(github.com/flutter/flutter-intellij/issues/3293, github.com/dart-lang/webdev/issues/233) The following check disables the
// WebSocket connection for all FlutterWeb run configurations, for some reason the WebSocket port can't be connected to, see listed
// issue above.
if (myConnector instanceof FlutterApp && (!((FlutterApp)myConnector).isWebDev())) {
try {
vmService = VmService.connect(url);
vmOpenSourceLocationListener = VmOpenSourceLocationListener.connect(url);
}
catch (IOException | RuntimeException e) {
onConnectFailed("Failed to connect to the VM observatory service at: " + url + "\n"
+ e.toString() + "\n" +
formatStackTraces(e));
return;
}
onConnectSucceeded(vmService, vmOpenSourceLocationListener);
}
onConnectSucceeded(vmService, vmOpenSourceLocationListener);
});
}

Expand Down Expand Up @@ -391,7 +397,7 @@ public void runToPosition(@NotNull XSourcePosition position, @Nullable XSuspendC

public void isolateSuspended(@NotNull final IsolateRef isolateRef) {
final String id = isolateRef.getId();
assert(!mySuspendedIsolateIds.containsKey(id));
assert (!mySuspendedIsolateIds.containsKey(id));
if (!mySuspendedIsolateIds.containsKey(id)) {
mySuspendedIsolateIds.put(id, new CompletableFuture<>());
}
Expand All @@ -406,10 +412,10 @@ public CompletableFuture<?> whenIsolateResumed(String isolateId) {
if (future == null) {
// Isolate wasn't actually suspended.
return CompletableFuture.completedFuture(null);
} else {
}
else {
return future;
}

}

public boolean isIsolateAlive(@NotNull final String isolateId) {
Expand Down