diff --git a/.travis.yml b/.travis.yml
index 2f40d76402..8cda265111 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,6 +29,5 @@ env:
- DART_BOT=true
- CHECK_BOT=true
- IDEA_VERSION=3.3.2
- - IDEA_VERSION=2018.3
- IDEA_VERSION=3.4
- IDEA_VERSION=3.5
diff --git a/flutter-studio/src/io/flutter/FlutterStudioStartupActivity.java b/flutter-studio/src/io/flutter/FlutterStudioStartupActivity.java
index fb5cd00131..f06363c112 100644
--- a/flutter-studio/src/io/flutter/FlutterStudioStartupActivity.java
+++ b/flutter-studio/src/io/flutter/FlutterStudioStartupActivity.java
@@ -26,7 +26,6 @@ public void runActivity(@NotNull Project project) {
// The IntelliJ version of this action spawns a new process for Android Studio.
// Since we're already running Android Studio we want to simply open the project in the current process.
replaceAction("flutter.androidstudio.open", new OpenAndroidModule());
- replaceAction("ShowProjectStructureSettings", new FlutterShowStructureSettingsAction());
// Unset this flag for all projects, mainly to ease the upgrade from 3.0.1 to 3.1.
// TODO(messick) Delete once 3.0.x has 0 7DA's.
FlutterProjectCreator.disableUserConfig(project);
diff --git a/product-matrix.json b/product-matrix.json
index b19ea8c957..d2d5ddd14a 100644
--- a/product-matrix.json
+++ b/product-matrix.json
@@ -14,6 +14,7 @@
"comments": "IntelliJ 2018.3, AS 3.4 beta",
"name": "Android Studio 3.4",
"version": "3.4",
+ "ijVersion": "2018.3",
"ideaProduct": "android-studio",
"ideaVersion": "183.5370308",
"dartPluginVersion": "183.5901",
@@ -24,9 +25,10 @@
"comments": "IntelliJ 2019.1, AS 3.5 canary",
"name": "Android Studio 3.5",
"version": "3.5",
+ "ijVersion": "2019.1",
"isTestTarget": "true",
"ideaProduct": "android-studio",
- "ideaVersion": "191.6183.62",
+ "ideaVersion": "191.5416148",
"dartPluginVersion": "191.6183.87",
"sinceBuild": "191.5416148",
"untilBuild": "191.*"
@@ -35,8 +37,8 @@
"comments": "IntelliJ 2019.2 EAP",
"name": "IntelliJ 2019.2 EAP",
"version": "2019.2",
- "ideaProduct": "ideaIC",
- "ideaVersion": "191.4738.6",
+ "ideaProduct": "ideaIU",
+ "ideaVersion": "2019.1",
"dartPluginVersion": "191.4899",
"sinceBuild": "192.0",
"untilBuild": "192.SNAPSHOT"
diff --git a/resources/META-INF/studio-contribs.xml b/resources/META-INF/studio-contribs.xml
index 1ea8741567..f1361e6d82 100644
--- a/resources/META-INF/studio-contribs.xml
+++ b/resources/META-INF/studio-contribs.xml
@@ -50,6 +50,11 @@
icon="AllIcons.Debugger.AttachToProcess">
+
+
diff --git a/resources/META-INF/studio-contribs_template.xml b/resources/META-INF/studio-contribs_template.xml
index f58f1dea36..f9442adcc9 100644
--- a/resources/META-INF/studio-contribs_template.xml
+++ b/resources/META-INF/studio-contribs_template.xml
@@ -48,6 +48,11 @@
icon="AllIcons.Debugger.AttachToProcess">
+
+
diff --git a/src/io/flutter/ProjectOpenActivity.java b/src/io/flutter/ProjectOpenActivity.java
index 78bc1415db..0405a535c1 100644
--- a/src/io/flutter/ProjectOpenActivity.java
+++ b/src/io/flutter/ProjectOpenActivity.java
@@ -13,6 +13,8 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectType;
+import com.intellij.openapi.project.ProjectTypeService;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.ui.Messages;
import icons.FlutterIcons;
@@ -28,6 +30,7 @@
* @see FlutterInitializer for actions that run later.
*/
public class ProjectOpenActivity implements StartupActivity, DumbAware {
+ public static final ProjectType FLUTTER_PROJECT_TYPE = new ProjectType("io.flutter");
private static final Logger LOG = Logger.getInstance(ProjectOpenActivity.class);
@Override
@@ -47,6 +50,9 @@ public void runActivity(@NotNull Project project) {
Notifications.Bus.notify(new PackagesOutOfDateNotification(project, pubRoot));
}
}
+ if (!FLUTTER_PROJECT_TYPE.equals(ProjectTypeService.getProjectType(project))) {
+ ProjectTypeService.setProjectType(project, FLUTTER_PROJECT_TYPE);
+ }
}
private static class PackagesOutOfDateNotification extends Notification {
diff --git a/tool/plugin/lib/plugin.dart b/tool/plugin/lib/plugin.dart
index f30cbcec31..d8addb8b97 100644
--- a/tool/plugin/lib/plugin.dart
+++ b/tool/plugin/lib/plugin.dart
@@ -35,6 +35,8 @@ const Map plugins = const {
'io.flutter.as': '10139', // Currently unused.
};
+const int cloudErrorFileMaxSize = 1000; // In bytes.
+
String rootPath;
int pluginCount = 0;
@@ -315,6 +317,9 @@ Future zip(String directory, String outFile) async {
return await exec('zip', args, cwd: p.dirname(directory));
}
+String _convertToTar(String path) =>
+ path.replaceFirst('.zip', '.tar.gz', path.length - 5);
+
void _copyFile(File file, Directory to, {String filename = ''}) {
if (!to.existsSync()) {
to.createSync(recursive: true);
@@ -342,6 +347,10 @@ void _copyResources(Directory from, Directory to) {
}
}
+bool _isValidDownloadArtifact(File archiveFile) =>
+ archiveFile.existsSync() &&
+ archiveFile.lengthSync() > cloudErrorFileMaxSize;
+
String _shorten(String str) {
return str.length < 200
? str
@@ -352,7 +361,7 @@ Stream _toLineStream(Stream> s, Encoding encoding) =>
s.transform(encoding.decoder).transform(const LineSplitter());
class Artifact {
- final String file;
+ String file;
final bool bareArchive;
String output;
@@ -365,6 +374,13 @@ class Artifact {
bool get isZip => file.endsWith('.zip');
String get outPath => p.join(rootPath, 'artifacts', output);
+
+ // Historically, Android Studio has been distributed as a zip file.
+ // Recent distros are packaged as gzip'd tar files.
+ void convertToTar() {
+ if (!isZip) return;
+ file = _convertToTar(file);
+ }
}
class ArtifactManager {
@@ -394,25 +410,55 @@ class ArtifactManager {
var result = 0;
for (var artifact in artifacts) {
- final path = 'artifacts/${artifact.file}';
- if (FileSystemEntity.isFileSync(path)) {
+ var doDownload = true;
+
+ void alreadyDownloaded(String path) {
log('$path exists in cache');
+ doDownload = false;
+ }
+
+ var path = 'artifacts/${artifact.file}';
+ if (FileSystemEntity.isFileSync(path)) {
+ alreadyDownloaded(path);
} else {
- log('downloading $path...');
- result = await curl('$base/${artifact.file}', to: path);
- if (result != 0) {
- log('download failed');
- break;
+ if (artifact.isZip) {
+ var tarPath = _convertToTar(path);
+ if (FileSystemEntity.isFileSync(tarPath)) {
+ artifact.convertToTar();
+ alreadyDownloaded(tarPath);
+ }
}
- var archiveFile = new File(path);
- if (!archiveFile.existsSync() || archiveFile.lengthSync() < 200) {
- // If the file is missing the server returns a small file containing
- // an error message. Delete it and fail. The smallest file we store in
- // the cloud is over 700K.
- log('archive file not found: $base/${artifact.file}');
- archiveFile.deleteSync();
- result = 1;
- break;
+ if (doDownload) {
+ log('downloading $path...');
+ result = await curl('$base/${artifact.file}', to: path);
+ if (result != 0) {
+ log('download failed');
+ break;
+ }
+ var archiveFile = new File(path);
+ if (!_isValidDownloadArtifact(archiveFile)) {
+ // If the file is missing the server returns a small file containing
+ // an error message. Delete it and try again. The smallest file we
+ // store in the cloud is over 700K.
+ log('archive file not found: $base/${artifact.file}');
+ archiveFile.deleteSync();
+ if (artifact.isZip) {
+ artifact.convertToTar();
+ path = 'artifacts/${artifact.file}';
+ result = await curl('$base/${artifact.file}', to: path);
+ if (result != 0) {
+ log('download failed');
+ break;
+ }
+ var archiveFile = new File(path);
+ if (!_isValidDownloadArtifact(archiveFile)) {
+ log('archive file not found: $base/${artifact.file}');
+ archiveFile.deleteSync();
+ result = 1;
+ break;
+ }
+ }
+ }
}
}
@@ -538,7 +584,7 @@ class BuildCommand extends ProductCommand {
// TODO: Remove this when we no longer support AS 3.3 (IJ 2018.2.5) or AS 3.4
var files = {};
var processedFile, source;
- if ((spec.version == '2018.2.5') || spec.version == '3.3.2') {
+ if (spec.version == '3.3.2') {
log('spec.version: ${spec.version}');
processedFile = File(
'flutter-studio/src/io/flutter/project/FlutterProjectCreator.java');
@@ -546,28 +592,32 @@ class BuildCommand extends ProductCommand {
files[processedFile] = source;
source = source.replaceAll('List extends File>', 'List');
processedFile.writeAsStringSync(source);
-
- if (spec.version == '2018.2.5') {
- processedFile = File(
- 'flutter-studio/src/io/flutter/profiler/FlutterStudioProfilers.java');
- source = processedFile.readAsStringSync();
- files[processedFile] = source;
- source = source.replaceAll('//changed(ProfilerAspect.DEVICES);',
- 'changed(ProfilerAspect.DEVICES);');
- processedFile.writeAsStringSync(source);
-
- processedFile = File(
- 'flutter-studio/src/io/flutter/android/AndroidModuleLibraryManager.java');
- source = processedFile.readAsStringSync();
- files[processedFile] = source;
- source = source.replaceAll(
- 'import static com.google.wireless.android.sdk.stats.GradleSyncStats.Trigger.TRIGGER_PROJECT_MODIFIED;',
- '');
- source = source.replaceAll(
- 'new GradleSyncInvoker.Request(TRIGGER_PROJECT_MODIFIED);',
- 'GradleSyncInvoker.Request.projectModified();');
- processedFile.writeAsStringSync(source);
- }
+ }
+ if (spec.version == '3.3.2' ||
+ spec.version == '3.4') {
+ log('spec.version: ${spec.version}');
+ processedFile = File(
+ 'flutter-studio/src/io/flutter/module/FlutterDescriptionProvider.java');
+ source = processedFile.readAsStringSync();
+ files[processedFile] = source;
+ source = source.replaceAll('Icon getIcon()', 'Image getIcon()');
+ source = source.replaceAll(
+ 'return FlutterIcons.AndroidStudioNewProject;',
+ 'return IconUtil.toImage(FlutterIcons.AndroidStudioNewProject);',
+ );
+ source = source.replaceAll(
+ 'return FlutterIcons.AndroidStudioNewPackage;',
+ 'return IconUtil.toImage(FlutterIcons.AndroidStudioNewPackage);',
+ );
+ source = source.replaceAll(
+ 'return FlutterIcons.AndroidStudioNewPlugin;',
+ 'return IconUtil.toImage(FlutterIcons.AndroidStudioNewPlugin);',
+ );
+ source = source.replaceAll(
+ 'return FlutterIcons.AndroidStudioNewModule;',
+ 'return IconUtil.toImage(FlutterIcons.AndroidStudioNewModule);',
+ );
+ processedFile.writeAsStringSync(source);
}
try {
@@ -627,6 +677,10 @@ class BuildCommand extends ProductCommand {
log('zip failed: ${result.toString()}');
return new Future(() => result);
}
+ if (spec.copyIjVersion && !isReleaseMode) {
+ _copyFile(File(releasesFilePath(spec)), Directory(ijVersionPath(spec)),
+ filename: 'flutter-intellij.zip');
+ }
separator('BUILT');
log('${releasesFilePath(spec)}');
}
@@ -712,6 +766,7 @@ class BuildSpec {
// Build targets
final String name;
final String version;
+ final String ijVersion;
final bool isTestTarget;
final String ideaProduct;
final String ideaVersion;
@@ -734,6 +789,7 @@ class BuildSpec {
: release = releaseNum,
name = json['name'],
version = json['version'],
+ ijVersion = json['ijVersion'] ?? null,
ideaProduct = json['ideaProduct'],
ideaVersion = json['ideaVersion'],
dartPluginVersion = json['dartPluginVersion'],
@@ -744,6 +800,8 @@ class BuildSpec {
createArtifacts();
}
+ bool get copyIjVersion => isAndroidStudio && ijVersion != null;
+
bool get isAndroidStudio => ideaProduct.contains('android-studio');
bool get isReleaseMode => release != null;
@@ -977,6 +1035,12 @@ abstract class ProductCommand extends Command {
return filePath;
}
+ String ijVersionPath(BuildSpec spec) {
+ var subDir = 'release_master';
+ var filePath = p.join(rootPath, 'releases', subDir, spec.ijVersion);
+ return filePath;
+ }
+
Future doit();
Future run() async {
diff --git a/tool/plugin/test/plugin_test.dart b/tool/plugin/test/plugin_test.dart
index cdaa9f19c6..9d169491c1 100644
--- a/tool/plugin/test/plugin_test.dart
+++ b/tool/plugin/test/plugin_test.dart
@@ -38,8 +38,7 @@ void main() {
'android-studio',
'android-studio',
'android-studio',
- 'android-studio',
- 'ideaIC',
+ 'ideaIU',
]));
});
});
@@ -55,8 +54,7 @@ void main() {
'android-studio',
'android-studio',
'android-studio',
- 'android-studio',
- 'ideaIC',
+ 'ideaIU',
]));
});
});
@@ -72,8 +70,7 @@ void main() {
'android-studio',
'android-studio',
'android-studio',
- 'android-studio',
- 'ideaIC',
+ 'ideaIU',
]));
});
});
@@ -151,7 +148,6 @@ void main() {
cmd.paths.map((p) => p.substring(p.indexOf('releases'))),
orderedEquals([
'releases/release_19/3.3.2/flutter-intellij.zip',
- 'releases/release_19/2018.3/flutter-intellij.zip',
'releases/release_19/3.4/flutter-intellij.zip',
'releases/release_19/3.5/flutter-intellij.zip',
'releases/release_19/2019.2/flutter-intellij.zip',