From 9d3bccbd6a3cdec1259ec22c3d458e91ff2179a8 Mon Sep 17 00:00:00 2001 From: Salakar Date: Sat, 22 Aug 2020 21:40:10 +0100 Subject: [PATCH 01/16] - --- bin/melos.dart | 4 + ide_templates/intellij/modules.xml.tmpl | 8 ++ .../modules/dart_package_module.iml.tmpl | 17 +++ .../flutter_app_android_java_module.iml.tmpl | 27 +++++ .../modules/flutter_app_module.iml.tmpl | 26 ++++ ...lutter_plugin_android_java_module.iml.tmpl | 26 ++++ .../modules/flutter_plugin_module.iml.tmpl | 30 +++++ .../modules/workspace_root_module.iml.tmpl | 10 ++ .../melos_package_flutter_test.xml.tmpl | 7 ++ .../melos_run_script.xml.tmpl | 11 ++ ide_templates/intellij/vcs.xml.tmpl | 6 + lib/src/command/bootstrap.dart | 114 ++++++++++++++++++ lib/src/common/package.dart | 90 ++++++++++---- lib/src/common/utils.dart | 4 + lib/src/common/workspace.dart | 2 +- pubspec.yaml | 2 +- 16 files changed, 360 insertions(+), 24 deletions(-) create mode 100644 ide_templates/intellij/modules.xml.tmpl create mode 100644 ide_templates/intellij/modules/dart_package_module.iml.tmpl create mode 100644 ide_templates/intellij/modules/flutter_app_android_java_module.iml.tmpl create mode 100644 ide_templates/intellij/modules/flutter_app_module.iml.tmpl create mode 100644 ide_templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl create mode 100644 ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl create mode 100644 ide_templates/intellij/modules/workspace_root_module.iml.tmpl create mode 100644 ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl create mode 100644 ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl create mode 100644 ide_templates/intellij/vcs.xml.tmpl diff --git a/bin/melos.dart b/bin/melos.dart index 162177697..f1a151c88 100644 --- a/bin/melos.dart +++ b/bin/melos.dart @@ -1,5 +1,9 @@ +import 'dart:io' show Platform; import 'package:melos/src/command_runner.dart'; void main(List arguments) { + if (!Platform.script.toString().contains('.pub-cache')) { + print('\n\n > USING LOCAL DEV COPY OF MELOS < \n\n'); + } MelosCommandRunner.instance.run(arguments); } diff --git a/ide_templates/intellij/modules.xml.tmpl b/ide_templates/intellij/modules.xml.tmpl new file mode 100644 index 000000000..bed32a044 --- /dev/null +++ b/ide_templates/intellij/modules.xml.tmpl @@ -0,0 +1,8 @@ + + + + +{{#modules}} + + + \ No newline at end of file diff --git a/ide_templates/intellij/modules/dart_package_module.iml.tmpl b/ide_templates/intellij/modules/dart_package_module.iml.tmpl new file mode 100644 index 000000000..d1477bf4a --- /dev/null +++ b/ide_templates/intellij/modules/dart_package_module.iml.tmpl @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/modules/flutter_app_android_java_module.iml.tmpl b/ide_templates/intellij/modules/flutter_app_android_java_module.iml.tmpl new file mode 100644 index 000000000..20173fe72 --- /dev/null +++ b/ide_templates/intellij/modules/flutter_app_android_java_module.iml.tmpl @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ide_templates/intellij/modules/flutter_app_module.iml.tmpl b/ide_templates/intellij/modules/flutter_app_module.iml.tmpl new file mode 100644 index 000000000..43512ab4f --- /dev/null +++ b/ide_templates/intellij/modules/flutter_app_module.iml.tmpl @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl b/ide_templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl new file mode 100644 index 000000000..29787d04c --- /dev/null +++ b/ide_templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl b/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl new file mode 100644 index 000000000..c2f969ba3 --- /dev/null +++ b/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/modules/workspace_root_module.iml.tmpl b/ide_templates/intellij/modules/workspace_root_module.iml.tmpl new file mode 100644 index 000000000..ca006a402 --- /dev/null +++ b/ide_templates/intellij/modules/workspace_root_module.iml.tmpl @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl b/ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl new file mode 100644 index 000000000..98c9782fd --- /dev/null +++ b/ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl b/ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl new file mode 100644 index 000000000..41565a4c2 --- /dev/null +++ b/ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/vcs.xml.tmpl b/ide_templates/intellij/vcs.xml.tmpl new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/ide_templates/intellij/vcs.xml.tmpl @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/lib/src/command/bootstrap.dart b/lib/src/command/bootstrap.dart index 6631fe254..c010b0245 100644 --- a/lib/src/command/bootstrap.dart +++ b/lib/src/command/bootstrap.dart @@ -1,9 +1,12 @@ import 'dart:io'; import 'package:args/command_runner.dart' show Command; +import 'package:meta/meta.dart'; import '../command_runner.dart'; import '../common/logger.dart'; +import '../common/package.dart'; +import '../common/utils.dart' as utils; import '../common/workspace.dart'; class BootstrapCommand extends Command { @@ -16,9 +19,120 @@ class BootstrapCommand extends Command { @override final String description = 'Initialize the workspace, link local packages together and install remaining package dependencies.'; + // TODO move me - just here for easy testing + Future initIntellijProject() async { + // TODO template cache + Future readTemplate(String fileName, + {String templateCategory}) async { + String ideTemplateDirectoryName = 'ide_templates'; + String intellijTemplateDirectoryName = 'intellij'; + String melosRootPath = utils.getMelosRoot(); + Directory intellijTemplateDirectory; + if (templateCategory != null) { + intellijTemplateDirectory = Directory( + '$melosRootPath${Platform.pathSeparator}$ideTemplateDirectoryName${Platform.pathSeparator}$intellijTemplateDirectoryName${Platform.pathSeparator}$templateCategory'); + } else { + intellijTemplateDirectory = Directory( + '$melosRootPath${Platform.pathSeparator}$ideTemplateDirectoryName${Platform.pathSeparator}$intellijTemplateDirectoryName'); + } + File templateFile = File( + '${intellijTemplateDirectory.path}${Platform.pathSeparator}$fileName.tmpl'); + return templateFile.readAsString(); + } + + String injectTemplateVariable( + {@required String sourceTemplate, + @required String variableName, + @required String variableValue}) { + return sourceTemplate.replaceAll('{{#$variableName}}', variableValue); + } + + String ideaModuleStringForName(String moduleName, {String relativePath}) { + String module = ''; + if (relativePath == null) { + module = + ''; + } else { + module = + ''; + } + // Pad to preserve formatting on generated file. Indent x6. + return ' $module'; + } + + Future writeTemplateToFile( + String filePath, String fileContents) async { + File outputFile = File(filePath); + await outputFile.create(recursive: true); + await outputFile.writeAsString(fileContents); + } + + List ideaModules = []; + String workspaceModuleName = + (currentWorkspace.config.name ?? 'melos_workspace').toLowerCase(); + Directory ideaOutputDirectory = + Directory('${currentWorkspace.path}${Platform.pathSeparator}.idea'); + + // Create a .name file if the workspace name is defined. + // This gets picked up by the IDE and is used for display purposes. + if (currentWorkspace.config.name != null) { + await writeTemplateToFile( + File('${ideaOutputDirectory.path}${Platform.pathSeparator}.name') + .path, + currentWorkspace.config.name); + } + + // Generate package modules. + await Future.forEach(currentWorkspace.packages, + (MelosPackage package) async { + String template; + if (!package.isFlutterPackage) { + template = await readTemplate('dart_package_module.iml', + templateCategory: 'modules'); + } else if (package.isFlutterApp) { + template = await readTemplate('flutter_app_module.iml', + templateCategory: 'modules'); + } else { + template = await readTemplate('flutter_plugin_module.iml', + templateCategory: 'modules'); + } + + // Generate package module. + await writeTemplateToFile( + File('${package.path}${Platform.pathSeparator}${package.name}.iml') + .path, + template); + // Add package module to modules list. + ideaModules.add(ideaModuleStringForName(package.name, + relativePath: package.pathInWorkspace)); + }); + + // Generate root module. + String ideaWorkspaceModuleImlTemplate = await readTemplate( + 'workspace_root_module.iml', + templateCategory: 'modules'); + await writeTemplateToFile( + File('${currentWorkspace.path}${Platform.pathSeparator}$workspaceModuleName.iml') + .path, + ideaWorkspaceModuleImlTemplate); + // Add root module to modules list. + ideaModules.add(ideaModuleStringForName(workspaceModuleName)); + + // Generate modules.xml + String ideaModulesXmlTemplate = await readTemplate('modules.xml'); + String generatedModulesXml = injectTemplateVariable( + sourceTemplate: ideaModulesXmlTemplate, + variableName: 'modules', + variableValue: ideaModules.join('\n')); + await writeTemplateToFile( + File('${ideaOutputDirectory.path}${Platform.pathSeparator}modules.xml') + .path, + generatedModulesXml); + } @override void run() async { + await initIntellijProject(); logger.stdout( '${logger.ansi.yellow}\$${logger.ansi.noColor} ${logger.ansi.emphasized("melos bootstrap")}'); logger.stdout( diff --git a/lib/src/common/package.dart b/lib/src/common/package.dart index 7f63b7221..738cb5d83 100644 --- a/lib/src/common/package.dart +++ b/lib/src/common/package.dart @@ -47,6 +47,9 @@ class MelosPackage { String get path => _path; + String get pathInWorkspace => + _path.replaceFirst('${currentWorkspace.path}/', ''); + MelosPackage._(this._name, this._path, this._yamlContents); Set get dependenciesSet { @@ -149,21 +152,32 @@ class MelosPackage { prefix: packagePrefix); } - // TODO(salakar): Conditionally write these files only if they exist in root. - // TODO(salakar): Only write Flutter specific files to packages that are Flutter plugins. + /// Generates Pub/Flutter related temporary files such as .packages or pubspec.lock. Future linkPackages(MelosWorkspace workspace) async { + // Dart specific files. await Future.forEach([ PackagesPubFile.fromWorkspacePackage(workspace, this), - FlutterPluginsPubFile.fromWorkspacePackage(workspace, this), PubspecLockPubFile.fromWorkspacePackage(workspace, this), PackageConfigPubFile.fromWorkspacePackage(workspace, this), - FlutterDependenciesPubFile.fromWorkspacePackage(workspace, this), ], (Future future) async { PubFile pubFile = await future; return pubFile.write(); }); + + // Additional Flutter application specific files, only if package is an App. + if (isFlutterApp) { + await Future.forEach([ + FlutterPluginsPubFile.fromWorkspacePackage(workspace, this), + FlutterDependenciesPubFile.fromWorkspacePackage(workspace, this), + ], (Future future) async { + PubFile pubFile = await future; + return pubFile.write(); + }); + } } + /// Queries the registry for published versions of this package. + /// Primarily used for publish filters and versioning. Future> getPublishedVersions() async { if (_registryVersions != null) { return _registryVersions; @@ -186,20 +200,15 @@ class MelosPackage { return _registryVersions; } + /// Cleans up all Melos generated files in this package. void clean() { PackagesPubFile.fromDirectory(path).delete(); - FlutterPluginsPubFile.fromDirectory(path).delete(); PubspecLockPubFile.fromDirectory(path).delete(); PackageConfigPubFile.fromDirectory(path).delete(); - FlutterDependenciesPubFile.fromDirectory(path).delete(); - } - - bool isFlutterPackage() { - final YamlMap dependencies = _yamlContents['dependencies'] as YamlMap; - if (dependencies == null) { - return false; + if (isFlutterPackage) { + FlutterPluginsPubFile.fromDirectory(path).delete(); + FlutterDependenciesPubFile.fromDirectory(path).delete(); } - return dependencies.containsKey('flutter'); } bool supportsFlutterPlatform(String platform) { @@ -228,27 +237,64 @@ class MelosPackage { return platforms.containsKey(platform); } - /// Returns whether the given directory contains a Flutter web plugin. - bool supportsFlutterWeb() { + /// Returns whether this package is for Flutter. + /// This is determined by whether the package depends on the Flutter SDK. + bool get isFlutterPackage { + final YamlMap dependencies = _yamlContents['dependencies'] as YamlMap; + if (dependencies == null) { + return false; + } + return dependencies.containsKey('flutter'); + } + + /// Returns whether this package is a Flutter app. + /// This is determined by ensuring all the following conditions are met: + /// a) the package depends on the Flutter SDK. + /// b) the package does not define itself as a Flutter plugin inside pubspec.yaml. + bool get isFlutterApp { + // Must directly depend on the Flutter SDK. + if (!isFlutterPackage) return false; + + // Must not have a Flutter plugin definition in it's pubspec.yaml. + final YamlMap flutterSection = _yamlContents['flutter'] as YamlMap; + if (flutterSection == null) { + return true; + } + final YamlMap pluginSection = flutterSection['plugin'] as YamlMap; + if (pluginSection == null) { + return true; + } + + // Package is a plugin not an app. + return false; + } + + /// Returns whether this package supports Flutter for Android. + bool get supportsFlutterAndroid { + return supportsFlutterPlatform(kAndroid); + } + /// Returns whether this package supports Flutter for Web. + bool get supportsFlutterWeb { return supportsFlutterPlatform(kWeb); } - /// Returns whether the given directory contains a Flutter Windows plugin. - bool supportsFlutterWindows() { + /// Returns whether this package supports Flutter for Windows. + bool get supportsFlutterWindows { return supportsFlutterPlatform(kWindows); } - /// Returns whether the given directory contains a Flutter macOS plugin. - bool isMacOsPlugin() { + /// Returns whether this package supports Flutter for MacOS. + bool get supportsFlutterMacos { return supportsFlutterPlatform(kMacos); } - /// Returns whether the given directory contains a Flutter linux plugin. - bool isLinuxPlugin() { + /// Returns whether this package supports Flutter for Linux. + bool get supportsFlutterLinux { return supportsFlutterPlatform(kLinux); } - bool isPrivate() { + /// Returns whether this package is private (publish_to set to 'none'). + bool get isPrivate { if (!_yamlContents.containsKey('publish_to')) return false; if (_yamlContents['publish_to'].runtimeType != String) return false; return _yamlContents['publish_to'] == 'none'; diff --git a/lib/src/common/utils.dart b/lib/src/common/utils.dart index cc4a0fc3c..68192810a 100644 --- a/lib/src/common/utils.dart +++ b/lib/src/common/utils.dart @@ -17,6 +17,10 @@ String getAndroidSdkRoot() { return possibleSdkRoot; } +String getMelosRoot() { + return File.fromUri(Platform.script).parent.parent.path; +} + String getFlutterSdkRoot() { var result = Process.runSync('which', ['flutter']); var possiblePath = result.stdout.toString(); diff --git a/lib/src/common/workspace.dart b/lib/src/common/workspace.dart index d8afd1a5e..5df564b75 100644 --- a/lib/src/common/workspace.dart +++ b/lib/src/common/workspace.dart @@ -137,7 +137,7 @@ class MelosWorkspace { if (skipPrivate) { // Whether we should skip packages with 'publish_to: none' set. filterResult = filterResult.where((package) { - return !package.isPrivate(); + return !package.isPrivate; }); } diff --git a/pubspec.yaml b/pubspec.yaml index d96a898a3..eaf307dbb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,7 @@ dependencies: pool: ^1.4.0 collection: ^1.14.12 string_scanner: ^1.0.5 - cli_util: ^0.1.4 + cli_util: ^0.2.0 glob: ^1.2.0 path: ^1.7.0 yaml: ^2.2.1 From fca52f49a08cdfc0bb3377532ad1737cb12b6440 Mon Sep 17 00:00:00 2001 From: Mike Diarmid Date: Sun, 23 Aug 2020 01:49:42 +0100 Subject: [PATCH 02/16] - --- .../intellij/modules/dart_package_module.iml.tmpl | 3 +-- .../intellij/modules/flutter_app_module.iml.tmpl | 2 +- .../intellij/modules/flutter_plugin_module.iml.tmpl | 3 +-- .../intellij/modules/workspace_root_module.iml.tmpl | 2 +- lib/src/command/bootstrap.dart | 11 ++++++----- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/ide_templates/intellij/modules/dart_package_module.iml.tmpl b/ide_templates/intellij/modules/dart_package_module.iml.tmpl index d1477bf4a..389d07a14 100644 --- a/ide_templates/intellij/modules/dart_package_module.iml.tmpl +++ b/ide_templates/intellij/modules/dart_package_module.iml.tmpl @@ -3,13 +3,12 @@ - + - diff --git a/ide_templates/intellij/modules/flutter_app_module.iml.tmpl b/ide_templates/intellij/modules/flutter_app_module.iml.tmpl index 43512ab4f..7e2b254ae 100644 --- a/ide_templates/intellij/modules/flutter_app_module.iml.tmpl +++ b/ide_templates/intellij/modules/flutter_app_module.iml.tmpl @@ -3,7 +3,7 @@ - + diff --git a/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl b/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl index c2f969ba3..7cf3068bc 100644 --- a/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl +++ b/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl @@ -3,8 +3,7 @@ - - + diff --git a/ide_templates/intellij/modules/workspace_root_module.iml.tmpl b/ide_templates/intellij/modules/workspace_root_module.iml.tmpl index ca006a402..8be8bf887 100644 --- a/ide_templates/intellij/modules/workspace_root_module.iml.tmpl +++ b/ide_templates/intellij/modules/workspace_root_module.iml.tmpl @@ -3,7 +3,7 @@ - + diff --git a/lib/src/command/bootstrap.dart b/lib/src/command/bootstrap.dart index c010b0245..275200f2b 100644 --- a/lib/src/command/bootstrap.dart +++ b/lib/src/command/bootstrap.dart @@ -132,7 +132,6 @@ class BootstrapCommand extends Command { @override void run() async { - await initIntellijProject(); logger.stdout( '${logger.ansi.yellow}\$${logger.ansi.noColor} ${logger.ansi.emphasized("melos bootstrap")}'); logger.stdout( @@ -159,10 +158,10 @@ class BootstrapCommand extends Command { message: '${logger.ansi.green}SUCCESS${logger.ansi.noColor}', showTiming: true); - if (currentWorkspace.config.scripts.containsKey('postbootstrap')) { - logger.stdout('Running postbootstrap script...\n'); - await MelosCommandRunner.instance.run(['run', 'postbootstrap']); - } + // if (currentWorkspace.config.scripts.containsKey('postbootstrap')) { + // logger.stdout('Running postbootstrap script...\n'); + // await MelosCommandRunner.instance.run(['run', 'postbootstrap']); + // } logger.stdout('\nPackages:'); currentWorkspace.packages.forEach((package) { @@ -173,5 +172,7 @@ class BootstrapCommand extends Command { }); logger.stdout( '\n -> ${currentWorkspace.packages.length} plugins bootstrapped'); + + await initIntellijProject(); } } From 3f2900dae84b27b9924b1f74e66f13b0f31254f0 Mon Sep 17 00:00:00 2001 From: Salakar Date: Sun, 23 Aug 2020 05:33:58 +0100 Subject: [PATCH 03/16] _ --- .../melos_package_flutter_test.xml.tmpl | 7 - lib/src/command/bootstrap.dart | 142 ++------- lib/src/command/clean.dart | 17 ++ lib/src/command/exec.dart | 17 ++ lib/src/command/run.dart | 17 ++ lib/src/command/unpublished.dart | 17 ++ lib/src/command_runner.dart | 17 ++ lib/src/common/intellij_project.dart | 231 +++++++++++++++ lib/src/common/logger.dart | 17 ++ lib/src/common/package.dart | 280 ++++++++++++------ lib/src/common/utils.dart | 31 +- lib/src/common/workspace.dart | 33 ++- lib/src/common/workspace_config.dart | 20 ++ lib/src/pub/pub_deps_list.dart | 17 ++ lib/src/pub/pub_file.dart | 17 ++ .../pub/pub_file_flutter_dependencies.dart | 17 ++ lib/src/pub/pub_file_flutter_plugins.dart | 17 ++ lib/src/pub/pub_file_package_config.dart | 17 ++ lib/src/pub/pub_file_packages.dart | 17 ++ lib/src/pub/pub_file_pubspec_lock.dart | 17 ++ .../intellij/modules.xml.tmpl | 0 .../modules/dart_package_module.iml.tmpl | 0 .../flutter_app_android_java_module.iml.tmpl | 0 .../modules/flutter_app_module.iml.tmpl | 0 ...lutter_plugin_android_java_module.iml.tmpl | 0 .../modules/flutter_plugin_module.iml.tmpl | 0 .../modules/workspace_root_module.iml.tmpl | 0 .../runConfigurations/flutter_run.xml.tmpl | 6 + .../runConfigurations/flutter_test.xml.tmpl | 7 + .../runConfigurations/melos_script.xml.tmpl | 4 +- .../intellij/vcs.xml.tmpl | 0 templates/melos/melos.yaml.tmpl | 1 + 32 files changed, 755 insertions(+), 228 deletions(-) delete mode 100644 ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl create mode 100644 lib/src/common/intellij_project.dart rename {ide_templates => templates}/intellij/modules.xml.tmpl (100%) rename {ide_templates => templates}/intellij/modules/dart_package_module.iml.tmpl (100%) rename {ide_templates => templates}/intellij/modules/flutter_app_android_java_module.iml.tmpl (100%) rename {ide_templates => templates}/intellij/modules/flutter_app_module.iml.tmpl (100%) rename {ide_templates => templates}/intellij/modules/flutter_plugin_android_java_module.iml.tmpl (100%) rename {ide_templates => templates}/intellij/modules/flutter_plugin_module.iml.tmpl (100%) rename {ide_templates => templates}/intellij/modules/workspace_root_module.iml.tmpl (100%) create mode 100644 templates/intellij/runConfigurations/flutter_run.xml.tmpl create mode 100644 templates/intellij/runConfigurations/flutter_test.xml.tmpl rename ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl => templates/intellij/runConfigurations/melos_script.xml.tmpl (71%) rename {ide_templates => templates}/intellij/vcs.xml.tmpl (100%) create mode 100644 templates/melos/melos.yaml.tmpl diff --git a/ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl b/ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl deleted file mode 100644 index 98c9782fd..000000000 --- a/ide_templates/intellij/runConfigurations/melos_package_flutter_test.xml.tmpl +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/lib/src/command/bootstrap.dart b/lib/src/command/bootstrap.dart index 275200f2b..1cc9067ae 100644 --- a/lib/src/command/bootstrap.dart +++ b/lib/src/command/bootstrap.dart @@ -1,12 +1,27 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import 'package:args/command_runner.dart' show Command; -import 'package:meta/meta.dart'; +import 'package:melos/src/common/intellij_project.dart'; import '../command_runner.dart'; import '../common/logger.dart'; -import '../common/package.dart'; -import '../common/utils.dart' as utils; import '../common/workspace.dart'; class BootstrapCommand extends Command { @@ -19,116 +34,6 @@ class BootstrapCommand extends Command { @override final String description = 'Initialize the workspace, link local packages together and install remaining package dependencies.'; - // TODO move me - just here for easy testing - Future initIntellijProject() async { - // TODO template cache - Future readTemplate(String fileName, - {String templateCategory}) async { - String ideTemplateDirectoryName = 'ide_templates'; - String intellijTemplateDirectoryName = 'intellij'; - String melosRootPath = utils.getMelosRoot(); - Directory intellijTemplateDirectory; - if (templateCategory != null) { - intellijTemplateDirectory = Directory( - '$melosRootPath${Platform.pathSeparator}$ideTemplateDirectoryName${Platform.pathSeparator}$intellijTemplateDirectoryName${Platform.pathSeparator}$templateCategory'); - } else { - intellijTemplateDirectory = Directory( - '$melosRootPath${Platform.pathSeparator}$ideTemplateDirectoryName${Platform.pathSeparator}$intellijTemplateDirectoryName'); - } - File templateFile = File( - '${intellijTemplateDirectory.path}${Platform.pathSeparator}$fileName.tmpl'); - return templateFile.readAsString(); - } - - String injectTemplateVariable( - {@required String sourceTemplate, - @required String variableName, - @required String variableValue}) { - return sourceTemplate.replaceAll('{{#$variableName}}', variableValue); - } - - String ideaModuleStringForName(String moduleName, {String relativePath}) { - String module = ''; - if (relativePath == null) { - module = - ''; - } else { - module = - ''; - } - // Pad to preserve formatting on generated file. Indent x6. - return ' $module'; - } - - Future writeTemplateToFile( - String filePath, String fileContents) async { - File outputFile = File(filePath); - await outputFile.create(recursive: true); - await outputFile.writeAsString(fileContents); - } - - List ideaModules = []; - String workspaceModuleName = - (currentWorkspace.config.name ?? 'melos_workspace').toLowerCase(); - Directory ideaOutputDirectory = - Directory('${currentWorkspace.path}${Platform.pathSeparator}.idea'); - - // Create a .name file if the workspace name is defined. - // This gets picked up by the IDE and is used for display purposes. - if (currentWorkspace.config.name != null) { - await writeTemplateToFile( - File('${ideaOutputDirectory.path}${Platform.pathSeparator}.name') - .path, - currentWorkspace.config.name); - } - - // Generate package modules. - await Future.forEach(currentWorkspace.packages, - (MelosPackage package) async { - String template; - if (!package.isFlutterPackage) { - template = await readTemplate('dart_package_module.iml', - templateCategory: 'modules'); - } else if (package.isFlutterApp) { - template = await readTemplate('flutter_app_module.iml', - templateCategory: 'modules'); - } else { - template = await readTemplate('flutter_plugin_module.iml', - templateCategory: 'modules'); - } - - // Generate package module. - await writeTemplateToFile( - File('${package.path}${Platform.pathSeparator}${package.name}.iml') - .path, - template); - // Add package module to modules list. - ideaModules.add(ideaModuleStringForName(package.name, - relativePath: package.pathInWorkspace)); - }); - - // Generate root module. - String ideaWorkspaceModuleImlTemplate = await readTemplate( - 'workspace_root_module.iml', - templateCategory: 'modules'); - await writeTemplateToFile( - File('${currentWorkspace.path}${Platform.pathSeparator}$workspaceModuleName.iml') - .path, - ideaWorkspaceModuleImlTemplate); - // Add root module to modules list. - ideaModules.add(ideaModuleStringForName(workspaceModuleName)); - - // Generate modules.xml - String ideaModulesXmlTemplate = await readTemplate('modules.xml'); - String generatedModulesXml = injectTemplateVariable( - sourceTemplate: ideaModulesXmlTemplate, - variableName: 'modules', - variableValue: ideaModules.join('\n')); - await writeTemplateToFile( - File('${ideaOutputDirectory.path}${Platform.pathSeparator}modules.xml') - .path, - generatedModulesXml); - } @override void run() async { @@ -153,15 +58,16 @@ class BootstrapCommand extends Command { var linkingProgress = logger.progress('Linking project packages'); await currentWorkspace.linkPackages(); + currentWorkspace.clean(cleanPackages: false); linkingProgress.finish( message: '${logger.ansi.green}SUCCESS${logger.ansi.noColor}', showTiming: true); - // if (currentWorkspace.config.scripts.containsKey('postbootstrap')) { - // logger.stdout('Running postbootstrap script...\n'); - // await MelosCommandRunner.instance.run(['run', 'postbootstrap']); - // } + if (currentWorkspace.config.scripts.containsKey('postbootstrap')) { + logger.stdout('Running postbootstrap script...\n'); + await MelosCommandRunner.instance.run(['run', 'postbootstrap']); + } logger.stdout('\nPackages:'); currentWorkspace.packages.forEach((package) { @@ -173,6 +79,6 @@ class BootstrapCommand extends Command { logger.stdout( '\n -> ${currentWorkspace.packages.length} plugins bootstrapped'); - await initIntellijProject(); + await IntellijProject.fromWorkspace(currentWorkspace).writeFiles(); } } diff --git a/lib/src/command/clean.dart b/lib/src/command/clean.dart index 02a511638..97d722c32 100644 --- a/lib/src/command/clean.dart +++ b/lib/src/command/clean.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'package:args/command_runner.dart' show Command; import '../command_runner.dart'; diff --git a/lib/src/command/exec.dart b/lib/src/command/exec.dart index b86725b53..16d9e66ce 100644 --- a/lib/src/command/exec.dart +++ b/lib/src/command/exec.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import 'package:args/command_runner.dart' show Command; diff --git a/lib/src/command/run.dart b/lib/src/command/run.dart index 90b0a7c4c..9dcc35ef5 100644 --- a/lib/src/command/run.dart +++ b/lib/src/command/run.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import 'package:args/command_runner.dart' show Command; diff --git a/lib/src/command/unpublished.dart b/lib/src/command/unpublished.dart index 0e7129009..f6f743f8d 100644 --- a/lib/src/command/unpublished.dart +++ b/lib/src/command/unpublished.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import 'package:args/command_runner.dart' show Command; diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart index 45e2ad6e0..ebf29a9ce 100644 --- a/lib/src/command_runner.dart +++ b/lib/src/command_runner.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import 'package:args/args.dart'; diff --git a/lib/src/common/intellij_project.dart b/lib/src/common/intellij_project.dart new file mode 100644 index 000000000..f05b9d46a --- /dev/null +++ b/lib/src/common/intellij_project.dart @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import 'dart:io'; + +import 'package:meta/meta.dart'; +import 'package:path/path.dart' show joinAll; + +import '../common/package.dart'; +import '../common/utils.dart' as utils; +import '../common/workspace.dart'; + +const String _kTemplatesDirName = 'templates'; +const String _kIntellijDirName = 'intellij'; +const String _kDotIdeaDirName = '.idea'; +const String _kTmplExtension = '.tmpl'; + +class IntellijProject { + final MelosWorkspace _workspace; + + final Map _cacheTemplates = {}; + + IntellijProject._(this._workspace); + + static IntellijProject fromWorkspace(MelosWorkspace workspace) { + return IntellijProject._(workspace); + } + + String get pathTemplates { + return joinAll([ + utils.getMelosRoot(), + _kTemplatesDirName, + _kIntellijDirName, + ]); + } + + String get pathDotIdea { + return joinAll([_workspace.path, _kDotIdeaDirName]); + } + + String get pathDotName { + return joinAll([pathDotIdea, '.name']); + } + + String get pathModulesXml { + return joinAll([pathDotIdea, 'modules.xml']); + } + + String pathTemplatesForCategory(String category) { + return joinAll([pathTemplates, category]); + } + + String pathPackageModuleIml(MelosPackage package) { + return joinAll([package.path, '${package.name}.iml']); + } + + String injectTemplateVariable( + {@required String template, + @required String variableName, + @required String variableValue}) { + return template.replaceAll('{{#$variableName}}', variableValue); + } + + String injectTemplateVariables( + String template, Map variables) { + String updatedTemplate = template; + variables.forEach((key, value) { + updatedTemplate = injectTemplateVariable( + template: updatedTemplate, variableName: key, variableValue: value); + }); + return updatedTemplate; + } + + String ideaModuleStringForName(String moduleName, {String relativePath}) { + String module = ''; + if (relativePath == null) { + module = + ''; + } else { + module = + ''; + } + // Pad to preserve formatting on generated file. Indent x6. + return ' $module'; + } + + Future cleanProject() async { + // TODO + } + + /// Reads a file template from the templates directory. + /// Additionally keeps a cache to reduce reads. + Future readFileTemplate(String fileName, + {String templateCategory}) async { + if (_cacheTemplates[fileName] != null) { + return _cacheTemplates[fileName]; + } + String templatesRootPath; + if (templateCategory != null) { + templatesRootPath = pathTemplatesForCategory(templateCategory); + } else { + templatesRootPath = pathTemplates; + } + + File templateFile = + File(joinAll([templatesRootPath, '$fileName$_kTmplExtension'])); + + String template = await templateFile.readAsString(); + _cacheTemplates[fileName] = template; + return template; + } + + Future forceWriteToFile(String filePath, String fileContents) async { + File outputFile = File(filePath); + await outputFile.create(recursive: true); + await outputFile.writeAsString(fileContents); + } + + /// Create a .name file using the workspace name. + /// This gets picked up by the IDE and is used for display purposes. + Future writeNameFile() { + return forceWriteToFile(pathDotName, _workspace.config.name); + } + + String moduleTemplateFileForPackageType(PackageType type) { + switch (type) { + case PackageType.flutterPackage: + case PackageType.flutterPlugin: + return 'flutter_plugin_module.iml'; + case PackageType.flutterApp: + return 'flutter_app_module.iml'; + case PackageType.dartPackage: + default: + return 'dart_package_module.iml'; + } + } + + Future writePackageModule(MelosPackage package) async { + String template = await readFileTemplate( + moduleTemplateFileForPackageType(package.type), + templateCategory: 'modules'); + // Generate package module. + return forceWriteToFile(pathPackageModuleIml(package), template); + } + + Future writeWorkspaceModule() async { + String ideaWorkspaceModuleImlTemplate = await readFileTemplate( + 'workspace_root_module.iml', + templateCategory: 'modules'); + String workspaceModuleName = _workspace.config.name.toLowerCase(); + return forceWriteToFile( + joinAll([_workspace.path, '$workspaceModuleName.iml']), + ideaWorkspaceModuleImlTemplate); + } + + Future writeModulesXml() async { + List ideaModules = []; + String workspaceModuleName = _workspace.config.name.toLowerCase(); + _workspace.packages.forEach((package) { + ideaModules.add(ideaModuleStringForName(package.name, + relativePath: package.pathRelativeToWorkspace)); + }); + ideaModules.add(ideaModuleStringForName(workspaceModuleName)); + String ideaModulesXmlTemplate = await readFileTemplate('modules.xml'); + String generatedModulesXml = injectTemplateVariable( + template: ideaModulesXmlTemplate, + variableName: 'modules', + variableValue: ideaModules.join('\n')); + return forceWriteToFile(pathModulesXml, generatedModulesXml); + } + + Future writeFiles() async { + // /.idea/.name + await writeNameFile(); + + // //.iml + await Future.forEach(_workspace.packages, (MelosPackage package) async { + await writePackageModule(package); + }); + + // /.iml + await writeWorkspaceModule(); + + // /.idea/modules.xml + await writeModulesXml(); + + // TODO move to own fn + // TODO flutter run scripts for apps + // TODO flutter test scripts for flutter packages (but not apps) + // TODO dart test scripts for dart packages + // Generate Melos scripts. + String melosScriptTemplate = await readFileTemplate('melos_script.xml', + templateCategory: 'runConfigurations'); + Map runConfigurations = { + 'Melos -> Bootstrap Workspace': 'bootstrap', + 'Melos -> Clean Workspace': 'clean', + }; + _workspace.config.scripts.keys.forEach((key) { + runConfigurations["Melos Run -> '$key'"] = 'run $key'; + }); + await Future.forEach(runConfigurations.keys, (String scriptName) async { + String scriptArgs = runConfigurations[scriptName]; + String generatedRunConfiguration = injectTemplateVariable( + template: melosScriptTemplate, + variableName: 'scriptName', + variableValue: scriptName); + generatedRunConfiguration = injectTemplateVariable( + template: generatedRunConfiguration, + variableName: 'scriptArgs', + variableValue: scriptArgs); + await forceWriteToFile( + File('$pathDotIdea${Platform.pathSeparator}runConfigurations${Platform.pathSeparator}melos_${scriptArgs.replaceAll(' ', '_')}.xml') + .path, + generatedRunConfiguration); + }); + } +} diff --git a/lib/src/common/logger.dart b/lib/src/common/logger.dart index 4a18c0e1d..9eb79fca0 100644 --- a/lib/src/common/logger.dart +++ b/lib/src/common/logger.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'package:cli_util/cli_logging.dart'; Logger logger = Logger.standard(); diff --git a/lib/src/common/package.dart b/lib/src/common/package.dart index 738cb5d83..6157ee96e 100644 --- a/lib/src/common/package.dart +++ b/lib/src/common/package.dart @@ -1,8 +1,26 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:yaml/yaml.dart'; +import 'package:path/path.dart' show relative, normalize; import 'package:http/http.dart' as http; import '../pub/pub_file.dart'; @@ -33,75 +51,102 @@ const String kAndroid = 'android'; /// Key for Web platform. const String kWeb = 'web'; +// Various pubspec yaml keys. +const String _kName = 'name'; +const String _kVersion = 'version'; +const String _kPublishTo = 'publish_to'; +const String _kDependencies = 'dependencies'; +const String _kDevDependencies = 'dev_dependencies'; +const String _kFlutter = 'flutter'; +const String _kPlugin = 'plugin'; + +/// Enum representing what type of package this is. +enum PackageType { + dartPackage, + flutterPackage, + flutterPlugin, + flutterApp, +} + +/// A workspace representation of a Dart package. class MelosPackage { + final MelosWorkspace _workspace; final Map _yamlContents; List _registryVersions; - final String _name; + final String _path; + /// Package name. + /// As defined in pubspec.yaml. String get name => _name; - String get version => _yamlContents['version'] as String; - - final String _path; + /// Package version. + /// As defined in pubspec.yaml. + String get version => _yamlContents[_kVersion] as String; + /// Package path. + /// Fully qualified path to this package location. String get path => _path; - String get pathInWorkspace => - _path.replaceFirst('${currentWorkspace.path}/', ''); + /// Package path as a normalized sting relative to the root of the workspace. + /// e.g. "packages/firebase_database". + String get pathRelativeToWorkspace => + normalize(relative(_path, from: _workspace.path)); + + /// Type of this package, e.g. [PackageType.flutterApp]. + PackageType get type { + if (isFlutterApp) return PackageType.flutterApp; + if (isFlutterPlugin) return PackageType.flutterPlugin; + if (isFlutterPackage) return PackageType.flutterPackage; + return PackageType.dartPackage; + } - MelosPackage._(this._name, this._path, this._yamlContents); + MelosPackage._(this._name, this._path, this._yamlContents, this._workspace); - Set get dependenciesSet { - if (_yamlContents['dependencies'] != null) { + /// Dependencies of this package. + /// Sourced from pubspec.yaml. + Map get dependencies { + if (_yamlContents[_kDependencies] != null) { // ignore: omit_local_variable_types - Set keysSet = {}; - _yamlContents['dependencies'].keys.forEach((key) { - keysSet.add(key as String); + Map deps = {}; + _yamlContents[_kDependencies].keys.forEach((key) { + deps[key as String] = _yamlContents[_kDependencies][key]; }); - return keysSet; + return deps; } return {}; } + /// Dev dependencies of this package. + /// Sourced from pubspec.yaml. Map get devDependencies { - if (_yamlContents['dev_dependencies'] != null) { + if (_yamlContents[_kDevDependencies] != null) { // ignore: omit_local_variable_types Map devDeps = {}; - _yamlContents['dev_dependencies'].keys.forEach((key) { - devDeps[key as String] = _yamlContents['dev_dependencies'][key]; + _yamlContents[_kDevDependencies].keys.forEach((key) { + devDeps[key as String] = _yamlContents[_kDevDependencies][key]; }); return devDeps; } return {}; } - Set get devDependenciesSet { - if (_yamlContents['dev_dependencies'] != null) { - // ignore: omit_local_variable_types - Set keysSet = {}; - _yamlContents['dev_dependencies'].keys.forEach((key) { - keysSet.add(key as String); - }); - return keysSet; - } - return {}; - } - - static Future fromPubspecPath( - FileSystemEntity pubspecPath) async { + /// Build a Melos representation of a package from a pubspec file. + static Future fromPubspecPathAndWorkspace( + FileSystemEntity pubspecPath, MelosWorkspace workspace) async { final yamlFileContents = await loadYamlFile(pubspecPath.path); if (yamlFileContents == null) return null; - final pluginName = yamlFileContents['name'] as String; + final pluginName = yamlFileContents[_kName] as String; return MelosPackage._( - pluginName, pubspecPath.parent.path, yamlFileContents); + pluginName, pubspecPath.parent.path, yamlFileContents, workspace); } + /// Builds a dependency graph of this packages dependencies and their dependents. Future> getDependencyGraph({bool includeDev = true}) async { var dependencyGraph = {}; - var workspaceGraph = await currentWorkspace.getDependencyGraph(); + var workspaceGraph = await _workspace.getDependencyGraph(); - dependenciesSet.forEach((name) { + dependencies.keys.toSet().forEach((name) { dependencyGraph.add(name); var children = workspaceGraph[name]; if (children != null && children.isNotEmpty) { @@ -110,7 +155,7 @@ class MelosPackage { }); if (includeDev) { - devDependenciesSet.forEach((name) { + devDependencies.keys.toSet().forEach((name) { dependencyGraph.add(name); var children = workspaceGraph[name]; if (children != null && children.isNotEmpty) { @@ -122,22 +167,25 @@ class MelosPackage { return dependencyGraph; } - /// Execute a command from this packages root directory. + /// Execute a shell command inside this package. Future exec(List execArgs) async { final packagePrefix = '[${logger.ansi.blue + logger.ansi.emphasized(_name) + logger.ansi.noColor}]: '; var environment = { 'MELOS_PACKAGE_NAME': name, - 'MELOS_PACKAGE_VERSION': version ?? '0.0.0', + 'MELOS_PACKAGE_VERSION': version ?? 'none', 'MELOS_PACKAGE_PATH': path, - 'MELOS_ROOT_PATH': currentWorkspace.path, + 'MELOS_ROOT_PATH': _workspace.path, }; + // TODO what if it's not called 'example'? if (path.endsWith('example')) { var exampleParentPackagePath = Directory(path).parent.path; - var exampleParentPackage = await fromPubspecPath(File( - '$exampleParentPackagePath${Platform.pathSeparator}pubspec.yaml')); + var exampleParentPackage = await fromPubspecPathAndWorkspace( + File( + '$exampleParentPackagePath${Platform.pathSeparator}pubspec.yaml'), + _workspace); if (exampleParentPackage != null) { environment['MELOS_PARENT_PACKAGE_NAME'] = exampleParentPackage.name; environment['MELOS_PARENT_PACKAGE_VERSION'] = @@ -176,7 +224,7 @@ class MelosPackage { } } - /// Queries the registry for published versions of this package. + /// Queries the pub.dev registry for published versions of this package. /// Primarily used for publish filters and versioning. Future> getPublishedVersions() async { if (_registryVersions != null) { @@ -200,7 +248,7 @@ class MelosPackage { return _registryVersions; } - /// Cleans up all Melos generated files in this package. + /// Cleans up all Melos generated files for this package. void clean() { PackagesPubFile.fromDirectory(path).delete(); PubspecLockPubFile.fromDirectory(path).delete(); @@ -211,40 +259,14 @@ class MelosPackage { } } - bool supportsFlutterPlatform(String platform) { - assert(platform == kIos || - platform == kAndroid || - platform == kWeb || - platform == kMacos || - platform == kWindows || - platform == kLinux); - - final YamlMap flutterSection = _yamlContents['flutter'] as YamlMap; - if (flutterSection == null) { - return false; - } - - final YamlMap pluginSection = flutterSection['plugin'] as YamlMap; - if (pluginSection == null) { - return false; - } - - final YamlMap platforms = pluginSection['platforms'] as YamlMap; - if (platforms == null) { - return false; - } - - return platforms.containsKey(platform); - } - /// Returns whether this package is for Flutter. /// This is determined by whether the package depends on the Flutter SDK. bool get isFlutterPackage { - final YamlMap dependencies = _yamlContents['dependencies'] as YamlMap; + final YamlMap dependencies = _yamlContents[_kDependencies] as YamlMap; if (dependencies == null) { return false; } - return dependencies.containsKey('flutter'); + return dependencies.containsKey(_kFlutter); } /// Returns whether this package is a Flutter app. @@ -254,50 +276,134 @@ class MelosPackage { bool get isFlutterApp { // Must directly depend on the Flutter SDK. if (!isFlutterPackage) return false; - // Must not have a Flutter plugin definition in it's pubspec.yaml. - final YamlMap flutterSection = _yamlContents['flutter'] as YamlMap; + final YamlMap flutterSection = _yamlContents[_kFlutter] as YamlMap; if (flutterSection == null) { return true; } - final YamlMap pluginSection = flutterSection['plugin'] as YamlMap; + final YamlMap pluginSection = flutterSection[_kPlugin] as YamlMap; if (pluginSection == null) { return true; } - // Package is a plugin not an app. return false; } /// Returns whether this package supports Flutter for Android. - bool get supportsFlutterAndroid { - return supportsFlutterPlatform(kAndroid); + bool get flutterAppSupportsAndroid { + if (!isFlutterApp) return false; + return _flutterAppSupportsPlatform(kAndroid); + } + + /// Returns whether this package supports Flutter for Web. + bool get flutterAppSupportsWeb { + if (!isFlutterApp) return false; + return _flutterAppSupportsPlatform(kWeb); + } + + /// Returns whether this package supports Flutter for Windows. + bool get flutterAppSupportsWindows { + if (!isFlutterApp) return false; + return _flutterAppSupportsPlatform(kWindows); + } + + /// Returns whether this package supports Flutter for MacOS. + bool get flutterAppSupportsMacos { + if (!isFlutterApp) return false; + return _flutterAppSupportsPlatform(kMacos); + } + + /// Returns whether this package supports Flutter for Linux. + bool get flutterAppSupportsLinux { + if (!isFlutterApp) return false; + return _flutterAppSupportsPlatform(kLinux); + } + + /// Returns whether this package is a Flutter plugin. + /// This is determined by whether the pubspec contains a flutter.plugin definition. + bool get isFlutterPlugin { + final YamlMap flutterSection = _yamlContents[_kFlutter] as YamlMap; + if (flutterSection == null) { + return false; + } + final YamlMap pluginSection = flutterSection[_kPlugin] as YamlMap; + if (pluginSection == null) { + return false; + } + return true; + } + + /// Returns whether this package supports Flutter for Android. + bool get flutterPluginSupportsAndroid { + if (!isFlutterPlugin) return false; + return _flutterPluginSupportsPlatform(kAndroid); } + /// Returns whether this package supports Flutter for Web. - bool get supportsFlutterWeb { - return supportsFlutterPlatform(kWeb); + bool get flutterPluginSupportsWeb { + if (!isFlutterPlugin) return false; + return _flutterPluginSupportsPlatform(kWeb); } /// Returns whether this package supports Flutter for Windows. - bool get supportsFlutterWindows { - return supportsFlutterPlatform(kWindows); + bool get flutterPluginSupportsWindows { + if (!isFlutterPlugin) return false; + return _flutterPluginSupportsPlatform(kWindows); } /// Returns whether this package supports Flutter for MacOS. - bool get supportsFlutterMacos { - return supportsFlutterPlatform(kMacos); + bool get flutterPluginSupportsMacos { + if (!isFlutterPlugin) return false; + return _flutterPluginSupportsPlatform(kMacos); } /// Returns whether this package supports Flutter for Linux. - bool get supportsFlutterLinux { - return supportsFlutterPlatform(kLinux); + bool get flutterPluginSupportsLinux { + if (!isFlutterPlugin) return false; + return _flutterPluginSupportsPlatform(kLinux); } /// Returns whether this package is private (publish_to set to 'none'). bool get isPrivate { - if (!_yamlContents.containsKey('publish_to')) return false; - if (_yamlContents['publish_to'].runtimeType != String) return false; - return _yamlContents['publish_to'] == 'none'; + if (!_yamlContents.containsKey(_kPublishTo)) return false; + if (_yamlContents[_kPublishTo].runtimeType != String) return false; + return _yamlContents[_kPublishTo] == 'none'; + } + + bool _flutterAppSupportsPlatform(String platform) { + assert(platform == kIos || + platform == kAndroid || + platform == kWeb || + platform == kMacos || + platform == kWindows || + platform == kLinux); + return File('$path${Platform.pathSeparator}$platform').existsSync(); + } + + bool _flutterPluginSupportsPlatform(String platform) { + assert(platform == kIos || + platform == kAndroid || + platform == kWeb || + platform == kMacos || + platform == kWindows || + platform == kLinux); + + final YamlMap flutterSection = _yamlContents[_kFlutter] as YamlMap; + if (flutterSection == null) { + return false; + } + + final YamlMap pluginSection = flutterSection[_kPlugin] as YamlMap; + if (pluginSection == null) { + return false; + } + + final YamlMap platforms = pluginSection['platforms'] as YamlMap; + if (platforms == null) { + return false; + } + + return platforms.containsKey(platform); } @override diff --git a/lib/src/common/utils.dart b/lib/src/common/utils.dart index 68192810a..ea804f95f 100644 --- a/lib/src/common/utils.dart +++ b/lib/src/common/utils.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:async'; import 'dart:convert'; import 'dart:io'; @@ -7,6 +24,10 @@ import 'package:yaml/yaml.dart'; import 'logger.dart'; +String getMelosRoot() { + return File.fromUri(Platform.script).parent.parent.path; +} + String getAndroidSdkRoot() { var possibleSdkRoot = Platform.environment['ANDROID_SDK_ROOT']; if (possibleSdkRoot == null) { @@ -17,10 +38,7 @@ String getAndroidSdkRoot() { return possibleSdkRoot; } -String getMelosRoot() { - return File.fromUri(Platform.script).parent.parent.path; -} - +// TODO not Windows compatible String getFlutterSdkRoot() { var result = Process.runSync('which', ['flutter']); var possiblePath = result.stdout.toString(); @@ -79,12 +97,13 @@ Future startProcess(List execArgs, final workingDirectoryPath = workingDirectory ?? Directory.current.path; final executable = - Platform.isWindows ? '%WINDIR%\\System32\\cmd.exe' : '/bin/sh'; + Platform.isWindows ? '%WINDIR%\\system32\\cmd.exe' : '/bin/sh'; final execProcess = await Process.start(executable, [], workingDirectory: workingDirectoryPath, includeParentEnvironment: true, - environment: environmentVariables); + environment: environmentVariables, + runInShell: Platform.isWindows); final execString = execArgs.map((arg) { var _arg = arg; diff --git a/lib/src/common/workspace.dart b/lib/src/common/workspace.dart index 5df564b75..29416c185 100644 --- a/lib/src/common/workspace.dart +++ b/lib/src/common/workspace.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:async'; import 'dart:io'; @@ -29,7 +46,7 @@ class MelosWorkspace { String get path => _path; - Map> _dependencyGraph; + Map> _cacheDependencyGraph; final MelosWorkspaceConfig _config; @@ -61,7 +78,6 @@ class MelosWorkspace { bool skipPrivate, bool published}) async { if (_packages != null) return Future.value(_packages); - final packageGlobs = _config.packages; var filterResult = Directory(_path) @@ -78,7 +94,7 @@ class MelosWorkspace { return matchedPattern != null; }).asyncMap((entity) { // Convert into Package for further filtering - return MelosPackage.fromPubspecPath(entity); + return MelosPackage.fromPubspecPathAndWorkspace(entity, this); }); if (scope.isNotEmpty) { @@ -169,9 +185,10 @@ class MelosWorkspace { return _packages; } + /// Builds a dependency graph of dependencies and their dependents in this workspace. Future>> getDependencyGraph() async { - if (_dependencyGraph != null) { - return _dependencyGraph; + if (_cacheDependencyGraph != null) { + return _cacheDependencyGraph; } final pubListCommandOutput = await Process.run( @@ -218,7 +235,7 @@ class MelosWorkspace { dependencyGraphFlat[entry.name] = entriesSet; }); - _dependencyGraph = dependencyGraphFlat; + _cacheDependencyGraph = dependencyGraphFlat; return dependencyGraphFlat; } @@ -242,7 +259,7 @@ class MelosWorkspace { } void clean({bool cleanPackages = true}) { - // clean workspace + // Clean workspace. PackagesPubFile.fromDirectory(path).delete(); FlutterPluginsPubFile.fromDirectory(path).delete(); PackageConfigPubFile.fromDirectory(path).delete(); @@ -292,7 +309,7 @@ class MelosWorkspace { // TODO(salakar): this is a hacky work around for dev deps - look at using // `pub cache add` etc and manually generating file:// links var devDependencies = plugin.devDependencies; - plugin.devDependenciesSet.forEach((name) { + plugin.devDependencies.keys.toSet().forEach((name) { var linkedPackageExists = packages.firstWhere((package) { return package.name == name; }, orElse: () { diff --git a/lib/src/common/workspace_config.dart b/lib/src/common/workspace_config.dart index a53825856..9d275dd3e 100644 --- a/lib/src/common/workspace_config.dart +++ b/lib/src/common/workspace_config.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import 'package:glob/glob.dart'; @@ -5,6 +22,9 @@ import 'package:yaml/yaml.dart'; import 'utils.dart'; + +// TODO validation of config +// name should be required, alphanumeric dasherized/underscoped class MelosWorkspaceConfig { final String _name; diff --git a/lib/src/pub/pub_deps_list.dart b/lib/src/pub/pub_deps_list.dart index 8b5547b55..28d331af2 100644 --- a/lib/src/pub/pub_deps_list.dart +++ b/lib/src/pub/pub_deps_list.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'package:collection/collection.dart'; import 'package:pub_semver/pub_semver.dart'; import 'package:string_scanner/string_scanner.dart'; diff --git a/lib/src/pub/pub_file.dart b/lib/src/pub/pub_file.dart index fd38429cd..de014ca8e 100644 --- a/lib/src/pub/pub_file.dart +++ b/lib/src/pub/pub_file.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; class PubFile { diff --git a/lib/src/pub/pub_file_flutter_dependencies.dart b/lib/src/pub/pub_file_flutter_dependencies.dart index bfb682d46..8b8e90e51 100644 --- a/lib/src/pub/pub_file_flutter_dependencies.dart +++ b/lib/src/pub/pub_file_flutter_dependencies.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:collection'; import 'dart:convert'; import 'dart:io'; diff --git a/lib/src/pub/pub_file_flutter_plugins.dart b/lib/src/pub/pub_file_flutter_plugins.dart index 4316e586a..cb629b578 100644 --- a/lib/src/pub/pub_file_flutter_plugins.dart +++ b/lib/src/pub/pub_file_flutter_plugins.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import '../common/package.dart'; diff --git a/lib/src/pub/pub_file_package_config.dart b/lib/src/pub/pub_file_package_config.dart index 3931f9d71..4ffcc1c20 100644 --- a/lib/src/pub/pub_file_package_config.dart +++ b/lib/src/pub/pub_file_package_config.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:collection'; import 'dart:convert'; import 'dart:io'; diff --git a/lib/src/pub/pub_file_packages.dart b/lib/src/pub/pub_file_packages.dart index e5d0604c7..511b762e4 100644 --- a/lib/src/pub/pub_file_packages.dart +++ b/lib/src/pub/pub_file_packages.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:io'; import '../common/package.dart'; diff --git a/lib/src/pub/pub_file_pubspec_lock.dart b/lib/src/pub/pub_file_pubspec_lock.dart index 9fb006782..c692dcac5 100644 --- a/lib/src/pub/pub_file_pubspec_lock.dart +++ b/lib/src/pub/pub_file_pubspec_lock.dart @@ -1,3 +1,20 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import 'dart:collection'; import 'dart:convert'; import 'dart:io'; diff --git a/ide_templates/intellij/modules.xml.tmpl b/templates/intellij/modules.xml.tmpl similarity index 100% rename from ide_templates/intellij/modules.xml.tmpl rename to templates/intellij/modules.xml.tmpl diff --git a/ide_templates/intellij/modules/dart_package_module.iml.tmpl b/templates/intellij/modules/dart_package_module.iml.tmpl similarity index 100% rename from ide_templates/intellij/modules/dart_package_module.iml.tmpl rename to templates/intellij/modules/dart_package_module.iml.tmpl diff --git a/ide_templates/intellij/modules/flutter_app_android_java_module.iml.tmpl b/templates/intellij/modules/flutter_app_android_java_module.iml.tmpl similarity index 100% rename from ide_templates/intellij/modules/flutter_app_android_java_module.iml.tmpl rename to templates/intellij/modules/flutter_app_android_java_module.iml.tmpl diff --git a/ide_templates/intellij/modules/flutter_app_module.iml.tmpl b/templates/intellij/modules/flutter_app_module.iml.tmpl similarity index 100% rename from ide_templates/intellij/modules/flutter_app_module.iml.tmpl rename to templates/intellij/modules/flutter_app_module.iml.tmpl diff --git a/ide_templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl b/templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl similarity index 100% rename from ide_templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl rename to templates/intellij/modules/flutter_plugin_android_java_module.iml.tmpl diff --git a/ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl b/templates/intellij/modules/flutter_plugin_module.iml.tmpl similarity index 100% rename from ide_templates/intellij/modules/flutter_plugin_module.iml.tmpl rename to templates/intellij/modules/flutter_plugin_module.iml.tmpl diff --git a/ide_templates/intellij/modules/workspace_root_module.iml.tmpl b/templates/intellij/modules/workspace_root_module.iml.tmpl similarity index 100% rename from ide_templates/intellij/modules/workspace_root_module.iml.tmpl rename to templates/intellij/modules/workspace_root_module.iml.tmpl diff --git a/templates/intellij/runConfigurations/flutter_run.xml.tmpl b/templates/intellij/runConfigurations/flutter_run.xml.tmpl new file mode 100644 index 000000000..70f2f6f01 --- /dev/null +++ b/templates/intellij/runConfigurations/flutter_run.xml.tmpl @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/templates/intellij/runConfigurations/flutter_test.xml.tmpl b/templates/intellij/runConfigurations/flutter_test.xml.tmpl new file mode 100644 index 000000000..aa53b9168 --- /dev/null +++ b/templates/intellij/runConfigurations/flutter_test.xml.tmpl @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl b/templates/intellij/runConfigurations/melos_script.xml.tmpl similarity index 71% rename from ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl rename to templates/intellij/runConfigurations/melos_script.xml.tmpl index 41565a4c2..fb8a28d70 100644 --- a/ide_templates/intellij/runConfigurations/melos_run_script.xml.tmpl +++ b/templates/intellij/runConfigurations/melos_script.xml.tmpl @@ -1,9 +1,9 @@ - + From c48ba53f9e299321cf1c6b00a7f902c3505efc3a Mon Sep 17 00:00:00 2001 From: Salakar Date: Mon, 24 Aug 2020 20:26:43 +0100 Subject: [PATCH 15/16] - --- bin/melos.dart | 4 ---- lib/src/command/bootstrap.dart | 18 ++++++++++++------ lib/src/command/clean.dart | 6 ++++-- lib/src/command/exec.dart | 2 +- lib/src/command_runner.dart | 1 + lib/src/common/intellij_project.dart | 10 +++++----- lib/src/common/utils.dart | 13 +++++++++++++ lib/src/common/workspace_config.dart | 3 +-- 8 files changed, 37 insertions(+), 20 deletions(-) diff --git a/bin/melos.dart b/bin/melos.dart index f1a151c88..162177697 100644 --- a/bin/melos.dart +++ b/bin/melos.dart @@ -1,9 +1,5 @@ -import 'dart:io' show Platform; import 'package:melos/src/command_runner.dart'; void main(List arguments) { - if (!Platform.script.toString().contains('.pub-cache')) { - print('\n\n > USING LOCAL DEV COPY OF MELOS < \n\n'); - } MelosCommandRunner.instance.run(arguments); } diff --git a/lib/src/command/bootstrap.dart b/lib/src/command/bootstrap.dart index 1cc9067ae..a27868c9d 100644 --- a/lib/src/command/bootstrap.dart +++ b/lib/src/command/bootstrap.dart @@ -41,6 +41,7 @@ class BootstrapCommand extends Command { '${logger.ansi.yellow}\$${logger.ansi.noColor} ${logger.ansi.emphasized("melos bootstrap")}'); logger.stdout( ' └> ${logger.ansi.cyan}${logger.ansi.emphasized(currentWorkspace.path)}${logger.ansi.noColor}\n'); + var successMessage = '${logger.ansi.green}SUCCESS${logger.ansi.noColor}'; var bootstrapProgress = logger.progress('Bootstrapping project'); await currentWorkspace.generatePubspecFile(); @@ -52,17 +53,22 @@ class BootstrapCommand extends Command { exit(1); } - bootstrapProgress.finish( - message: '${logger.ansi.green}SUCCESS${logger.ansi.noColor}', - showTiming: true); + bootstrapProgress.finish(message: successMessage, showTiming: true); + if (Platform.isWindows) { + // TODO Manual print finish status as it doesn't show on Windows, bug with progress library. + print(' > $successMessage'); + } + var linkingProgress = logger.progress('Linking project packages'); await currentWorkspace.linkPackages(); currentWorkspace.clean(cleanPackages: false); - linkingProgress.finish( - message: '${logger.ansi.green}SUCCESS${logger.ansi.noColor}', - showTiming: true); + linkingProgress.finish(message: successMessage, showTiming: true); + if (Platform.isWindows) { + // TODO Manual print finish status as it doesn't show on Windows, bug with progress library. + print(' > $successMessage'); + } if (currentWorkspace.config.scripts.containsKey('postbootstrap')) { logger.stdout('Running postbootstrap script...\n'); diff --git a/lib/src/command/clean.dart b/lib/src/command/clean.dart index 97d722c32..a37731a3a 100644 --- a/lib/src/command/clean.dart +++ b/lib/src/command/clean.dart @@ -16,6 +16,7 @@ */ import 'package:args/command_runner.dart' show Command; +import 'package:melos/src/common/intellij_project.dart'; import '../command_runner.dart'; import '../common/logger.dart'; @@ -30,17 +31,18 @@ class CleanCommand extends Command { @override final String description = - 'Clean this workspace and all packages. This deletes the temporary pub files such as ".packages" & ".flutter-plugins". Supports all package filtering options.'; + 'Clean this workspace and all packages. This deletes the temporary pub & ide files such as ".packages" & ".flutter-plugins". Supports all package filtering options.'; @override void run() async { logger.stdout('Cleaning workspace...'); currentWorkspace.clean(); + await IntellijProject.fromWorkspace(currentWorkspace).cleanFiles(); if (currentWorkspace.config.scripts.containsKey('postclean')) { logger.stdout('Running postclean script...\n'); await MelosCommandRunner.instance.run(['run', 'postclean']); } logger.stdout( - 'Workspace cleaned, you will need to run the bootstrap command again.'); + '\nWorkspace cleaned. You will need to run the bootstrap command again to use this workspace.'); } } diff --git a/lib/src/command/exec.dart b/lib/src/command/exec.dart index 16d9e66ce..45232859a 100644 --- a/lib/src/command/exec.dart +++ b/lib/src/command/exec.dart @@ -42,7 +42,7 @@ class ExecCommand extends Command { defaultsTo: false, negatable: true, help: - 'Wether exec should fail fast and not execute the script in further packages if the script fails in a individual package.'); + 'Whether exec should fail fast and not execute the script in further packages if the script fails in a individual package.'); } @override diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart index ebf29a9ce..9a3f1f4c7 100644 --- a/lib/src/command_runner.dart +++ b/lib/src/command_runner.dart @@ -85,6 +85,7 @@ class MelosCommandRunner extends CommandRunner { // TODO(salakar): log init help once init command complete logger.stderr( 'Your current directory does not appear to be a valid workspace.'); + logger.stderr('Does the "melos.yaml" file exist in the root?'); exit(1); } diff --git a/lib/src/common/intellij_project.dart b/lib/src/common/intellij_project.dart index 57e04f064..3bc5d9215 100644 --- a/lib/src/common/intellij_project.dart +++ b/lib/src/common/intellij_project.dart @@ -42,7 +42,7 @@ class IntellijProject { return IntellijProject._(workspace); } - /// Fully qualified path to the intellij templates shiped as part of Melos. + /// Fully qualified path to the intellij templates shipped as part of Melos. String get pathTemplates { return joinAll([ utils.getMelosRoot(), @@ -108,10 +108,6 @@ class IntellijProject { return ' $module'; } - Future cleanProject() async { - // TODO - } - /// Reads a file template from the templates directory. /// Additionally keeps a cache to reduce reads. Future readFileTemplate(String fileName, @@ -228,6 +224,10 @@ class IntellijProject { }); } + Future cleanFiles() async { + // TODO + } + Future writeFlutterRunScripts() async { // TODO } diff --git a/lib/src/common/utils.dart b/lib/src/common/utils.dart index e36c85cf8..fc11a1126 100644 --- a/lib/src/common/utils.dart +++ b/lib/src/common/utils.dart @@ -24,6 +24,8 @@ import 'package:yaml/yaml.dart'; import 'logger.dart'; +var _didLogRmWarning = false; + String getMelosRoot() { return File.fromUri(Platform.script).parent.parent.path; } @@ -124,6 +126,17 @@ Future startProcess(List execArgs, return _arg; }).where((element) => element != null); + // TODO This is just a temporary workaround to keep FlutterFire working on Windows + // TODO until all the run scripts have been updated in its melos.yaml file. + if (filteredArgs.toList()[0] == 'rm' && Platform.isWindows) { + if (!_didLogRmWarning) { + print( + '> Warning: skipped executing a script as "rm" is not supported on Windows.'); + _didLogRmWarning = true; + } + return 0; + } + final execProcess = await Process.start(executable, Platform.isWindows ? ['/C', '%MELOS_SCRIPT%'] : ['-c', r'$MELOS_SCRIPT'], workingDirectory: workingDirectoryPath, diff --git a/lib/src/common/workspace_config.dart b/lib/src/common/workspace_config.dart index 9d275dd3e..a1b4c261c 100644 --- a/lib/src/common/workspace_config.dart +++ b/lib/src/common/workspace_config.dart @@ -22,9 +22,8 @@ import 'package:yaml/yaml.dart'; import 'utils.dart'; - // TODO validation of config -// name should be required, alphanumeric dasherized/underscoped +// name should be required, alphanumeric dasherized/underscored class MelosWorkspaceConfig { final String _name; From 23f23bbea0acce5014e9e3ed13d1cbb9038c5ba1 Mon Sep 17 00:00:00 2001 From: Salakar Date: Mon, 24 Aug 2020 21:17:57 +0100 Subject: [PATCH 16/16] fix startProcess on macos/linux --- lib/src/common/utils.dart | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/src/common/utils.dart b/lib/src/common/utils.dart index fc11a1126..dc61fd61e 100644 --- a/lib/src/common/utils.dart +++ b/lib/src/common/utils.dart @@ -137,15 +137,22 @@ Future startProcess(List execArgs, return 0; } - final execProcess = await Process.start(executable, - Platform.isWindows ? ['/C', '%MELOS_SCRIPT%'] : ['-c', r'$MELOS_SCRIPT'], + final execProcess = await Process.start( + executable, Platform.isWindows ? ['/C', '%MELOS_SCRIPT%'] : [], workingDirectory: workingDirectoryPath, includeParentEnvironment: true, environment: { ...environmentVariables, 'MELOS_SCRIPT': filteredArgs.join(' '), }, - runInShell: true); + runInShell: Platform.isWindows); + + if (!Platform.isWindows) { + // Pipe in the arguments to trigger the script to run. + execProcess.stdin.writeln(filteredArgs.join(' ')); + // Exit the process with the same exit code as the previous command. + execProcess.stdin.writeln('exit \$?'); + } var stdoutStream = execProcess.stdout; var stderrStream = execProcess.stderr;