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
3 changes: 3 additions & 0 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,9 @@
<projectService serviceInterface="io.flutter.devtools.DevToolsManager"
serviceImplementation="io.flutter.devtools.DevToolsManager"
overrides="false"/>
<projectService serviceInterface="io.flutter.devtools.WebDevManager"
serviceImplementation="io.flutter.devtools.WebDevManager"
overrides="false"/>

<iconProvider implementation="io.flutter.project.FlutterIconProvider" order="first"/>

Expand Down
3 changes: 3 additions & 0 deletions resources/META-INF/plugin_template.xml
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,9 @@
<projectService serviceInterface="io.flutter.devtools.DevToolsManager"
serviceImplementation="io.flutter.devtools.DevToolsManager"
overrides="false"/>
<projectService serviceInterface="io.flutter.devtools.WebDevManager"
serviceImplementation="io.flutter.devtools.WebDevManager"
overrides="false"/>

<iconProvider implementation="io.flutter.project.FlutterIconProvider" order="first"/>

Expand Down
51 changes: 48 additions & 3 deletions src/io/flutter/FlutterInitializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.flutter.analytics.Analytics;
import io.flutter.analytics.ToolWindowTracker;
import io.flutter.android.IntelliJAndroidSdk;
import io.flutter.devtools.WebDevManager;
import io.flutter.editor.FlutterSaveActionsManager;
import io.flutter.perf.FlutterWidgetPerfManager;
import io.flutter.pub.PubRoot;
Expand All @@ -32,6 +33,8 @@
import io.flutter.run.daemon.DeviceService;
import io.flutter.samples.FlutterSampleManager;
import io.flutter.sdk.FlutterPluginsLibraryManager;
import io.flutter.sdk.FlutterSdk;
import io.flutter.sdk.FlutterSdkManager;
import io.flutter.settings.FlutterSettings;
import io.flutter.utils.FlutterModuleUtils;
import io.flutter.view.FlutterPerfViewFactory;
Expand Down Expand Up @@ -82,14 +85,19 @@ public void runActivity(@NotNull Project project) {

// If the project declares a Flutter dependency, do some extra initialization.
boolean hasFlutterModule = false;
boolean hasFlutterWebModule = false;

for (Module module : ModuleManager.getInstance(project).getModules()) {
if (!FlutterModuleUtils.declaresFlutter(module)) {
final boolean declaresFlutter = FlutterModuleUtils.declaresFlutter(module);
final boolean declaresFlutterWeb = FlutterModuleUtils.declaresFlutterWeb(module);

hasFlutterModule = hasFlutterModule || declaresFlutter;
hasFlutterWebModule = hasFlutterWebModule || declaresFlutterWeb;

if (!declaresFlutter && !declaresFlutterWeb) {
continue;
}

hasFlutterModule = true;

// Ensure SDKs are configured; needed for clean module import.
FlutterModuleUtils.enableDartSDK(module);

Expand Down Expand Up @@ -119,6 +127,11 @@ public void runActivity(@NotNull Project project) {
performAndroidStudioCanaryCheck();
}

// Check if the project is a flutter web project; if so, install webdev.
if (hasFlutterWebModule) {
installWebDev(project);
}

FlutterRunNotifications.init(project);

// Start the widget perf manager.
Expand Down Expand Up @@ -188,6 +201,38 @@ public void actionPerformed(@NotNull AnActionEvent event) {
}
}

private void installWebDev(@NotNull Project project) {
final FlutterSdk flutterSdk = FlutterSdk.getFlutterSdk(project);

final WebDevManager webDevManager = WebDevManager.getInstance(project);

if (flutterSdk != null) {
if (!webDevManager.hasInstalledWebDev()) {
webDevManager.installWebdev();
}
}
else {
// Listen for sdk changes; on a valid flutter sdk, attempt to install webdev.
FlutterSdkManager.getInstance(project).addListener(new FlutterSdkManager.Listener() {
boolean installAttempted = false;

@Override
public void flutterSdkAdded() {
final FlutterSdk flutterSdk = FlutterSdk.getFlutterSdk(project);
if (flutterSdk == null) {
return;
}

if (!installAttempted && !webDevManager.hasInstalledWebDev()) {
installAttempted = true;

webDevManager.installWebdev();
}
}
});
}
}

/**
* Automatically set Android SDK based on ANDROID_HOME.
*/
Expand Down
31 changes: 21 additions & 10 deletions src/io/flutter/devtools/DevToolsManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.ide.browsers.BrowserLauncher;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import io.flutter.console.FlutterConsoles;
import io.flutter.pub.PubRoot;
import io.flutter.pub.PubRoots;
import io.flutter.sdk.FlutterCommand;
Expand Down Expand Up @@ -69,34 +71,40 @@ public CompletableFuture<Boolean> installDevTools() {

final ProgressManager progressManager = ProgressManager.getInstance();
progressManager.run(new Task.Backgroundable(project, "Installing DevTools...", true) {
OSProcessHandler processHandler;
Process process;

@Override
public void run(@NotNull ProgressIndicator indicator) {
indicator.setText(getTitle());
indicator.setIndeterminate(true);

processHandler = command.startInConsole(project);
process = command.start((ProcessOutput output) -> {
if (output.getExitCode() != 0) {
final String message = (output.getStdout() + "\n" + output.getStderr()).trim();
FlutterConsoles.displayMessage(project, null, message, true);
}
}, null);

try {
final boolean value = processHandler.waitFor();
if (value) {
final int resultCode = process.waitFor();
if (resultCode == 0) {
installedDevTools = true;
}
result.complete(value);
result.complete(resultCode == 0);
}
catch (RuntimeException re) {
catch (RuntimeException | InterruptedException re) {
if (!result.isDone()) {
result.complete(false);
}
}

processHandler = null;
process = null;
}

@Override
public void onCancel() {
if (processHandler != null && !processHandler.isProcessTerminated()) {
processHandler.destroyProcess();
if (process != null && process.isAlive()) {
process.destroy();
if (!result.isDone()) {
result.complete(false);
}
Expand Down Expand Up @@ -158,6 +166,9 @@ public static void startServer(
Callback<DevToolsInstance> onClose
) {
final FlutterCommand command = sdk.flutterPackagesPub(pubRoot, "global", "run", "devtools", "--machine", "--port=0");

// TODO(devoncarew): Refactor this so that we don't use the console to display output - this steals
// focus away from the Run (or Debug) view.
final OSProcessHandler processHandler = command.startInConsole(project);

if (processHandler == null) {
Expand All @@ -170,7 +181,7 @@ public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType
final String text = event.getText().trim();

if (text.startsWith("{") && text.endsWith("}")) {
// {"method":"server.started","params":{"host":"127.0.0.1","port":9100}}
// {"event":"server.started","params":{"host":"127.0.0.1","port":9100}}

try {
final JsonParser jsonParser = new JsonParser();
Expand Down
110 changes: 110 additions & 0 deletions src/io/flutter/devtools/WebDevManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* Copyright 2019 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
package io.flutter.devtools;

import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import io.flutter.console.FlutterConsoles;
import io.flutter.pub.PubRoot;
import io.flutter.pub.PubRoots;
import io.flutter.sdk.FlutterCommand;
import io.flutter.sdk.FlutterSdk;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
* Manage installing the webdev cli.
*/
public class WebDevManager {
public static WebDevManager getInstance(@NotNull Project project) {
return ServiceManager.getService(project, WebDevManager.class);
}

@NotNull private final Project project;

private boolean installedWebdev = false;

private WebDevManager(@NotNull Project project) {
this.project = project;
}

public boolean hasInstalledWebDev() {
return installedWebdev;
}

public CompletableFuture<Boolean> installWebdev() {
final FlutterSdk sdk = FlutterSdk.getFlutterSdk(project);
if (sdk == null) {
return createCompletedFuture(false);
}

final List<PubRoot> pubRoots = PubRoots.forProject(project);
if (pubRoots.isEmpty()) {
return createCompletedFuture(false);
}

final CompletableFuture<Boolean> result = new CompletableFuture<>();
final FlutterCommand command = sdk.flutterPackagesPub(pubRoots.get(0), "global", "activate", "webdev");

final ProgressManager progressManager = ProgressManager.getInstance();
//noinspection DialogTitleCapitalization
progressManager.run(new Task.Backgroundable(project, "Installing webdev...", true) {
Process process;

@Override
public void run(@NotNull ProgressIndicator indicator) {
indicator.setText(getTitle());
indicator.setIndeterminate(true);

process = command.start((ProcessOutput output) -> {
if (output.getExitCode() != 0) {
final String message = (output.getStdout() + "\n" + output.getStderr()).trim();
FlutterConsoles.displayMessage(project, null, message, true);
}
}, null);

try {
final int resultCode = process.waitFor();
if (resultCode == 0) {
installedWebdev = true;
}
result.complete(resultCode == 0);
}
catch (RuntimeException | InterruptedException re) {
if (!result.isDone()) {
result.complete(false);
}
}

process = null;
}

@Override
public void onCancel() {
if (process != null && process.isAlive()) {
process.destroy();
if (!result.isDone()) {
result.complete(false);
}
}
}
});

return result;
}

private CompletableFuture<Boolean> createCompletedFuture(boolean value) {
final CompletableFuture<Boolean> result = new CompletableFuture<>();
result.complete(value);
return result;
}
}
7 changes: 7 additions & 0 deletions src/io/flutter/pub/PubRoot.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,13 @@ public boolean declaresFlutter() {
return FlutterUtils.declaresFlutter(pubspec);
}

/**
* Returns true if the pubspec declares a flutter web dependency.
*/
public boolean declaresFlutterWeb() {
return FlutterUtils.declaresFlutterWeb(pubspec);
}

/**
* Returns true if the pubspec indicates that it is a Flutter plugin.
*/
Expand Down
14 changes: 9 additions & 5 deletions src/io/flutter/run/SdkFields.java
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,17 @@ public GeneralCommandLine createFlutterSdkRunCommand(@NotNull Project project,
throw new ExecutionException("Entrypoint isn't within a Flutter pub root");
}

final FlutterCommand command;
String[] args = additionalArgs == null ? new String[]{ } : additionalArgs.split(" ");
if (buildFlavor != null) {
args = ArrayUtil.append(args, "--flavor=" + buildFlavor);
if (FlutterUtils.declaresFlutterWeb(root.getPubspec())) {
command = flutterSdk.flutterRunWeb(root, runMode, args);
}
else {
if (buildFlavor != null) {
args = ArrayUtil.append(args, "--flavor=" + buildFlavor);
}
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 Down
6 changes: 2 additions & 4 deletions src/io/flutter/sdk/FlutterSdk.java
Original file line number Diff line number Diff line change
Expand Up @@ -277,15 +277,13 @@ 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) {
// TODO(devoncarew): We need to provision the webdev cli here.

public FlutterCommand flutterRunWeb(@NotNull PubRoot root, @NotNull RunMode mode, String... additionalArgs) {
// TODO(jwren): After debugging 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"); }
// See https://github.com/flutter/flutter-intellij/issues/3349.

// flutter packages pub global run webdev daemon
return new FlutterWebCommand(this, root.getRoot(), FlutterCommand.Type.FLUTTER_WEB_RUN, new String[]{ });
return new FlutterWebCommand(this, root.getRoot(), FlutterCommand.Type.FLUTTER_WEB_RUN, additionalArgs);
}

public FlutterCommand flutterRunOnTester(@NotNull PubRoot root, @NotNull String mainPath) {
Expand Down
1 change: 0 additions & 1 deletion src/io/flutter/sdk/FlutterWebCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public GeneralCommandLine createGeneralCommandLine(@Nullable Project project) {
line.setExePath(FileUtil.toSystemDependentName(sdk.getHomePath() + "/bin/" + FlutterSdkUtil.flutterScriptName()));
// flutter packages pub
line.addParameters(Type.PACKAGES_PUB.subCommand);
// TODO(devoncarew): We need to provision webdev locally.
line.addParameters("global", "run", "webdev", "daemon");
line.addParameters(args);
return line;
Expand Down
Loading