Unverified Commit 576a455a authored by Francisco Magdaleno's avatar Francisco Magdaleno Committed by GitHub

[windows] Refactor to optimize vswhere queries (#40197)

parent 91af0715
...@@ -18,11 +18,11 @@ class VisualStudio { ...@@ -18,11 +18,11 @@ class VisualStudio {
/// Versions older than 2017 Update 2 won't be detected, so error messages to /// Versions older than 2017 Update 2 won't be detected, so error messages to
/// users should take into account that [false] may mean that the user may /// users should take into account that [false] may mean that the user may
/// have an old version rather than no installation at all. /// have an old version rather than no installation at all.
bool get isInstalled => _bestVisualStudioDetails != null; bool get isInstalled => _bestVisualStudioDetails.isNotEmpty;
/// True if there is a version of Visual Studio with all the components /// True if there is a version of Visual Studio with all the components
/// necessary to build the project. /// necessary to build the project.
bool get hasNecessaryComponents => _usableVisualStudioDetails != null; bool get hasNecessaryComponents => _usableVisualStudioDetails.isNotEmpty;
/// The name of the Visual Studio install. /// The name of the Visual Studio install.
/// ///
...@@ -32,8 +32,12 @@ class VisualStudio { ...@@ -32,8 +32,12 @@ class VisualStudio {
/// The user-friendly version number of the Visual Studio install. /// The user-friendly version number of the Visual Studio install.
/// ///
/// For instance: "15.4.0". /// For instance: "15.4.0".
String get displayVersion => String get displayVersion {
_bestVisualStudioDetails[_catalogKey][_catalogDisplayVersionKey]; if (_bestVisualStudioDetails[_catalogKey] == null) {
return null;
}
return _bestVisualStudioDetails[_catalogKey][_catalogDisplayVersionKey];
}
/// The directory where Visual Studio is installed. /// The directory where Visual Studio is installed.
String get installLocation => _bestVisualStudioDetails[_installationPathKey]; String get installLocation => _bestVisualStudioDetails[_installationPathKey];
...@@ -47,11 +51,25 @@ class VisualStudio { ...@@ -47,11 +51,25 @@ class VisualStudio {
// Visual Studio versions that don't include them, so default to a "valid" value to // Visual Studio versions that don't include them, so default to a "valid" value to
// avoid false negatives. // avoid false negatives.
/// True there is complete installation of Visual Studio. /// True if there is a complete installation of Visual Studio.
bool get isComplete => _bestVisualStudioDetails[_isCompleteKey] ?? false; ///
/// False if installation is not found.
bool get isComplete {
if (_bestVisualStudioDetails.isEmpty) {
return false;
}
return _bestVisualStudioDetails[_isCompleteKey] ?? true;
}
/// True if Visual Studio is launchable. /// True if Visual Studio is launchable.
bool get isLaunchable => _bestVisualStudioDetails[_isLaunchableKey] ?? false; ///
/// False if installation is not found.
bool get isLaunchable {
if (_bestVisualStudioDetails.isEmpty) {
return false;
}
return _bestVisualStudioDetails[_isLaunchableKey] ?? true;
}
/// True if the Visual Studio installation is as pre-release version. /// True if the Visual Studio installation is as pre-release version.
bool get isPrerelease => _bestVisualStudioDetails[_isPrereleaseKey] ?? false; bool get isPrerelease => _bestVisualStudioDetails[_isPrereleaseKey] ?? false;
...@@ -75,7 +93,7 @@ class VisualStudio { ...@@ -75,7 +93,7 @@ class VisualStudio {
/// the components necessary to build. /// the components necessary to build.
String get vcvarsPath { String get vcvarsPath {
final Map<String, dynamic> details = _usableVisualStudioDetails; final Map<String, dynamic> details = _usableVisualStudioDetails;
if (details == null) { if (details.isEmpty) {
return null; return null;
} }
return fs.path.join( return fs.path.join(
...@@ -211,39 +229,56 @@ class VisualStudio { ...@@ -211,39 +229,56 @@ class VisualStudio {
} }
/// Returns the details dictionary for the latest version of Visual Studio /// Returns the details dictionary for the latest version of Visual Studio
/// that has all required components. /// that has all required components, or {} if there is no such installation.
///
/// If no installation is found, the cached VS details are set to an empty map
/// to avoid repeating vswhere queries that have already not found an installation.
Map<String, dynamic> _cachedUsableVisualStudioDetails; Map<String, dynamic> _cachedUsableVisualStudioDetails;
Map<String, dynamic> get _usableVisualStudioDetails { Map<String, dynamic> get _usableVisualStudioDetails {
_cachedUsableVisualStudioDetails ??= if (_cachedUsableVisualStudioDetails != null) {
return _cachedUsableVisualStudioDetails;
}
Map<String, dynamic> visualStudioDetails =
_visualStudioDetails(requiredComponents: _requiredComponents().keys); _visualStudioDetails(requiredComponents: _requiredComponents().keys);
// If a stable version is not found, try searching for a pre-release version. // If a stable version is not found, try searching for a pre-release version.
_cachedUsableVisualStudioDetails ??= _visualStudioDetails( visualStudioDetails ??= _visualStudioDetails(
requiredComponents: _requiredComponents().keys, requiredComponents: _requiredComponents().keys,
additionalArguments: <String>[_prereleaseKey]); additionalArguments: <String>[_prereleaseKey]);
if (_cachedUsableVisualStudioDetails != null) {
if (installationHasIssues(_cachedUsableVisualStudioDetails)) { if (visualStudioDetails != null) {
_cachedAnyVisualStudioDetails = _cachedUsableVisualStudioDetails; if (installationHasIssues(visualStudioDetails)) {
return null; _cachedAnyVisualStudioDetails = visualStudioDetails;
} else {
_cachedUsableVisualStudioDetails = visualStudioDetails;
} }
} }
_cachedUsableVisualStudioDetails ??= <String, dynamic>{};
return _cachedUsableVisualStudioDetails; return _cachedUsableVisualStudioDetails;
} }
/// Returns the details dictionary of the latest version of Visual Studio, /// Returns the details dictionary of the latest version of Visual Studio,
/// regardless of components. /// regardless of components, or {} if no such installation is found.
///
/// If no installation is found, the cached
/// VS details are set to an empty map to avoid repeating vswhere queries that
/// have already not found an installation.
Map<String, dynamic> _cachedAnyVisualStudioDetails; Map<String, dynamic> _cachedAnyVisualStudioDetails;
Map<String, dynamic> get _anyVisualStudioDetails { Map<String, dynamic> get _anyVisualStudioDetails {
// Search for all types of installations. // Search for all types of installations.
_cachedAnyVisualStudioDetails ??= _visualStudioDetails( _cachedAnyVisualStudioDetails ??= _visualStudioDetails(
additionalArguments: <String>[_prereleaseKey, '-all']); additionalArguments: <String>[_prereleaseKey, '-all']);
// Add a sentinel empty value to avoid querying vswhere again.
_cachedAnyVisualStudioDetails ??= <String, dynamic>{};
return _cachedAnyVisualStudioDetails; return _cachedAnyVisualStudioDetails;
} }
/// Returns the details dictionary of the best available version of Visual /// Returns the details dictionary of the best available version of Visual
/// Studio. If there's a version that has all the required components, that /// Studio.
///
/// If there's a version that has all the required components, that
/// will be returned, otherwise returs the lastest installed version (if any). /// will be returned, otherwise returs the lastest installed version (if any).
Map<String, dynamic> get _bestVisualStudioDetails { Map<String, dynamic> get _bestVisualStudioDetails {
if (_usableVisualStudioDetails != null) { if (_usableVisualStudioDetails.isNotEmpty) {
return _usableVisualStudioDetails; return _usableVisualStudioDetails;
} }
return _anyVisualStudioDetails; return _anyVisualStudioDetails;
......
...@@ -184,6 +184,27 @@ void main() { ...@@ -184,6 +184,27 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
}); });
testUsingContext('VisualStudio getters return the right values if no installation is found', () {
setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null);
setMockAnyVisualStudioInstallation(null);
visualStudio = VisualStudio();
expect(visualStudio.isInstalled, false);
expect(visualStudio.hasNecessaryComponents, false);
expect(visualStudio.isComplete, false);
expect(visualStudio.isRebootRequired, false);
expect(visualStudio.isLaunchable, false);
expect(visualStudio.displayName, null);
expect(visualStudio.displayVersion, null);
expect(visualStudio.installLocation, null);
expect(visualStudio.fullVersion, null);
}, overrides: <Type, Generator>{
FileSystem: () => memoryFilesystem,
Platform: () => windowsPlatform,
ProcessManager: () => mockProcessManager,
});
testUsingContext('isInstalled returns true even with missing status information', () { testUsingContext('isInstalled returns true even with missing status information', () {
setMockCompatibleVisualStudioInstallation(null); setMockCompatibleVisualStudioInstallation(null);
setMockPrereleaseVisualStudioInstallation(null); setMockPrereleaseVisualStudioInstallation(null);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment