// 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 'dart:async'; import '../base/common.dart'; import '../base/io.dart'; import '../base/os.dart'; import '../base/process.dart'; import '../base/version.dart'; import '../cache.dart'; import '../dart/pub.dart'; import '../globals.dart' as globals; import '../runner/flutter_command.dart'; import '../version.dart'; class VersionCommand extends FlutterCommand { VersionCommand() : super() { usesPubOption(hide: true); argParser.addFlag('force', abbr: 'f', help: 'Force switch to older Flutter versions that do not include a version command', ); } @override final String name = 'version'; @override final String description = 'List or switch flutter versions.'; // The first version of Flutter which includes the flutter version command. Switching to older // versions will require the user to manually upgrade. Version minSupportedVersion = Version.parse('1.2.1'); Future<List<String>> getTags() async { RunResult runResult; try { runResult = await processUtils.run( <String>['git', 'tag', '-l', 'v*', '--sort=-creatordate'], throwOnError: true, workingDirectory: Cache.flutterRoot, ); } on ProcessException catch (error) { throwToolExit( 'Unable to get the tags. ' 'This might be due to git not being installed or an internal error' '\nError: $error.' ); } return runResult.toString().split('\n'); } @override Future<FlutterCommandResult> runCommand() async { final List<String> tags = await getTags(); if (argResults.rest.isEmpty) { tags.forEach(globals.printStatus); return const FlutterCommandResult(ExitStatus.success); } final String version = argResults.rest[0].replaceFirst('v', ''); if (!tags.contains('v$version')) { globals.printError('There is no version: $version'); } // check min supported version final Version targetVersion = Version.parse(version); if (targetVersion == null) { throwToolExit('Failed to parse version "$version"'); } bool withForce = false; if (targetVersion < minSupportedVersion) { if (!boolArg('force')) { globals.printError( 'Version command is not supported in $targetVersion and it is supported since version $minSupportedVersion' 'which means if you switch to version $minSupportedVersion then you can not use version command.' 'If you really want to switch to version $targetVersion, please use `--force` flag: `flutter version --force $targetVersion`.' ); return const FlutterCommandResult(ExitStatus.success); } withForce = true; } try { await processUtils.run( <String>['git', 'checkout', 'v$version'], throwOnError: true, workingDirectory: Cache.flutterRoot, ); } catch (e) { throwToolExit('Unable to checkout version branch for version $version.'); } final FlutterVersion flutterVersion = FlutterVersion(); globals.printStatus('Switching Flutter to version ${flutterVersion.frameworkVersion}${withForce ? ' with force' : ''}'); // Check for and download any engine and pkg/ updates. // We run the 'flutter' shell script re-entrantly here // so that it will download the updated Dart and so forth // if necessary. globals.printStatus(''); globals.printStatus('Downloading engine...'); int code = await processUtils.stream(<String>[ globals.fs.path.join('bin', 'flutter'), '--no-color', 'precache', ], workingDirectory: Cache.flutterRoot, allowReentrantFlutter: true); if (code != 0) { throwToolExit(null, exitCode: code); } globals.printStatus(''); globals.printStatus(flutterVersion.toString()); final String projectRoot = findProjectRoot(); if (projectRoot != null && shouldRunPub) { globals.printStatus(''); await pub.get( context: PubContext.pubUpgrade, directory: projectRoot, upgrade: true, checkLastModified: false, ); } // Run a doctor check in case system requirements have changed. globals.printStatus(''); globals.printStatus('Running flutter doctor...'); code = await processUtils.stream( <String>[ globals.fs.path.join('bin', 'flutter'), 'doctor', ], workingDirectory: Cache.flutterRoot, allowReentrantFlutter: true, ); if (code != 0) { throwToolExit(null, exitCode: code); } return FlutterCommandResult.success(); } }