245 lines
8.7 KiB
Dart
245 lines
8.7 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import '../base/common.dart';
|
|
import '../base/file_system.dart';
|
|
import '../base/utils.dart';
|
|
import '../base/version.dart';
|
|
import '../convert.dart';
|
|
import '../doctor.dart';
|
|
import '../globals.dart' as globals;
|
|
|
|
// Include VS Code insiders (useful for debugging).
|
|
const bool _includeInsiders = false;
|
|
|
|
|
|
const String extensionIdentifier = 'Dart-Code.flutter';
|
|
const String extensionMarketplaceUrl =
|
|
'https://marketplace.visualstudio.com/items?itemName=$extensionIdentifier';
|
|
|
|
class VsCode {
|
|
VsCode._(this.directory, this.extensionDirectory, { Version version, this.edition })
|
|
: version = version ?? Version.unknown {
|
|
|
|
if (!globals.fs.isDirectorySync(directory)) {
|
|
_validationMessages.add(ValidationMessage.error('VS Code not found at $directory'));
|
|
return;
|
|
} else {
|
|
_validationMessages.add(ValidationMessage('VS Code at $directory'));
|
|
}
|
|
|
|
// If the extensions directory doesn't exist at all, the listSync()
|
|
// below will fail, so just bail out early.
|
|
final ValidationMessage notInstalledMessage = ValidationMessage.error(
|
|
'Flutter extension not installed; install from\n$extensionMarketplaceUrl');
|
|
if (!globals.fs.isDirectorySync(extensionDirectory)) {
|
|
_validationMessages.add(notInstalledMessage);
|
|
return;
|
|
}
|
|
|
|
// Check for presence of extension.
|
|
final String extensionIdentifierLower = extensionIdentifier.toLowerCase();
|
|
final Iterable<FileSystemEntity> extensionDirs = globals.fs
|
|
.directory(extensionDirectory)
|
|
.listSync()
|
|
.whereType<Directory>()
|
|
.where((Directory d) => d.basename.toLowerCase().startsWith(extensionIdentifierLower));
|
|
|
|
if (extensionDirs.isNotEmpty) {
|
|
final FileSystemEntity extensionDir = extensionDirs.first;
|
|
|
|
_isValid = true;
|
|
_extensionVersion = Version.parse(
|
|
extensionDir.basename.substring('$extensionIdentifier-'.length));
|
|
_validationMessages.add(ValidationMessage('Flutter extension version $_extensionVersion'));
|
|
} else {
|
|
_validationMessages.add(notInstalledMessage);
|
|
}
|
|
}
|
|
|
|
factory VsCode.fromDirectory(
|
|
String installPath,
|
|
String extensionDirectory, {
|
|
String edition,
|
|
}) {
|
|
final String packageJsonPath =
|
|
globals.fs.path.join(installPath, 'resources', 'app', 'package.json');
|
|
final String versionString = _getVersionFromPackageJson(packageJsonPath);
|
|
Version version;
|
|
if (versionString != null) {
|
|
version = Version.parse(versionString);
|
|
}
|
|
return VsCode._(installPath, extensionDirectory, version: version, edition: edition);
|
|
}
|
|
|
|
final String directory;
|
|
final String extensionDirectory;
|
|
final Version version;
|
|
final String edition;
|
|
|
|
bool _isValid = false;
|
|
Version _extensionVersion;
|
|
final List<ValidationMessage> _validationMessages = <ValidationMessage>[];
|
|
|
|
bool get isValid => _isValid;
|
|
String get productName => 'VS Code' + (edition != null ? ', $edition' : '');
|
|
|
|
Iterable<ValidationMessage> get validationMessages => _validationMessages;
|
|
|
|
static List<VsCode> allInstalled() {
|
|
if (globals.platform.isMacOS) {
|
|
return _installedMacOS();
|
|
}
|
|
if (globals.platform.isWindows) {
|
|
return _installedWindows();
|
|
}
|
|
if (globals.platform.isLinux) {
|
|
return _installedLinux();
|
|
}
|
|
// VS Code isn't supported on the other platforms.
|
|
return <VsCode>[];
|
|
}
|
|
|
|
// macOS:
|
|
// /Applications/Visual Studio Code.app/Contents/
|
|
// /Applications/Visual Studio Code - Insiders.app/Contents/
|
|
// $HOME/Applications/Visual Studio Code.app/Contents/
|
|
// $HOME/Applications/Visual Studio Code - Insiders.app/Contents/
|
|
// macOS Extensions:
|
|
// $HOME/.vscode/extensions
|
|
// $HOME/.vscode-insiders/extensions
|
|
static List<VsCode> _installedMacOS() {
|
|
return _findInstalled(<_VsCodeInstallLocation>[
|
|
_VsCodeInstallLocation(
|
|
globals.fs.path.join('/Applications', 'Visual Studio Code.app', 'Contents'),
|
|
'.vscode',
|
|
),
|
|
_VsCodeInstallLocation(
|
|
globals.fs.path.join(homeDirPath, 'Applications', 'Visual Studio Code.app', 'Contents'),
|
|
'.vscode',
|
|
),
|
|
_VsCodeInstallLocation(
|
|
globals.fs.path.join('/Applications', 'Visual Studio Code - Insiders.app', 'Contents'),
|
|
'.vscode-insiders',
|
|
isInsiders: true,
|
|
),
|
|
_VsCodeInstallLocation(
|
|
globals.fs.path.join(homeDirPath, 'Applications', 'Visual Studio Code - Insiders.app', 'Contents'),
|
|
'.vscode-insiders',
|
|
isInsiders: true,
|
|
),
|
|
]);
|
|
}
|
|
|
|
// Windows:
|
|
// $programfiles(x86)\Microsoft VS Code
|
|
// $programfiles(x86)\Microsoft VS Code Insiders
|
|
// User install:
|
|
// $localappdata\Programs\Microsoft VS Code
|
|
// $localappdata\Programs\Microsoft VS Code Insiders
|
|
// TODO(dantup): Confirm these are correct for 64bit
|
|
// $programfiles\Microsoft VS Code
|
|
// $programfiles\Microsoft VS Code Insiders
|
|
// Windows Extensions:
|
|
// $HOME/.vscode/extensions
|
|
// $HOME/.vscode-insiders/extensions
|
|
static List<VsCode> _installedWindows() {
|
|
final String progFiles86 = globals.platform.environment['programfiles(x86)'];
|
|
final String progFiles = globals.platform.environment['programfiles'];
|
|
final String localAppData = globals.platform.environment['localappdata'];
|
|
|
|
final List<_VsCodeInstallLocation> searchLocations =
|
|
<_VsCodeInstallLocation>[];
|
|
|
|
if (localAppData != null) {
|
|
searchLocations.add(_VsCodeInstallLocation(
|
|
globals.fs.path.join(localAppData, 'Programs\\Microsoft VS Code'),
|
|
'.vscode'));
|
|
}
|
|
searchLocations.add(_VsCodeInstallLocation(
|
|
globals.fs.path.join(progFiles86, 'Microsoft VS Code'), '.vscode',
|
|
edition: '32-bit edition'));
|
|
searchLocations.add(_VsCodeInstallLocation(
|
|
globals.fs.path.join(progFiles, 'Microsoft VS Code'), '.vscode',
|
|
edition: '64-bit edition'));
|
|
if (localAppData != null) {
|
|
searchLocations.add(_VsCodeInstallLocation(
|
|
globals.fs.path.join(localAppData, 'Programs\\Microsoft VS Code Insiders'),
|
|
'.vscode-insiders',
|
|
isInsiders: true));
|
|
}
|
|
searchLocations.add(_VsCodeInstallLocation(
|
|
globals.fs.path.join(progFiles86, 'Microsoft VS Code Insiders'),
|
|
'.vscode-insiders',
|
|
edition: '32-bit edition',
|
|
isInsiders: true));
|
|
searchLocations.add(_VsCodeInstallLocation(
|
|
globals.fs.path.join(progFiles, 'Microsoft VS Code Insiders'),
|
|
'.vscode-insiders',
|
|
edition: '64-bit edition',
|
|
isInsiders: true));
|
|
|
|
return _findInstalled(searchLocations);
|
|
}
|
|
|
|
// Linux:
|
|
// /usr/share/code/bin/code
|
|
// /usr/share/code-insiders/bin/code-insiders
|
|
// Linux Extensions:
|
|
// $HOME/.vscode/extensions
|
|
// $HOME/.vscode-insiders/extensions
|
|
static List<VsCode> _installedLinux() {
|
|
return _findInstalled(<_VsCodeInstallLocation>[
|
|
const _VsCodeInstallLocation('/usr/share/code', '.vscode'),
|
|
const _VsCodeInstallLocation('/usr/share/code-insiders', '.vscode-insiders', isInsiders: true),
|
|
]);
|
|
}
|
|
|
|
static List<VsCode> _findInstalled(List<_VsCodeInstallLocation> allLocations) {
|
|
final Iterable<_VsCodeInstallLocation> searchLocations =
|
|
_includeInsiders
|
|
? allLocations
|
|
: allLocations.where((_VsCodeInstallLocation p) => p.isInsiders != true);
|
|
|
|
final List<VsCode> results = <VsCode>[];
|
|
|
|
for (final _VsCodeInstallLocation searchLocation in searchLocations) {
|
|
if (globals.fs.isDirectorySync(searchLocation.installPath)) {
|
|
final String extensionDirectory =
|
|
globals.fs.path.join(homeDirPath, searchLocation.extensionsFolder, 'extensions');
|
|
results.add(VsCode.fromDirectory(searchLocation.installPath, extensionDirectory, edition: searchLocation.edition));
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
@override
|
|
String toString() =>
|
|
'VS Code ($version)${_extensionVersion != Version.unknown ? ', Flutter ($_extensionVersion)' : ''}';
|
|
|
|
static String _getVersionFromPackageJson(String packageJsonPath) {
|
|
if (!globals.fs.isFileSync(packageJsonPath)) {
|
|
return null;
|
|
}
|
|
final String jsonString = globals.fs.file(packageJsonPath).readAsStringSync();
|
|
try {
|
|
final Map<String, dynamic> jsonObject = castStringKeyedMap(json.decode(jsonString));
|
|
return jsonObject['version'] as String;
|
|
} on FormatException catch (err) {
|
|
globals.printTrace('Error parsing VSCode $packageJsonPath:\n$err');
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
class _VsCodeInstallLocation {
|
|
const _VsCodeInstallLocation(this.installPath, this.extensionsFolder, { this.edition, bool isInsiders })
|
|
: isInsiders = isInsiders ?? false;
|
|
final String installPath;
|
|
final String extensionsFolder;
|
|
final String edition;
|
|
final bool isInsiders;
|
|
}
|