Support using flutter with specific version (#26840)
* Support using flutter with specific version * Set min supported version to 1.2.1
This commit is contained in:
parent
c6cc3cdeda
commit
9f7ab4c4a0
@ -33,6 +33,7 @@ import 'src/commands/test.dart';
|
|||||||
import 'src/commands/trace.dart';
|
import 'src/commands/trace.dart';
|
||||||
import 'src/commands/update_packages.dart';
|
import 'src/commands/update_packages.dart';
|
||||||
import 'src/commands/upgrade.dart';
|
import 'src/commands/upgrade.dart';
|
||||||
|
import 'src/commands/version.dart';
|
||||||
import 'src/runner/flutter_command.dart';
|
import 'src/runner/flutter_command.dart';
|
||||||
|
|
||||||
/// Main entry point for commands.
|
/// Main entry point for commands.
|
||||||
@ -77,6 +78,7 @@ Future<void> main(List<String> args) async {
|
|||||||
TraceCommand(),
|
TraceCommand(),
|
||||||
UpdatePackagesCommand(hidden: !verboseHelp),
|
UpdatePackagesCommand(hidden: !verboseHelp),
|
||||||
UpgradeCommand(),
|
UpgradeCommand(),
|
||||||
|
VersionCommand(),
|
||||||
], verbose: verbose,
|
], verbose: verbose,
|
||||||
muteCommandLogging: muteCommandLogging,
|
muteCommandLogging: muteCommandLogging,
|
||||||
verboseHelp: verboseHelp);
|
verboseHelp: verboseHelp);
|
||||||
|
132
packages/flutter_tools/lib/src/commands/version.dart
Normal file
132
packages/flutter_tools/lib/src/commands/version.dart
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
// Copyright 2019 The Chromium 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/file_system.dart';
|
||||||
|
import '../base/os.dart';
|
||||||
|
import '../base/process.dart';
|
||||||
|
import '../base/version.dart';
|
||||||
|
import '../cache.dart';
|
||||||
|
import '../dart/pub.dart';
|
||||||
|
import '../globals.dart';
|
||||||
|
import '../runner/flutter_command.dart';
|
||||||
|
import '../version.dart';
|
||||||
|
|
||||||
|
class VersionCommand extends FlutterCommand {
|
||||||
|
VersionCommand(): super() {
|
||||||
|
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 {
|
||||||
|
final RunResult runResult = await runCheckedAsync(
|
||||||
|
<String>['git', 'tag', '-l', 'v*'],
|
||||||
|
workingDirectory: Cache.flutterRoot
|
||||||
|
);
|
||||||
|
return runResult.toString().split('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<FlutterCommandResult> runCommand() async {
|
||||||
|
final List<String> tags = await getTags();
|
||||||
|
if (argResults.rest.isEmpty) {
|
||||||
|
tags.forEach(printStatus);
|
||||||
|
return const FlutterCommandResult(ExitStatus.success);
|
||||||
|
}
|
||||||
|
final String version = argResults.rest[0].replaceFirst('v', '');
|
||||||
|
if (!tags.contains('v$version')) {
|
||||||
|
printError('There is no version: $version');
|
||||||
|
}
|
||||||
|
|
||||||
|
// check min supported version
|
||||||
|
final Version targetVersion = Version.parse(version);
|
||||||
|
bool withForce = false;
|
||||||
|
if (targetVersion < minSupportedVersion) {
|
||||||
|
if (!argResults['force']) {
|
||||||
|
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 runCheckedAsync(
|
||||||
|
<String>['git', 'checkout', 'v$version'],
|
||||||
|
workingDirectory: Cache.flutterRoot
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
throwToolExit('Unable to checkout version branch for version $version.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final FlutterVersion flutterVersion = FlutterVersion();
|
||||||
|
|
||||||
|
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.
|
||||||
|
printStatus('');
|
||||||
|
printStatus('Downloading engine...');
|
||||||
|
int code = await runCommandAndStreamOutput(<String>[
|
||||||
|
fs.path.join('bin', 'flutter'),
|
||||||
|
'--no-color',
|
||||||
|
'precache',
|
||||||
|
], workingDirectory: Cache.flutterRoot, allowReentrantFlutter: true);
|
||||||
|
|
||||||
|
if (code != 0) {
|
||||||
|
throwToolExit(null, exitCode: code);
|
||||||
|
}
|
||||||
|
|
||||||
|
printStatus('');
|
||||||
|
printStatus(flutterVersion.toString());
|
||||||
|
|
||||||
|
final String projectRoot = findProjectRoot();
|
||||||
|
if (projectRoot != null) {
|
||||||
|
printStatus('');
|
||||||
|
await pubGet(
|
||||||
|
context: PubContext.pubUpgrade,
|
||||||
|
directory: projectRoot,
|
||||||
|
upgrade: true,
|
||||||
|
checkLastModified: false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run a doctor check in case system requirements have changed.
|
||||||
|
printStatus('');
|
||||||
|
printStatus('Running flutter doctor...');
|
||||||
|
code = await runCommandAndStreamOutput(
|
||||||
|
<String>[
|
||||||
|
fs.path.join('bin', 'flutter'),
|
||||||
|
'doctor',
|
||||||
|
],
|
||||||
|
workingDirectory: Cache.flutterRoot,
|
||||||
|
allowReentrantFlutter: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (code != 0) {
|
||||||
|
throwToolExit(null, exitCode: code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return const FlutterCommandResult(ExitStatus.success);
|
||||||
|
}
|
||||||
|
}
|
121
packages/flutter_tools/test/commands/version_test.dart
Normal file
121
packages/flutter_tools/test/commands/version_test.dart
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// Copyright 2019 The Chromium 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 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter_tools/src/base/io.dart';
|
||||||
|
import 'package:flutter_tools/src/cache.dart';
|
||||||
|
import 'package:flutter_tools/src/commands/version.dart';
|
||||||
|
import 'package:mockito/mockito.dart';
|
||||||
|
import 'package:process/process.dart';
|
||||||
|
|
||||||
|
import '../src/common.dart';
|
||||||
|
import '../src/context.dart';
|
||||||
|
import '../src/mocks.dart' show MockProcess;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('version', () {
|
||||||
|
setUpAll(() {
|
||||||
|
Cache.disableLocking();
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('version ls', () async {
|
||||||
|
final VersionCommand command = VersionCommand();
|
||||||
|
await createTestCommandRunner(command).run(<String>['version']);
|
||||||
|
expect(testLogger.statusText, equals('v10.0.0\r\nv20.0.0\n' ''));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => MockProcessManager(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('version switch', () async {
|
||||||
|
const String version = '10.0.0';
|
||||||
|
final VersionCommand command = VersionCommand();
|
||||||
|
final Future<void> runCommand = createTestCommandRunner(command).run(<String>['version', version]);
|
||||||
|
await Future.wait<void>(<Future<void>>[runCommand]);
|
||||||
|
expect(testLogger.statusText, contains('Switching Flutter to version $version'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => MockProcessManager(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('switch to not supported version without force', () async {
|
||||||
|
const String version = '1.1.5';
|
||||||
|
final VersionCommand command = VersionCommand();
|
||||||
|
final Future<void> runCommand = createTestCommandRunner(command).run(<String>['version', version]);
|
||||||
|
await Future.wait<void>(<Future<void>>[runCommand]);
|
||||||
|
expect(testLogger.errorText, contains('Version command is not supported in'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => MockProcessManager(),
|
||||||
|
});
|
||||||
|
|
||||||
|
testUsingContext('switch to not supported version with force', () async {
|
||||||
|
const String version = '1.1.5';
|
||||||
|
final VersionCommand command = VersionCommand();
|
||||||
|
final Future<void> runCommand = createTestCommandRunner(command).run(<String>['version', '--force', version]);
|
||||||
|
await Future.wait<void>(<Future<void>>[runCommand]);
|
||||||
|
expect(testLogger.statusText, contains('Switching Flutter to version $version with force'));
|
||||||
|
}, overrides: <Type, Generator>{
|
||||||
|
ProcessManager: () => MockProcessManager(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockProcessManager extends Mock implements ProcessManager {
|
||||||
|
String version = '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ProcessResult> run(
|
||||||
|
List<dynamic> command, {
|
||||||
|
String workingDirectory,
|
||||||
|
Map<String, String> environment,
|
||||||
|
bool includeParentEnvironment = true,
|
||||||
|
bool runInShell = false,
|
||||||
|
Encoding stdoutEncoding = systemEncoding,
|
||||||
|
Encoding stderrEncoding = systemEncoding,
|
||||||
|
}) async {
|
||||||
|
if (command[0] == 'git' && command[1] == 'tag') {
|
||||||
|
return ProcessResult(0, 0, 'v10.0.0\r\nv20.0.0', '');
|
||||||
|
}
|
||||||
|
if (command[0] == 'git' && command[1] == 'checkout') {
|
||||||
|
version = command[2];
|
||||||
|
}
|
||||||
|
return ProcessResult(0, 0, '', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ProcessResult runSync(
|
||||||
|
List<dynamic> command, {
|
||||||
|
String workingDirectory,
|
||||||
|
Map<String, String> environment,
|
||||||
|
bool includeParentEnvironment = true,
|
||||||
|
bool runInShell = false,
|
||||||
|
Encoding stdoutEncoding = systemEncoding,
|
||||||
|
Encoding stderrEncoding = systemEncoding,
|
||||||
|
}) {
|
||||||
|
final String commandStr = command.join(' ');
|
||||||
|
if (commandStr == 'git log -n 1 --pretty=format:%H') {
|
||||||
|
return ProcessResult(0, 0, '000000000000000000000', '');
|
||||||
|
}
|
||||||
|
if (commandStr ==
|
||||||
|
'git describe --match v*.*.* --first-parent --long --tags') {
|
||||||
|
if (version.isNotEmpty) {
|
||||||
|
return ProcessResult(0, 0, '$version-0-g00000000', '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ProcessResult(0, 0, '', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Process> start(List<dynamic> command,
|
||||||
|
{String workingDirectory,
|
||||||
|
Map<String, String> environment,
|
||||||
|
bool includeParentEnvironment = true,
|
||||||
|
bool runInShell = false,
|
||||||
|
ProcessStartMode mode = ProcessStartMode.normal}) {
|
||||||
|
final Completer<Process> completer = Completer<Process>();
|
||||||
|
completer.complete(MockProcess());
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user