@@ -735,22 +735,75 @@ Future<void> _runFromList(
735735 }
736736}
737737
738- /// Checks the given file's contents to determine if they match the allowed
739- /// pattern for version strings.
740- ///
741- /// Returns null if the contents are good. Returns a string if they are bad.
742- /// The string is an error message.
743- Future <String ?> verifyVersion (File file) async {
744- final RegExp pattern = RegExp (r'^(\d+)\.(\d+)\.(\d+)((-\d+\.\d+)?\.pre([-\.]\d+)?)?$' );
745- if (! file.existsSync ()) {
746- return 'The version logic failed to create the Flutter version file.' ;
747- }
748- final String version = await file.readAsString ();
749- if (version == '0.0.0-unknown' ) {
750- return 'The version logic failed to determine the Flutter version.' ;
738+ /// Provides access to read and parse the `bin/cache/flutter.version.json` .
739+ sealed class Version {
740+ static final RegExp _pattern = RegExp (r'^(\d+)\.(\d+)\.(\d+)((-\d+\.\d+)?\.pre([-\.]\d+)?)?$' );
741+
742+ /// Attempts to read and resolve the version stored in the [checkoutPath] .
743+ ///
744+ /// If omitted, defaults the current flutter root using the real file system.
745+ static Future <Version > resolveIn ([fs.Directory ? checkoutPath]) async {
746+ checkoutPath ?? = const LocalFileSystem ().directory (flutterRoot);
747+ return resolveFile (
748+ checkoutPath.childDirectory ('bin' ).childDirectory ('cache' ).childFile ('flutter.version.json' ),
749+ );
750+ }
751+
752+ /// Attempts to read and resolve the version stored in [file] .
753+ static Future <Version > resolveFile (fs.File file) async {
754+ if (! file.existsSync ()) {
755+ return VersionError ._(
756+ 'The version logic failed to create the Flutter version file: ${file .path }' ,
757+ contents: null ,
758+ );
759+ }
760+ final Object ? json = jsonDecode (await file.readAsString ());
761+ if (json is ! Map <String , Object ?>) {
762+ return VersionError ._('The version file was in an unexpected format.' , contents: '$json ' );
763+ }
764+ final String ? version = json['flutterVersion' ] as String ? ;
765+ if (version == null ) {
766+ return VersionError ._(
767+ 'The version file was missing the key "flutterVersion".' ,
768+ contents: '$json ' ,
769+ );
770+ }
771+ if (version == '0.0.0-unknown' ) {
772+ return VersionError ._(
773+ 'The version logic failed to determine the Flutter version.' ,
774+ contents: version,
775+ );
776+ }
777+ if (! version.contains (_pattern)) {
778+ return VersionError ._(
779+ 'The version logic generated an invalid version string: "$version ".' ,
780+ contents: version,
781+ );
782+ }
783+ return VersionOk ._(version);
751784 }
752- if (! version.contains (pattern)) {
753- return 'The version logic generated an invalid version string: "$version ".' ;
785+ }
786+
787+ /// A failed result of [Version.resolveFile] .
788+ final class VersionError implements Version {
789+ const VersionError ._(this .error, {required this .contents});
790+
791+ /// Describes the error state.
792+ final String error;
793+
794+ /// The contents of the version file, if any.
795+ final String ? contents;
796+
797+ @override
798+ String toString () {
799+ return error;
754800 }
755- return null ;
801+ }
802+
803+ /// A successful result of [Version.resolveFile] .
804+ final class VersionOk implements Version {
805+ const VersionOk ._(this .version);
806+
807+ /// The contents of the version file, successfully parsed.
808+ final String version;
756809}
0 commit comments