Adjust how the Sdk class is constructed (#739)

Co-authored-by: Brett Morgan <brett.morgan@gmail.com>
diff --git a/benchmark/bench.dart b/benchmark/bench.dart
index a690631..01f0366 100644
--- a/benchmark/bench.dart
+++ b/benchmark/bench.dart
@@ -19,7 +19,7 @@
 void main(List<String> args) async {
   final json = args.contains('--json');
   final harness = BenchmarkHarness(asJson: json);
-  final compiler = Compiler(Sdk(), nullSafe);
+  final compiler = Compiler(Sdk.create(), nullSafe);
 
   Logger.root.level = Level.WARNING;
   Logger.root.onRecord.listen((LogRecord record) {
diff --git a/lib/src/common_server_impl.dart b/lib/src/common_server_impl.dart
index 65ce0e4..7580b00 100644
--- a/lib/src/common_server_impl.dart
+++ b/lib/src/common_server_impl.dart
@@ -57,7 +57,7 @@
   Future<void> init() async {
     log.info('Beginning CommonServer init().');
     _analysisServers = AnalysisServersWrapper(_nullSafety);
-    _compiler = Compiler(Sdk(), _nullSafety);
+    _compiler = Compiler(Sdk.create(), _nullSafety);
 
     await _compiler.warmup();
     await _analysisServers.warmup();
@@ -151,7 +151,7 @@
   }
 
   Future<proto.VersionResponse> version(proto.VersionRequest _) {
-    final sdk = Sdk();
+    final sdk = Sdk.create();
     final packageVersions = getPackageVersions(nullSafe: _nullSafety);
 
     return Future.value(
diff --git a/lib/src/sdk.dart b/lib/src/sdk.dart
index 61c9b0d..5dfb160 100644
--- a/lib/src/sdk.dart
+++ b/lib/src/sdk.dart
@@ -10,18 +10,26 @@
 import 'package:yaml/yaml.dart';
 
 class Sdk {
-  static late final Sdk _instance = Sdk._();
-  // TODO: eliminate this factory constructor
-  factory Sdk() => _instance;
+  static Sdk? _instance;
 
   /// The current version of the SDK, including any `-dev` suffix.
   final String versionFull;
 
   final String flutterVersion;
 
-  Sdk._()
-      : versionFull = _readVersionFile(sdkPath),
-        flutterVersion = _readVersionFile(flutterSdkPath);
+  /// The current version of the SDK, not including any `-dev` suffix.
+  final String version;
+
+  factory Sdk.create() {
+    return _instance ??= Sdk._(
+        versionFull: _readVersionFile(sdkPath),
+        flutterVersion: _readVersionFile(flutterSdkPath));
+  }
+
+  Sdk._({required this.versionFull, required this.flutterVersion})
+      : version = versionFull.contains('-')
+            ? versionFull.substring(0, versionFull.indexOf('-'))
+            : versionFull;
 
   static String _readVersionFile(String filePath) =>
       (File(path.join(filePath, 'version')).readAsStringSync()).trim();
@@ -35,13 +43,6 @@
 
   /// Get the path to the Flutter binaries.
   static String get flutterBinPath => path.join(flutterSdkPath, 'bin');
-
-  /// Report the current version of the SDK.
-  String get version {
-    var ver = versionFull;
-    if (ver.contains('-')) ver = ver.substring(0, ver.indexOf('-'));
-    return ver;
-  }
 }
 
 class DownloadingSdkManager {
@@ -59,7 +60,7 @@
   /// `flutter-sdk-version.yaml` file.
   ///
   /// Note that this is an expensive operation.
-  Future<Sdk> createFromConfigFile() async {
+  Future<void> createFromConfigFile() async {
     final sdkConfig = getSdkConfigInfo();
 
     // flutter_sdk:
@@ -81,7 +82,7 @@
       return createUsingFlutterVersion(version: config['version'] as String);
     } else {
       // Clone the repo if necessary but don't do any other setup.
-      return (await _cloneSdkIfNecessary()).asSdk();
+      await _cloneSdkIfNecessary();
     }
   }
 
@@ -89,7 +90,7 @@
   /// channel.
   ///
   /// Note that this is an expensive operation.
-  Future<Sdk> createUsingFlutterChannel({
+  Future<void> createUsingFlutterChannel({
     required String channel,
   }) async {
     final sdk = await _cloneSdkIfNecessary();
@@ -106,15 +107,13 @@
 
     // git pull
     await sdk.pull();
-
-    return sdk.asSdk();
   }
 
   /// Create a Flutter SDK in `flutter-sdk/` that tracks a specific Flutter
   /// version.
   ///
   /// Note that this is an expensive operation.
-  Future<Sdk> createUsingFlutterVersion({
+  Future<void> createUsingFlutterVersion({
     required String version,
   }) async {
     final sdk = await _cloneSdkIfNecessary();
@@ -128,8 +127,6 @@
 
     // Force downloading of Dart SDK before constructing the Sdk singleton.
     await sdk.init();
-
-    return sdk.asSdk();
   }
 
   Future<_DownloadedFlutterSdk> _cloneSdkIfNecessary() async {
@@ -159,12 +156,10 @@
   _DownloadedFlutterSdk(this.flutterSdkPath);
 
   Future<void> init() async {
-    // flutter --version takes ~28s
+    // `flutter --version` takes ~28s.
     await _execLog('bin/flutter', ['--version'], flutterSdkPath);
   }
 
-  Sdk asSdk() => Sdk();
-
   String get sdkPath => path.join(flutterSdkPath, 'bin/cache/dart-sdk');
 
   String get versionFull =>
diff --git a/lib/src/server_cache.dart b/lib/src/server_cache.dart
index e6a6561..61fa4f6 100644
--- a/lib/src/server_cache.dart
+++ b/lib/src/server_cache.dart
@@ -143,7 +143,7 @@
   /// We don't use the existing key directly so that different AppEngine
   /// versions using the same redis cache do not have collisions.
   String _genKey(String key) {
-    final sdk = Sdk();
+    final sdk = Sdk.create();
     // the `rc` here is a differentiator to keep the `resp_client` documents
     // separate from the `dartis` documents.
     return 'server:rc:$serverVersion:dart:${sdk.versionFull}:flutter:${sdk.flutterVersion}+$key';
diff --git a/test/compiler_test.dart b/test/compiler_test.dart
index 0d894b5..023114b 100644
--- a/test/compiler_test.dart
+++ b/test/compiler_test.dart
@@ -17,7 +17,7 @@
   for (final nullSafety in [false, true]) {
     group('Null ${nullSafety ? 'Safe' : 'Unsafe'} Compiler', () {
       setUpAll(() async {
-        compiler = Compiler(Sdk(), nullSafety);
+        compiler = Compiler(Sdk.create(), nullSafety);
         await compiler.warmup();
       });
 
diff --git a/tool/fuzz_driver.dart b/tool/fuzz_driver.dart
index 1b2ac78..d6c264d 100644
--- a/tool/fuzz_driver.dart
+++ b/tool/fuzz_driver.dart
@@ -133,7 +133,7 @@
   await analysisServer!.warmup();
 
   print('Warming up compiler');
-  compiler = comp.Compiler(Sdk(), false);
+  compiler = comp.Compiler(Sdk.create(), false);
   await compiler.warmup();
   print('SetupTools done');
 }
diff --git a/tool/grind.dart b/tool/grind.dart
index 84e884b..43d0675 100644
--- a/tool/grind.dart
+++ b/tool/grind.dart
@@ -86,7 +86,7 @@
     'google storage')
 @Depends(sdkInit)
 void validateStorageArtifacts() async {
-  final version = Sdk().versionFull;
+  final version = Sdk.create().versionFull;
 
   const nullUnsafeUrlBase =
       'https://storage.googleapis.com/compilation_artifacts/';
@@ -296,7 +296,7 @@
   copy(joinFile(dir, ['flutter_web.dill']), artifactsDir);
 
   // Emit some good google storage upload instructions.
-  final version = Sdk().versionFull;
+  final version = Sdk.create().versionFull;
   return ('  gsutil -h "Cache-Control: public, max-age=604800, immutable" cp -z js ${artifactsDir.path}/*.js'
       ' gs://${nullSafety ? 'nnbd_artifacts' : 'compilation_artifacts'}/$version/');
 }