diff --git a/packages/flutter_tools/lib/src/android/android_studio_validator.dart b/packages/flutter_tools/lib/src/android/android_studio_validator.dart index 268926a791d..3fc1b797f58 100644 --- a/packages/flutter_tools/lib/src/android/android_studio_validator.dart +++ b/packages/flutter_tools/lib/src/android/android_studio_validator.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import '../base/user_messages.dart'; import '../base/version.dart'; import '../doctor.dart'; import '../globals.dart'; @@ -34,9 +35,9 @@ class AndroidStudioValidator extends DoctorValidator { final String studioVersionText = _studio.version == Version.unknown ? null - : 'version ${_studio.version}'; + : userMessages.androidStudioVersion(_studio.version.toString()); messages - .add(ValidationMessage('Android Studio at ${_studio.directory}')); + .add(ValidationMessage(userMessages.androidStudioLocation(_studio.directory))); final IntelliJPlugins plugins = IntelliJPlugins(_studio.pluginsPath); plugins.validatePackage(messages, ['flutter-intellij', 'flutter-intellij.jar'], @@ -51,11 +52,9 @@ class AndroidStudioValidator extends DoctorValidator { type = ValidationType.partial; messages.addAll(_studio.validationMessages .map((String m) => ValidationMessage.error(m))); - messages.add(ValidationMessage( - 'Try updating or re-installing Android Studio.')); + messages.add(ValidationMessage(userMessages.androidStudioNeedsUpdate)); if (_studio.configured != null) { - messages.add(ValidationMessage( - 'Consider removing your android-studio-dir setting by running:\nflutter config --android-studio-dir=')); + messages.add(ValidationMessage(userMessages.androidStudioResetDir)); } } @@ -76,13 +75,9 @@ class NoAndroidStudioValidator extends DoctorValidator { final String cfgAndroidStudio = config.getValue('android-studio-dir'); if (cfgAndroidStudio != null) { - messages.add( - ValidationMessage.error('android-studio-dir = $cfgAndroidStudio\n' - 'but Android Studio not found at this location.')); + messages.add(ValidationMessage.error(userMessages.androidStudioMissing(cfgAndroidStudio))); } - messages.add(ValidationMessage( - 'Android Studio not found; download from https://developer.android.com/studio/index.html\n' - '(or visit https://flutter.io/setup/#android-setup for detailed instructions).')); + messages.add(ValidationMessage(userMessages.androidStudioInstallation)); return ValidationResult(ValidationType.notAvailable, messages, statusInfo: 'not installed'); diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart index f2e7725a3a5..6fccde73989 100644 --- a/packages/flutter_tools/lib/src/android/android_workflow.dart +++ b/packages/flutter_tools/lib/src/android/android_workflow.dart @@ -11,6 +11,7 @@ import '../base/io.dart'; import '../base/platform.dart'; import '../base/process.dart'; import '../base/process_manager.dart'; +import '../base/user_messages.dart'; import '../base/utils.dart'; import '../base/version.dart'; import '../doctor.dart'; @@ -49,13 +50,11 @@ class AndroidWorkflow implements Workflow { class AndroidValidator extends DoctorValidator { AndroidValidator(): super('Android toolchain - develop for Android devices',); - static const String _jdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/'; - /// Returns false if we cannot determine the Java version or if the version /// is not compatible. Future _checkJavaVersion(String javaBinary, List messages) async { if (!processManager.canRun(javaBinary)) { - messages.add(ValidationMessage.error('Cannot execute $javaBinary to determine the version')); + messages.add(ValidationMessage.error(userMessages.androidCantRunJavaBinary(javaBinary))); return false; } String javaVersion; @@ -71,10 +70,10 @@ class AndroidValidator extends DoctorValidator { } if (javaVersion == null) { // Could not determine the java version. - messages.add(ValidationMessage.error('Could not determine java version')); + messages.add(ValidationMessage.error(userMessages.androidUnknownJavaVersion)); return false; } - messages.add(ValidationMessage('Java version $javaVersion')); + messages.add(ValidationMessage(userMessages.androidJavaVersion(javaVersion))); // TODO(johnmccutchan): Validate version. return true; } @@ -87,38 +86,26 @@ class AndroidValidator extends DoctorValidator { // No Android SDK found. if (platform.environment.containsKey(kAndroidHome)) { final String androidHomeDir = platform.environment[kAndroidHome]; - messages.add(ValidationMessage.error( - '$kAndroidHome = $androidHomeDir\n' - 'but Android SDK not found at this location.' - )); + messages.add(ValidationMessage.error(userMessages.androidBadSdkDir(kAndroidHome, androidHomeDir))); } else { - messages.add(ValidationMessage.error( - 'Unable to locate Android SDK.\n' - 'Install Android Studio from: https://developer.android.com/studio/index.html\n' - 'On first launch it will assist you in installing the Android SDK components.\n' - '(or visit https://flutter.io/setup/#android-setup for detailed instructions).\n' - 'If Android SDK has been installed to a custom location, set \$$kAndroidHome to that location.\n' - 'You may also want to add it to your PATH environment variable.\n' - )); + messages.add(ValidationMessage.error(userMessages.androidMissingSdkInstructions(kAndroidHome))); } - return ValidationResult(ValidationType.missing, messages); } - messages.add(ValidationMessage('Android SDK at ${androidSdk.directory}')); + messages.add(ValidationMessage(userMessages.androidSdkLocation(androidSdk.directory))); messages.add(ValidationMessage(androidSdk.ndk == null - ? 'Android NDK location not configured (optional; useful for native profiling support)' - : 'Android NDK at ${androidSdk.ndk.directory}')); + ? userMessages.androidMissingNdk + : userMessages.androidNdkLocation(androidSdk.ndk.directory))); String sdkVersionText; if (androidSdk.latestVersion != null) { - sdkVersionText = 'Android SDK ${androidSdk.latestVersion.buildToolsVersionName}'; + sdkVersionText = userMessages.androidStatusInfo(androidSdk.latestVersion.buildToolsVersionName); - messages.add(ValidationMessage( - 'Platform ${androidSdk.latestVersion.platformName}, ' - 'build-tools ${androidSdk.latestVersion.buildToolsVersionName}' - )); + messages.add(ValidationMessage(userMessages.androidSdkPlatformToolsVersion( + androidSdk.latestVersion.platformName, + androidSdk.latestVersion.buildToolsVersionName))); } if (platform.environment.containsKey(kAndroidHome)) { @@ -137,22 +124,17 @@ class AndroidValidator extends DoctorValidator { messages.addAll(validationResult.map((String message) { return ValidationMessage.error(message); })); - messages.add(ValidationMessage( - 'Try re-installing or updating your Android SDK,\n' - 'visit https://flutter.io/setup/#android-setup for detailed instructions.')); + messages.add(ValidationMessage(userMessages.androidSdkInstallHelp)); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); } // Now check for the JDK. final String javaBinary = AndroidSdk.findJavaBinary(); if (javaBinary == null) { - messages.add(ValidationMessage.error( - 'No Java Development Kit (JDK) found; You must have the environment ' - 'variable JAVA_HOME set and the java binary in your PATH. ' - 'You can download the JDK from $_jdkDownload.')); + messages.add(ValidationMessage.error(userMessages.androidMissingJdk)); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); } - messages.add(ValidationMessage('Java binary at: $javaBinary')); + messages.add(ValidationMessage(userMessages.androidJdkLocation(javaBinary))); // Check JDK version. if (! await _checkJavaVersion(javaBinary, messages)) { @@ -178,21 +160,21 @@ class AndroidLicenseValidator extends DoctorValidator { return ValidationResult(ValidationType.missing, messages); } - final String sdkVersionText = 'Android SDK ${androidSdk.latestVersion.buildToolsVersionName}'; + final String sdkVersionText = userMessages.androidStatusInfo(androidSdk.latestVersion.buildToolsVersionName); // Check for licenses. switch (await licensesAccepted) { case LicensesAccepted.all: - messages.add(ValidationMessage('All Android licenses accepted.')); + messages.add(ValidationMessage(userMessages.androidLicensesAll)); break; case LicensesAccepted.some: - messages.add(ValidationMessage.hint('Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses')); + messages.add(ValidationMessage.hint(userMessages.androidLicensesSome)); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); case LicensesAccepted.none: - messages.add(ValidationMessage.error('Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses')); + messages.add(ValidationMessage.error(userMessages.androidLicensesNone)); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); case LicensesAccepted.unknown: - messages.add(ValidationMessage.error('Android license status unknown.')); + messages.add(ValidationMessage.error(userMessages.androidLicensesUnknown)); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); } return ValidationResult(ValidationType.installed, messages, statusInfo: sdkVersionText); @@ -263,7 +245,7 @@ class AndroidLicenseValidator extends DoctorValidator { try { await Future.wait(>[output, errors]).timeout(const Duration(seconds: 30)); } catch (TimeoutException) { - printTrace('Intentionally killing ${androidSdk.sdkManagerPath}'); + printTrace(userMessages.androidLicensesTimeout(androidSdk.sdkManagerPath)); processManager.killPid(process.pid); } return status ?? LicensesAccepted.unknown; @@ -272,7 +254,7 @@ class AndroidLicenseValidator extends DoctorValidator { /// Run the Android SDK manager tool in order to accept SDK licenses. static Future runLicenseManager() async { if (androidSdk == null) { - printStatus('Unable to locate Android SDK.'); + printStatus(userMessages.androidSdkShort); return false; } @@ -281,10 +263,7 @@ class AndroidLicenseValidator extends DoctorValidator { final Version sdkManagerVersion = Version.parse(androidSdk.sdkManagerVersion); if (sdkManagerVersion == null || sdkManagerVersion.major < 26) // SDK manager is found, but needs to be updated. - throwToolExit( - 'A newer version of the Android SDK is required. To update, run:\n' - '${androidSdk.sdkManagerPath} --update\n' - ); + throwToolExit(userMessages.androidSdkOutdated(androidSdk.sdkManagerPath)); final Process process = await runCommand( [androidSdk.sdkManagerPath, '--licenses'], @@ -309,10 +288,6 @@ class AndroidLicenseValidator extends DoctorValidator { assert(androidSdk != null); final String sdkManagerPath = androidSdk.sdkManagerPath; if (!processManager.canRun(sdkManagerPath)) - throwToolExit( - 'Android sdkmanager tool not found ($sdkManagerPath).\n' - 'Try re-installing or updating your Android SDK,\n' - 'visit https://flutter.io/setup/#android-setup for detailed instructions.' - ); + throwToolExit(userMessages.androidMissingSdkManager(sdkManagerPath)); } } diff --git a/packages/flutter_tools/lib/src/base/user_messages.dart b/packages/flutter_tools/lib/src/base/user_messages.dart new file mode 100644 index 00000000000..4e0e4a801cb --- /dev/null +++ b/packages/flutter_tools/lib/src/base/user_messages.dart @@ -0,0 +1,183 @@ +import 'context.dart'; + +UserMessages get userMessages => context[UserMessages]; + +/// Class containing message strings that can be produced by Flutter tools. +class UserMessages { + // Messages used in FlutterValidator + String flutterStatusInfo(String channel, String version, String os, String locale) => + 'Channel $channel, v$version, on $os, locale $locale'; + String flutterVersion(String version, String flutterRoot) => + 'Flutter version $version at $flutterRoot'; + String flutterRevision(String revision, String age, String date) => + 'Framework revision $revision ($age), $date'; + String engineRevision(String revision) => 'Engine revision $revision'; + String dartRevision(String revision) => 'Dart version $revision'; + String get flutterBinariesDoNotRun => + 'Downloaded executables cannot execute on host.\n' + 'See https://github.com/flutter/flutter/issues/6207 for more information'; + String get flutterBinariesLinuxRepairCommands => + 'On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6\n' + 'On Fedora: dnf install libstdc++.i686\n' + 'On Arch: pacman -S lib32-libstdc++5'; + + // Messages used in NoIdeValidator + String get noIdeStatusInfo => 'No supported IDEs installed'; + String get noIdeInstallationInfo => 'IntelliJ - https://www.jetbrains.com/idea/'; + + // Messages used in IntellijValidator + String intellijStatusInfo(String version) => 'version $version'; + String get intellijPluginInfo => + 'For information about installing plugins, see\n' + 'https://flutter.io/intellij-setup/#installing-the-plugins'; + String intellijMinimumVersion(String minVersion) => + 'This install is older than the minimum recommended version of $minVersion.'; + String intellijLocation(String installPath) => 'IntelliJ at $installPath'; + + // Message used in IntellijValidatorOnMac + String get intellijMacUnknownResult => 'Cannot determine if IntelliJ is installed'; + + // Messages used in DeviceValidator + String get devicesMissing => 'No devices available'; + String devicesAvailable(int devices) => '$devices available'; + + // Messages used in AndroidValidator + String androidCantRunJavaBinary(String javaBinary) => 'Cannot execute $javaBinary to determine the version'; + String get androidUnknownJavaVersion => 'Could not determine java version'; + String androidJavaVersion(String javaVersion) => 'Java version $javaVersion'; + String androidBadSdkDir(String envKey, String homeDir) => + '$envKey = $homeDir\n' + 'but Android SDK not found at this location.'; + String androidMissingSdkInstructions(String envKey) => + 'Unable to locate Android SDK.\n' + 'Install Android Studio from: https://developer.android.com/studio/index.html\n' + 'On first launch it will assist you in installing the Android SDK components.\n' + '(or visit https://flutter.io/setup/#android-setup for detailed instructions).\n' + 'If Android SDK has been installed to a custom location, set $envKey to that location.\n' + 'You may also want to add it to your PATH environment variable.\n'; + String androidSdkLocation(String directory) => 'Android SDK at $directory'; + String androidSdkPlatformToolsVersion(String platform, String tools) => + 'Platform $platform, build-tools $tools'; + String get androidSdkInstallHelp => + 'Try re-installing or updating your Android SDK,\n' + 'visit https://flutter.io/setup/#android-setup for detailed instructions.'; + String get androidMissingNdk => 'Android NDK location not configured (optional; useful for native profiling support)'; + String androidNdkLocation(String directory) => 'Android NDK at $directory'; + // Also occurs in AndroidLicenseValidator + String androidStatusInfo(String version) => 'Android SDK version $version'; + + // Messages used in AndroidLicenseValidator + String get androidMissingJdk => + 'No Java Development Kit (JDK) found; You must have the environment ' + 'variable JAVA_HOME set and the java binary in your PATH. ' + 'You can download the JDK from https://www.oracle.com/technetwork/java/javase/downloads/.'; + String androidJdkLocation(String location) => 'Java binary at: $location'; + String get androidLicensesAll => 'All Android licenses accepted.'; + String get androidLicensesSome => 'Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses'; + String get androidLicensesNone => 'Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses'; + String get androidLicensesUnknown => 'Android license status unknown.'; + String androidSdkOutdated(String managerPath) => + 'A newer version of the Android SDK is required. To update, run:\n' + '$managerPath --update\n'; + String androidLicensesTimeout(String managerPath) => 'Intentionally killing $managerPath'; + String get androidSdkShort => 'Unable to locate Android SDK.'; + String androidMissingSdkManager(String sdkManagerPath) => + 'Android sdkmanager tool not found ($sdkManagerPath).\n' + 'Try re-installing or updating your Android SDK,\n' + 'visit https://flutter.io/setup/#android-setup for detailed instructions.'; + + // Messages used in AndroidStudioValidator + String androidStudioVersion(String version) => 'version $version'; + String androidStudioLocation(String location) => 'Android Studio at $location'; + String get androidStudioNeedsUpdate => 'Try updating or re-installing Android Studio.'; + String get androidStudioResetDir => + 'Consider removing your android-studio-dir setting by running:\n' + 'flutter config --android-studio-dir='; + + // Messages used in NoAndroidStudioValidator + String androidStudioMissing(String location) => + 'android-studio-dir = $location\n' + 'but Android Studio not found at this location.'; + String get androidStudioInstallation => + 'Android Studio not found; download from https://developer.android.com/studio/index.html\n' + '(or visit https://flutter.io/setup/#android-setup for detailed instructions).'; + + // Messages used in IOSValidator + String iOSXcodeLocation(String location) => 'Xcode at $location'; + String iOSXcodeOutdated(int versionMajor, int versionMinor) => + 'Flutter requires a minimum Xcode version of $versionMajor.$versionMinor.0.\n' + 'Download the latest version or update via the Mac App Store.'; + String get iOSXcodeEula => 'Xcode end user license agreement not signed; open Xcode or run the command \'sudo xcodebuild -license\'.'; + String get iOSXcodeMissingSimct => + 'Xcode requires additional components to be installed in order to run.\n' + 'Launch Xcode and install additional required components when prompted.'; + String get iOSXcodeMissing => + 'Xcode not installed; this is necessary for iOS development.\n' + 'Download at https://developer.apple.com/xcode/download/.'; + String get iOSXcodeIncomplete => + 'Xcode installation is incomplete; a full installation is necessary for iOS development.\n' + 'Download at: https://developer.apple.com/xcode/download/\n' + 'Or install Xcode via the App Store.\n' + 'Once installed, run:\n' + ' sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer'; + String get iOSIMobileDeviceMissing => + 'libimobiledevice and ideviceinstaller are not installed. To install with Brew, run:\n' + ' brew update\n' + ' brew install --HEAD usbmuxd\n' + ' brew link usbmuxd\n' + ' brew install --HEAD libimobiledevice\n' + ' brew install ideviceinstaller'; + String get iOSIMobileDeviceBroken => + 'Verify that all connected devices have been paired with this computer in Xcode.\n' + 'If all devices have been paired, libimobiledevice and ideviceinstaller may require updating.\n' + 'To update with Brew, run:\n' + ' brew update\n' + ' brew uninstall --ignore-dependencies libimobiledevice\n' + ' brew uninstall --ignore-dependencies usbmuxd\n' + ' brew install --HEAD usbmuxd\n' + ' brew unlink usbmuxd\n' + ' brew link usbmuxd\n' + ' brew install --HEAD libimobiledevice\n' + ' brew install ideviceinstaller'; + String get iOSDeviceInstallerMissing => + 'ideviceinstaller is not installed; this is used to discover connected iOS devices.\n' + 'To install with Brew, run:\n' + ' brew install --HEAD usbmuxd\n' + ' brew link usbmuxd\n' + ' brew install --HEAD libimobiledevice\n' + ' brew install ideviceinstaller'; + String iOSDeployVersion(String version) => 'ios-deploy $version'; + String iOSDeployOutdated(String minVersion) => + 'ios-deploy out of date ($minVersion is required). To upgrade with Brew:\n' + ' brew upgrade ios-deploy'; + String get iOSDeployMissing => + 'ios-deploy not installed. To install:\n' + ' brew install ios-deploy'; + String get iOSBrewMissing => + 'Brew can be used to install tools for iOS device development.\n' + 'Download brew at https://brew.sh/.'; + + // Messages used in CocoaPodsValidator + String cocoaPodsVersion(String version) => 'CocoaPods version $version'; + String cocoaPodsUninitialized(String consequence) => + 'CocoaPods installed but not initialized.\n' + '$consequence\n' + 'To initialize CocoaPods, run:\n' + ' pod setup\n' + 'once to finalize CocoaPods\' installation.'; + String cocoaPodsMissing(String consequence, String installInstructions) => + 'CocoaPods not installed.\n' + '$consequence\n' + 'To install:\n' + '$installInstructions'; + String cocoaPodsOutdated(String recVersion, String consequence, String upgradeInstructions) => + 'CocoaPods out of date ($recVersion is recommended).\n' + '$consequence\n' + 'To upgrade:\n' + '$upgradeInstructions'; + + // Messages used in VsCodeValidator + String vsCodeVersion(String version) => 'version $version'; + String vsCodeLocation(String location) => 'VS Code at $location'; + String vsCodeFlutterExtensionMissing(String url) => 'Flutter extension not installed; install from\n$url'; +} diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index d9dff8a5d5b..31a88b48245 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -18,6 +18,7 @@ import 'base/logger.dart'; import 'base/os.dart'; import 'base/platform.dart'; import 'base/time.dart'; +import 'base/user_messages.dart'; import 'base/utils.dart'; import 'cache.dart'; import 'compile.dart'; @@ -81,6 +82,7 @@ Future runInContext( SystemClock: () => const SystemClock(), Stdio: () => const Stdio(), Usage: () => Usage(), + UserMessages: () => UserMessages(), Xcode: () => Xcode(), XcodeProjectInterpreter: () => XcodeProjectInterpreter(), }, diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 52b540e545e..e9a34a06686 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -15,6 +15,7 @@ import 'base/os.dart'; import 'base/platform.dart'; import 'base/process_manager.dart'; import 'base/terminal.dart'; +import 'base/user_messages.dart'; import 'base/utils.dart'; import 'base/version.dart'; import 'cache.dart'; @@ -432,32 +433,26 @@ class _FlutterValidator extends DoctorValidator { final FlutterVersion version = FlutterVersion.instance; - messages.add(ValidationMessage('Flutter version ${version.frameworkVersion} at ${Cache.flutterRoot}')); - messages.add(ValidationMessage( - 'Framework revision ${version.frameworkRevisionShort} ' - '(${version.frameworkAge}), ${version.frameworkDate}' - )); - messages.add(ValidationMessage('Engine revision ${version.engineRevisionShort}')); - messages.add(ValidationMessage('Dart version ${version.dartSdkVersion}')); + messages.add(ValidationMessage(userMessages.flutterVersion(version.frameworkVersion, Cache.flutterRoot))); + messages.add(ValidationMessage(userMessages.flutterRevision(version.frameworkRevisionShort, version.frameworkAge, version.frameworkDate))); + messages.add(ValidationMessage(userMessages.engineRevision(version.engineRevisionShort))); + messages.add(ValidationMessage(userMessages.dartRevision(version.dartSdkVersion))); final String genSnapshotPath = artifacts.getArtifactPath(Artifact.genSnapshot); // Check that the binaries we downloaded for this platform actually run on it. if (!_genSnapshotRuns(genSnapshotPath)) { final StringBuffer buf = StringBuffer(); - buf.writeln('Downloaded executables cannot execute on host.'); - buf.writeln('See https://github.com/flutter/flutter/issues/6207 for more information'); + buf.writeln(userMessages.flutterBinariesDoNotRun); if (platform.isLinux) { - buf.writeln('On Debian/Ubuntu/Mint: sudo apt-get install lib32stdc++6'); - buf.writeln('On Fedora: dnf install libstdc++.i686'); - buf.writeln('On Arch: pacman -S lib32-libstdc++5'); + buf.writeln(userMessages.flutterBinariesLinuxRepairCommands); } messages.add(ValidationMessage.error(buf.toString())); valid = ValidationType.partial; } return ValidationResult(valid, messages, - statusInfo: 'Channel ${version.channel}, v${version.frameworkVersion}, on ${os.name}, locale ${platform.localeName}' + statusInfo: userMessages.flutterStatusInfo(version.channel, version.frameworkVersion, os.name, platform.localeName) ); } } @@ -477,8 +472,8 @@ class NoIdeValidator extends DoctorValidator { @override Future validate() async { return ValidationResult(ValidationType.missing, [ - ValidationMessage('IntelliJ - https://www.jetbrains.com/idea/'), - ], statusInfo: 'No supported IDEs installed'); + ValidationMessage(userMessages.noIdeInstallationInfo), + ], statusInfo: userMessages.noIdeStatusInfo); } } @@ -509,7 +504,7 @@ abstract class IntelliJValidator extends DoctorValidator { Future validate() async { final List messages = []; - messages.add(ValidationMessage('IntelliJ at $installPath')); + messages.add(ValidationMessage(userMessages.intellijLocation(installPath))); final IntelliJPlugins plugins = IntelliJPlugins(pluginsPath); plugins.validatePackage(messages, ['flutter-intellij', 'flutter-intellij.jar'], @@ -517,10 +512,7 @@ abstract class IntelliJValidator extends DoctorValidator { plugins.validatePackage(messages, ['Dart'], 'Dart'); if (_hasIssues(messages)) { - messages.add(ValidationMessage( - 'For information about installing plugins, see\n' - 'https://flutter.io/intellij-setup/#installing-the-plugins' - )); + messages.add(ValidationMessage(userMessages.intellijPluginInfo)); } _validateIntelliJVersion(messages, kMinIdeaVersion); @@ -528,8 +520,7 @@ abstract class IntelliJValidator extends DoctorValidator { return ValidationResult( _hasIssues(messages) ? ValidationType.partial : ValidationType.installed, messages, - statusInfo: 'version $version' - ); + statusInfo: userMessages.intellijStatusInfo(version)); } bool _hasIssues(List messages) { @@ -546,9 +537,7 @@ abstract class IntelliJValidator extends DoctorValidator { return; if (installedVersion < minVersion) { - messages.add(ValidationMessage.error( - 'This install is older than the minimum recommended version of $minVersion.' - )); + messages.add(ValidationMessage.error(userMessages.intellijMinimumVersion(minVersion.toString()))); } } } @@ -648,7 +637,7 @@ class IntelliJValidatorOnMac extends IntelliJValidator { } } on FileSystemException catch (e) { validators.add(ValidatorWithResult( - 'Cannot determine if IntelliJ is installed', + userMessages.intellijMacUnknownResult, ValidationResult(ValidationType.missing, [ ValidationMessage.error(e.message), ]), @@ -691,7 +680,7 @@ class DeviceValidator extends DoctorValidator { if (diagnostics.isNotEmpty) { messages = diagnostics.map((String message) => ValidationMessage(message)).toList(); } else { - messages = [ValidationMessage.hint('No devices available')]; + messages = [ValidationMessage.hint(userMessages.devicesMissing)]; } } else { messages = await Device.descriptions(devices) @@ -701,7 +690,7 @@ class DeviceValidator extends DoctorValidator { if (devices.isEmpty) { return ValidationResult(ValidationType.notAvailable, messages); } else { - return ValidationResult(ValidationType.installed, messages, statusInfo: '${devices.length} available'); + return ValidationResult(ValidationType.installed, messages, statusInfo: userMessages.devicesAvailable(devices.length)); } } } diff --git a/packages/flutter_tools/lib/src/ios/ios_workflow.dart b/packages/flutter_tools/lib/src/ios/ios_workflow.dart index c8bc17f501d..f7cdc35f43c 100644 --- a/packages/flutter_tools/lib/src/ios/ios_workflow.dart +++ b/packages/flutter_tools/lib/src/ios/ios_workflow.dart @@ -8,6 +8,7 @@ import '../base/context.dart'; import '../base/os.dart'; import '../base/platform.dart'; import '../base/process.dart'; +import '../base/user_messages.dart'; import '../base/version.dart'; import '../doctor.dart'; import 'cocoapods.dart'; @@ -81,7 +82,7 @@ class IOSValidator extends DoctorValidator { if (xcode.isInstalled) { xcodeStatus = ValidationType.installed; - messages.add(ValidationMessage('Xcode at ${xcode.xcodeSelectPath}')); + messages.add(ValidationMessage(userMessages.iOSXcodeLocation(xcode.xcodeSelectPath))); xcodeVersionInfo = xcode.versionText; if (xcodeVersionInfo.contains(',')) @@ -91,40 +92,25 @@ class IOSValidator extends DoctorValidator { if (!xcode.isInstalledAndMeetsVersionCheck) { xcodeStatus = ValidationType.partial; messages.add(ValidationMessage.error( - 'Flutter requires a minimum Xcode version of $kXcodeRequiredVersionMajor.$kXcodeRequiredVersionMinor.0.\n' - 'Download the latest version or update via the Mac App Store.' + userMessages.iOSXcodeOutdated(kXcodeRequiredVersionMajor, kXcodeRequiredVersionMinor) )); } if (!xcode.eulaSigned) { xcodeStatus = ValidationType.partial; - messages.add(ValidationMessage.error( - 'Xcode end user license agreement not signed; open Xcode or run the command \'sudo xcodebuild -license\'.' - )); + messages.add(ValidationMessage.error(userMessages.iOSXcodeEula)); } if (!xcode.isSimctlInstalled) { xcodeStatus = ValidationType.partial; - messages.add(ValidationMessage.error( - 'Xcode requires additional components to be installed in order to run.\n' - 'Launch Xcode and install additional required components when prompted.' - )); + messages.add(ValidationMessage.error(userMessages.iOSXcodeMissingSimct)); } } else { xcodeStatus = ValidationType.missing; if (xcode.xcodeSelectPath == null || xcode.xcodeSelectPath.isEmpty) { - messages.add(ValidationMessage.error( - 'Xcode not installed; this is necessary for iOS development.\n' - 'Download at https://developer.apple.com/xcode/download/.' - )); + messages.add(ValidationMessage.error(userMessages.iOSXcodeMissing)); } else { - messages.add(ValidationMessage.error( - 'Xcode installation is incomplete; a full installation is necessary for iOS development.\n' - 'Download at: https://developer.apple.com/xcode/download/\n' - 'Or install Xcode via the App Store.\n' - 'Once installed, run:\n' - ' sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer' - )); + messages.add(ValidationMessage.error(userMessages.iOSXcodeIncomplete)); } } @@ -133,63 +119,30 @@ class IOSValidator extends DoctorValidator { if (!iMobileDevice.isInstalled) { checksFailed += 3; packageManagerStatus = ValidationType.partial; - messages.add(ValidationMessage.error( - 'libimobiledevice and ideviceinstaller are not installed. To install with Brew, run:\n' - ' brew update\n' - ' brew install --HEAD usbmuxd\n' - ' brew link usbmuxd\n' - ' brew install --HEAD libimobiledevice\n' - ' brew install ideviceinstaller' - )); + messages.add(ValidationMessage.error(userMessages.iOSIMobileDeviceMissing)); } else if (!await iMobileDevice.isWorking) { checksFailed += 2; packageManagerStatus = ValidationType.partial; - messages.add(ValidationMessage.error( - 'Verify that all connected devices have been paired with this computer in Xcode.\n' - 'If all devices have been paired, libimobiledevice and ideviceinstaller may require updating.\n' - 'To update with Brew, run:\n' - ' brew update\n' - ' brew uninstall --ignore-dependencies libimobiledevice\n' - ' brew uninstall --ignore-dependencies usbmuxd\n' - ' brew install --HEAD usbmuxd\n' - ' brew unlink usbmuxd\n' - ' brew link usbmuxd\n' - ' brew install --HEAD libimobiledevice\n' - ' brew install ideviceinstaller' - )); + messages.add(ValidationMessage.error(userMessages.iOSIMobileDeviceBroken)); } else if (!await hasIDeviceInstaller) { checksFailed += 1; packageManagerStatus = ValidationType.partial; - messages.add(ValidationMessage.error( - 'ideviceinstaller is not installed; this is used to discover connected iOS devices.\n' - 'To install with Brew, run:\n' - ' brew install --HEAD usbmuxd\n' - ' brew link usbmuxd\n' - ' brew install --HEAD libimobiledevice\n' - ' brew install ideviceinstaller' - )); + messages.add(ValidationMessage.error(userMessages.iOSDeviceInstallerMissing)); } final bool iHasIosDeploy = await hasIosDeploy; // Check ios-deploy is installed at meets version requirements. if (iHasIosDeploy) { - messages.add( - ValidationMessage('ios-deploy ${await iosDeployVersionText}')); + messages.add(ValidationMessage(userMessages.iOSDeployVersion(await iosDeployVersionText))); } if (!await _iosDeployIsInstalledAndMeetsVersionCheck) { packageManagerStatus = ValidationType.partial; if (iHasIosDeploy) { - messages.add(ValidationMessage.error( - 'ios-deploy out of date ($iosDeployMinimumVersion is required). To upgrade with Brew:\n' - ' brew upgrade ios-deploy' - )); + messages.add(ValidationMessage.error(userMessages.iOSDeployOutdated(iosDeployMinimumVersion))); } else { checksFailed += 1; - messages.add(ValidationMessage.error( - 'ios-deploy not installed. To install with Brew:\n' - ' brew install ios-deploy' - )); + messages.add(ValidationMessage.error(userMessages.iOSDeployMissing)); } } @@ -198,10 +151,7 @@ class IOSValidator extends DoctorValidator { if (checksFailed == totalChecks) packageManagerStatus = ValidationType.missing; if (checksFailed > 0 && !hasHomebrew) { - messages.add(ValidationMessage.error( - 'Brew can be used to install tools for iOS device development.\n' - 'Download brew at https://brew.sh/.' - )); + messages.add(ValidationMessage.error(userMessages.iOSBrewMissing)); } return ValidationResult( @@ -232,34 +182,20 @@ class CocoaPodsValidator extends DoctorValidator { if (cocoaPodsStatus == CocoaPodsStatus.recommended) { if (await cocoaPods.isCocoaPodsInitialized) { - messages.add(ValidationMessage('CocoaPods version ${await cocoaPods.cocoaPodsVersionText}')); + messages.add(ValidationMessage(userMessages.cocoaPodsVersion(await cocoaPods.cocoaPodsVersionText))); } else { status = ValidationType.partial; - messages.add(ValidationMessage.error( - 'CocoaPods installed but not initialized.\n' - '$noCocoaPodsConsequence\n' - 'To initialize CocoaPods, run:\n' - ' pod setup\n' - 'once to finalize CocoaPods\' installation.' - )); + messages.add(ValidationMessage.error(userMessages.cocoaPodsUninitialized(noCocoaPodsConsequence))); } } else { if (cocoaPodsStatus == CocoaPodsStatus.notInstalled) { status = ValidationType.missing; messages.add(ValidationMessage.error( - 'CocoaPods not installed.\n' - '$noCocoaPodsConsequence\n' - 'To install:\n' - '$cocoaPodsInstallInstructions' - )); + userMessages.cocoaPodsMissing(noCocoaPodsConsequence, cocoaPodsInstallInstructions))); } else { status = ValidationType.partial; messages.add(ValidationMessage.hint( - 'CocoaPods out of date (${cocoaPods.cocoaPodsRecommendedVersion} is recommended).\n' - '$noCocoaPodsConsequence\n' - 'To upgrade:\n' - '$cocoaPodsUpgradeInstructions' - )); + userMessages.cocoaPodsOutdated(cocoaPods.cocoaPodsRecommendedVersion, noCocoaPodsConsequence, cocoaPodsUpgradeInstructions))); } } } else { diff --git a/packages/flutter_tools/lib/src/vscode/vscode_validator.dart b/packages/flutter_tools/lib/src/vscode/vscode_validator.dart index 8746ae16d16..f955c5f4e8f 100644 --- a/packages/flutter_tools/lib/src/vscode/vscode_validator.dart +++ b/packages/flutter_tools/lib/src/vscode/vscode_validator.dart @@ -4,6 +4,7 @@ import 'dart:async'; +import '../base/user_messages.dart'; import '../base/version.dart'; import '../doctor.dart'; import 'vscode.dart'; @@ -24,7 +25,7 @@ class VsCodeValidator extends DoctorValidator { Future validate() async { final String vsCodeVersionText = _vsCode.version == Version.unknown ? null - : 'version ${_vsCode.version}'; + : userMessages.vsCodeVersion(_vsCode.version.toString()); final ValidationType validationType = _vsCode.isValid ? ValidationType.installed