Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
e2554a92
Unverified
Commit
e2554a92
authored
Feb 13, 2020
by
Jonah Williams
Committed by
GitHub
Feb 13, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add "flutter downgrade" command (#50506)
parent
1f3d423f
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
835 additions
and
66 deletions
+835
-66
executable.dart
packages/flutter_tools/lib/executable.dart
+2
-0
downgrade.dart
packages/flutter_tools/lib/src/commands/downgrade.dart
+191
-0
upgrade.dart
packages/flutter_tools/lib/src/commands/upgrade.dart
+56
-27
version.dart
packages/flutter_tools/lib/src/commands/version.dart
+22
-1
persistent_tool_state.dart
packages/flutter_tools/lib/src/persistent_tool_state.dart
+33
-0
version.dart
packages/flutter_tools/lib/src/version.dart
+54
-11
downgrade_test.dart
...er_tools/test/commands.shard/hermetic/downgrade_test.dart
+249
-0
version_test.dart
...tter_tools/test/commands.shard/hermetic/version_test.dart
+49
-1
upgrade_test.dart
...ter_tools/test/commands.shard/permeable/upgrade_test.dart
+30
-24
persistent_tool_state_test.dart
..._tools/test/general.shard/persistent_tool_state_test.dart
+27
-2
downgrade_upgrade_integration_test.dart
...integration.shard/downgrade_upgrade_integration_test.dart
+122
-0
No files found.
packages/flutter_tools/lib/executable.dart
View file @
e2554a92
...
@@ -25,6 +25,7 @@ import 'src/commands/create.dart';
...
@@ -25,6 +25,7 @@ import 'src/commands/create.dart';
import
'src/commands/daemon.dart'
;
import
'src/commands/daemon.dart'
;
import
'src/commands/devices.dart'
;
import
'src/commands/devices.dart'
;
import
'src/commands/doctor.dart'
;
import
'src/commands/doctor.dart'
;
import
'src/commands/downgrade.dart'
;
import
'src/commands/drive.dart'
;
import
'src/commands/drive.dart'
;
import
'src/commands/emulators.dart'
;
import
'src/commands/emulators.dart'
;
import
'src/commands/format.dart'
;
import
'src/commands/format.dart'
;
...
@@ -76,6 +77,7 @@ Future<void> main(List<String> args) async {
...
@@ -76,6 +77,7 @@ Future<void> main(List<String> args) async {
DaemonCommand
(
hidden:
!
verboseHelp
),
DaemonCommand
(
hidden:
!
verboseHelp
),
DevicesCommand
(),
DevicesCommand
(),
DoctorCommand
(
verbose:
verbose
),
DoctorCommand
(
verbose:
verbose
),
DowngradeCommand
(),
DriveCommand
(),
DriveCommand
(),
EmulatorsCommand
(),
EmulatorsCommand
(),
FormatCommand
(),
FormatCommand
(),
...
...
packages/flutter_tools/lib/src/commands/downgrade.dart
0 → 100644
View file @
e2554a92
// 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
'package:process/process.dart'
;
import
'../base/common.dart'
;
import
'../base/file_system.dart'
;
import
'../base/io.dart'
;
import
'../base/logger.dart'
;
import
'../base/process.dart'
;
import
'../base/terminal.dart'
;
import
'../base/time.dart'
;
import
'../cache.dart'
;
import
'../globals.dart'
as
globals
;
import
'../persistent_tool_state.dart'
;
import
'../runner/flutter_command.dart'
;
import
'../version.dart'
;
/// The flutter downgrade command returns the SDK to the last recorded version
/// for a particular branch.
///
/// For example, suppose a user on the beta channel upgrades from 1.2.3 to 1.4.6.
/// The tool will record that sha "abcdefg" was the last active beta channel in the
/// persistent tool state. If the user is still on the beta channel and runs
/// flutter downgrade, this will take the user back to "abcdefg". They will not be
/// able to downgrade again, since the tool only records one prior version.
/// Additionally, if they had switched channels to stable before trying to downgrade,
/// the command would fail since there was no previously recorded stable version.
class
DowngradeCommand
extends
FlutterCommand
{
DowngradeCommand
({
PersistentToolState
persistentToolState
,
Logger
logger
,
ProcessManager
processManager
,
FlutterVersion
flutterVersion
,
AnsiTerminal
terminal
,
Stdio
stdio
,
FileSystem
fileSystem
,
})
:
_terminal
=
terminal
,
_flutterVersion
=
flutterVersion
,
_persistentToolState
=
persistentToolState
,
_processManager
=
processManager
,
_stdio
=
stdio
,
_logger
=
logger
,
_fileSystem
=
fileSystem
{
argParser
.
addOption
(
'working-directory'
,
hide:
true
,
help:
'Override the downgrade working directory for integration testing.'
);
argParser
.
addFlag
(
'prompt'
,
defaultsTo:
true
,
hide:
true
,
help:
'Disable the downgrade prompt for integration testing.'
);
}
AnsiTerminal
_terminal
;
FlutterVersion
_flutterVersion
;
PersistentToolState
_persistentToolState
;
ProcessUtils
_processUtils
;
ProcessManager
_processManager
;
Logger
_logger
;
Stdio
_stdio
;
FileSystem
_fileSystem
;
@override
String
get
description
=>
'Downgrade Flutter to the last active version for the current channel.'
;
@override
String
get
name
=>
'downgrade'
;
@override
Future
<
FlutterCommandResult
>
runCommand
()
async
{
// Note: commands do not necessarily have access to the correct zone injected
// values when being created. Fields must be lazily instantiated in runCommand,
// at least until the zone injection is refactored.
_terminal
??=
globals
.
terminal
;
_logger
??=
globals
.
logger
;
_flutterVersion
??=
globals
.
flutterVersion
;
_persistentToolState
??=
globals
.
persistentToolState
;
_processManager
??=
globals
.
processManager
;
_processUtils
??=
ProcessUtils
(
processManager:
_processManager
,
logger:
_logger
);
_stdio
??=
globals
.
stdio
;
_fileSystem
??=
globals
.
fs
;
String
workingDirectory
=
Cache
.
flutterRoot
;
if
(
argResults
.
wasParsed
(
'working-directory'
))
{
workingDirectory
=
stringArg
(
'working-directory'
);
_flutterVersion
=
FlutterVersion
(
const
SystemClock
(),
workingDirectory
);
}
final
String
currentChannel
=
_flutterVersion
.
channel
;
final
Channel
channel
=
getChannelForName
(
currentChannel
);
if
(
channel
==
null
)
{
throwToolExit
(
'Flutter is not currently on a known channel. Use "flutter channel <name>" '
'to switch to an official channel.'
,
);
}
final
String
lastFlutterVesion
=
_persistentToolState
.
lastActiveVersion
(
channel
);
final
String
currentFlutterVersion
=
_flutterVersion
.
frameworkRevision
;
if
(
lastFlutterVesion
==
null
||
currentFlutterVersion
==
lastFlutterVesion
)
{
final
String
trailing
=
await
_createErrorMessage
(
workingDirectory
,
channel
);
throwToolExit
(
'There is no previously recorded version for channel "
$currentChannel
".
\n
'
'
$trailing
'
);
}
// Detect unkown versions.
final
RunResult
parseResult
=
await
_processUtils
.
run
(<
String
>[
'git'
,
'describe'
,
'--tags'
,
lastFlutterVesion
,
],
workingDirectory:
workingDirectory
);
if
(
parseResult
.
exitCode
!=
0
)
{
throwToolExit
(
'Failed to parse version for downgrade:
\n
${parseResult.stderr}
'
);
}
final
String
humanReadableVersion
=
parseResult
.
stdout
;
// If there is a terminal attached, prompt the user to confirm the downgrade.
if
(
_stdio
.
hasTerminal
&&
boolArg
(
'prompt'
))
{
_terminal
.
usesTerminalUi
=
true
;
final
String
result
=
await
_terminal
.
promptForCharInput
(
const
<
String
>[
'y'
,
'n'
],
prompt:
'Downgrade flutter to version
$humanReadableVersion
?'
,
logger:
_logger
,
);
if
(
result
==
'n'
)
{
return
FlutterCommandResult
.
success
();
}
}
else
{
_logger
.
printStatus
(
'Downgrading Flutter to version
$humanReadableVersion
'
);
}
// To downgrade the tool, we perform a git checkout --hard, and then
// switch channels. The version recorded must have existed on that branch
// so this operation is safe.
try
{
await
_processUtils
.
run
(
<
String
>[
'git'
,
'reset'
,
'--hard'
,
lastFlutterVesion
],
throwOnError:
true
,
workingDirectory:
workingDirectory
,
);
}
on
ProcessException
catch
(
error
)
{
throwToolExit
(
'Unable to downgrade Flutter: The tool could not update to the version '
'
$humanReadableVersion
. This may be due to git not being installed or an '
'internal error. Please ensure that git is installed on your computer and '
'retry again.
\n
Error:
$error
.'
);
}
try
{
await
_processUtils
.
run
(
<
String
>[
'git'
,
'checkout'
,
currentChannel
,
'--'
],
throwOnError:
true
,
workingDirectory:
workingDirectory
,
);
}
on
ProcessException
catch
(
error
)
{
throwToolExit
(
'Unable to downgrade Flutter: The tool could not switch to the channel '
'
$currentChannel
. This may be due to git not being installed or an '
'internal error. Please ensure that git is installed on your computer '
'and retry again.
\n
Error:
$error
.'
);
}
await
FlutterVersion
.
resetFlutterVersionFreshnessCheck
();
_logger
.
printStatus
(
'Success'
);
return
FlutterCommandResult
.
success
();
}
// Formats an error message that lists the currently stored versions.
Future
<
String
>
_createErrorMessage
(
String
workingDirectory
,
Channel
currentChannel
)
async
{
final
StringBuffer
buffer
=
StringBuffer
();
for
(
final
Channel
channel
in
Channel
.
values
)
{
if
(
channel
==
currentChannel
)
{
continue
;
}
final
String
sha
=
_persistentToolState
.
lastActiveVersion
(
channel
);
if
(
sha
==
null
)
{
continue
;
}
final
RunResult
parseResult
=
await
_processUtils
.
run
(<
String
>[
'git'
,
'describe'
,
'--tags'
,
sha
,
],
workingDirectory:
workingDirectory
);
if
(
parseResult
.
exitCode
==
0
)
{
buffer
.
writeln
(
'Channel "
${getNameForChannel(channel)}
" was previously on:
${parseResult.stdout}
.'
);
}
}
return
buffer
.
toString
();
}
}
packages/flutter_tools/lib/src/commands/upgrade.dart
View file @
e2554a92
...
@@ -10,6 +10,7 @@ import '../base/common.dart';
...
@@ -10,6 +10,7 @@ import '../base/common.dart';
import
'../base/io.dart'
;
import
'../base/io.dart'
;
import
'../base/os.dart'
;
import
'../base/os.dart'
;
import
'../base/process.dart'
;
import
'../base/process.dart'
;
import
'../base/time.dart'
;
import
'../cache.dart'
;
import
'../cache.dart'
;
import
'../dart/pub.dart'
;
import
'../dart/pub.dart'
;
import
'../globals.dart'
as
globals
;
import
'../globals.dart'
as
globals
;
...
@@ -34,6 +35,11 @@ class UpgradeCommand extends FlutterCommand {
...
@@ -34,6 +35,11 @@ class UpgradeCommand extends FlutterCommand {
help:
'For the second half of the upgrade flow requiring the new '
help:
'For the second half of the upgrade flow requiring the new '
'version of Flutter. Should not be invoked manually, but '
'version of Flutter. Should not be invoked manually, but '
're-entrantly by the standard upgrade command.'
,
're-entrantly by the standard upgrade command.'
,
)
..
addOption
(
'working-directory'
,
hide:
true
,
help:
'Override the upgrade working directoy for integration testing.'
);
);
}
}
...
@@ -50,36 +56,50 @@ class UpgradeCommand extends FlutterCommand {
...
@@ -50,36 +56,50 @@ class UpgradeCommand extends FlutterCommand {
@override
@override
Future
<
FlutterCommandResult
>
runCommand
()
{
Future
<
FlutterCommandResult
>
runCommand
()
{
_commandRunner
.
workingDirectory
=
stringArg
(
'working-directory'
)
??
Cache
.
flutterRoot
;
return
_commandRunner
.
runCommand
(
return
_commandRunner
.
runCommand
(
boolArg
(
'force'
),
force:
boolArg
(
'force'
),
boolArg
(
'continue'
),
continueFlow:
boolArg
(
'continue'
),
GitTagVersion
.
determine
(),
testFlow:
stringArg
(
'working-directory'
)
!=
null
,
globals
.
flutterVersion
,
gitTagVersion:
GitTagVersion
.
determine
(
processUtils
),
flutterVersion:
stringArg
(
'working-directory'
)
==
null
?
globals
.
flutterVersion
:
FlutterVersion
(
const
SystemClock
(),
_commandRunner
.
workingDirectory
),
);
);
}
}
}
}
@visibleForTesting
@visibleForTesting
class
UpgradeCommandRunner
{
class
UpgradeCommandRunner
{
Future
<
FlutterCommandResult
>
runCommand
(
bool
force
,
String
workingDirectory
;
bool
continueFlow
,
GitTagVersion
gitTagVersion
,
Future
<
FlutterCommandResult
>
runCommand
({
FlutterVersion
flutterVersion
,
@required
bool
force
,
)
async
{
@required
bool
continueFlow
,
@required
bool
testFlow
,
@required
GitTagVersion
gitTagVersion
,
@required
FlutterVersion
flutterVersion
,
})
async
{
if
(!
continueFlow
)
{
if
(!
continueFlow
)
{
await
runCommandFirstHalf
(
force
,
gitTagVersion
,
flutterVersion
);
await
runCommandFirstHalf
(
force:
force
,
gitTagVersion:
gitTagVersion
,
flutterVersion:
flutterVersion
,
testFlow:
testFlow
,
);
}
else
{
}
else
{
await
runCommandSecondHalf
(
flutterVersion
);
await
runCommandSecondHalf
(
flutterVersion
);
}
}
return
FlutterCommandResult
.
success
();
return
FlutterCommandResult
.
success
();
}
}
Future
<
void
>
runCommandFirstHalf
(
Future
<
void
>
runCommandFirstHalf
({
bool
force
,
@required
bool
force
,
GitTagVersion
gitTagVersion
,
@required
GitTagVersion
gitTagVersion
,
FlutterVersion
flutterVersion
,
@required
FlutterVersion
flutterVersion
,
)
async
{
@required
bool
testFlow
,
})
async
{
await
verifyUpstreamConfigured
();
await
verifyUpstreamConfigured
();
if
(!
force
&&
gitTagVersion
==
const
GitTagVersion
.
unknown
())
{
if
(!
force
&&
gitTagVersion
==
const
GitTagVersion
.
unknown
())
{
// If the commit is a recognized branch and not master,
// If the commit is a recognized branch and not master,
...
@@ -110,6 +130,7 @@ class UpgradeCommandRunner {
...
@@ -110,6 +130,7 @@ class UpgradeCommandRunner {
'command with --force.'
'command with --force.'
);
);
}
}
recordState
(
flutterVersion
);
await
resetChanges
(
gitTagVersion
);
await
resetChanges
(
gitTagVersion
);
await
upgradeChannel
(
flutterVersion
);
await
upgradeChannel
(
flutterVersion
);
final
bool
alreadyUpToDate
=
await
attemptFastForward
(
flutterVersion
);
final
bool
alreadyUpToDate
=
await
attemptFastForward
(
flutterVersion
);
...
@@ -117,11 +138,19 @@ class UpgradeCommandRunner {
...
@@ -117,11 +138,19 @@ class UpgradeCommandRunner {
// If the upgrade was a no op, then do not continue with the second half.
// If the upgrade was a no op, then do not continue with the second half.
globals
.
printStatus
(
'Flutter is already up to date on channel
${flutterVersion.channel}
'
);
globals
.
printStatus
(
'Flutter is already up to date on channel
${flutterVersion.channel}
'
);
globals
.
printStatus
(
'
$flutterVersion
'
);
globals
.
printStatus
(
'
$flutterVersion
'
);
}
else
{
}
else
if
(!
testFlow
)
{
await
flutterUpgradeContinue
();
await
flutterUpgradeContinue
();
}
}
}
}
void
recordState
(
FlutterVersion
flutterVersion
)
{
final
Channel
channel
=
getChannelForName
(
flutterVersion
.
channel
);
if
(
channel
==
null
)
{
return
;
}
globals
.
persistentToolState
.
updateLastActiveVersion
(
flutterVersion
.
frameworkRevision
,
channel
);
}
Future
<
void
>
flutterUpgradeContinue
()
async
{
Future
<
void
>
flutterUpgradeContinue
()
async
{
final
int
code
=
await
processUtils
.
stream
(
final
int
code
=
await
processUtils
.
stream
(
<
String
>[
<
String
>[
...
@@ -130,7 +159,7 @@ class UpgradeCommandRunner {
...
@@ -130,7 +159,7 @@ class UpgradeCommandRunner {
'--continue'
,
'--continue'
,
'--no-version-check'
,
'--no-version-check'
,
],
],
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
allowReentrantFlutter:
true
,
allowReentrantFlutter:
true
,
environment:
Map
<
String
,
String
>.
of
(
globals
.
platform
.
environment
),
environment:
Map
<
String
,
String
>.
of
(
globals
.
platform
.
environment
),
);
);
...
@@ -156,7 +185,7 @@ class UpgradeCommandRunner {
...
@@ -156,7 +185,7 @@ class UpgradeCommandRunner {
final
RunResult
result
=
await
processUtils
.
run
(
final
RunResult
result
=
await
processUtils
.
run
(
<
String
>[
'git'
,
'status'
,
'-s'
],
<
String
>[
'git'
,
'status'
,
'-s'
],
throwOnError:
true
,
throwOnError:
true
,
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
);
);
return
result
.
stdout
.
trim
().
isNotEmpty
;
return
result
.
stdout
.
trim
().
isNotEmpty
;
}
on
ProcessException
catch
(
error
)
{
}
on
ProcessException
catch
(
error
)
{
...
@@ -179,13 +208,13 @@ class UpgradeCommandRunner {
...
@@ -179,13 +208,13 @@ class UpgradeCommandRunner {
await
processUtils
.
run
(
await
processUtils
.
run
(
<
String
>[
'git'
,
'rev-parse'
,
'@{u}'
],
<
String
>[
'git'
,
'rev-parse'
,
'@{u}'
],
throwOnError:
true
,
throwOnError:
true
,
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
);
);
}
catch
(
e
)
{
}
catch
(
e
)
{
throwToolExit
(
throwToolExit
(
'Unable to upgrade Flutter: no origin repository configured. '
'Unable to upgrade Flutter: no origin repository configured. '
"Run 'git remote add origin "
"Run 'git remote add origin "
"https://github.com/flutter/flutter' in
$
{Cache.flutterRoot}
"
,
"https://github.com/flutter/flutter' in
$
workingDirectory
"
,
);
);
}
}
}
}
...
@@ -206,7 +235,7 @@ class UpgradeCommandRunner {
...
@@ -206,7 +235,7 @@ class UpgradeCommandRunner {
await
processUtils
.
run
(
await
processUtils
.
run
(
<
String
>[
'git'
,
'reset'
,
'--hard'
,
tag
],
<
String
>[
'git'
,
'reset'
,
'--hard'
,
tag
],
throwOnError:
true
,
throwOnError:
true
,
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
);
);
}
on
ProcessException
catch
(
error
)
{
}
on
ProcessException
catch
(
error
)
{
throwToolExit
(
throwToolExit
(
...
@@ -223,7 +252,7 @@ class UpgradeCommandRunner {
...
@@ -223,7 +252,7 @@ class UpgradeCommandRunner {
/// If the user is on a deprecated channel, attempts to migrate them off of
/// If the user is on a deprecated channel, attempts to migrate them off of
/// it.
/// it.
Future
<
void
>
upgradeChannel
(
FlutterVersion
flutterVersion
)
async
{
Future
<
void
>
upgradeChannel
(
FlutterVersion
flutterVersion
)
async
{
globals
.
printStatus
(
'Upgrading Flutter from
$
{Cache.flutterRoot}
...'
);
globals
.
printStatus
(
'Upgrading Flutter from
$
workingDirectory
...'
);
await
ChannelCommand
.
upgradeChannel
();
await
ChannelCommand
.
upgradeChannel
();
}
}
...
@@ -237,7 +266,7 @@ class UpgradeCommandRunner {
...
@@ -237,7 +266,7 @@ class UpgradeCommandRunner {
Future
<
bool
>
attemptFastForward
(
FlutterVersion
oldFlutterVersion
)
async
{
Future
<
bool
>
attemptFastForward
(
FlutterVersion
oldFlutterVersion
)
async
{
final
int
code
=
await
processUtils
.
stream
(
final
int
code
=
await
processUtils
.
stream
(
<
String
>[
'git'
,
'pull'
,
'--ff'
],
<
String
>[
'git'
,
'pull'
,
'--ff'
],
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
mapFunction:
(
String
line
)
=>
matchesGitLine
(
line
)
?
null
:
line
,
mapFunction:
(
String
line
)
=>
matchesGitLine
(
line
)
?
null
:
line
,
);
);
if
(
code
!=
0
)
{
if
(
code
!=
0
)
{
...
@@ -247,7 +276,7 @@ class UpgradeCommandRunner {
...
@@ -247,7 +276,7 @@ class UpgradeCommandRunner {
// Check if the upgrade did anything.
// Check if the upgrade did anything.
bool
alreadyUpToDate
=
false
;
bool
alreadyUpToDate
=
false
;
try
{
try
{
final
FlutterVersion
newFlutterVersion
=
FlutterVersion
();
final
FlutterVersion
newFlutterVersion
=
FlutterVersion
(
const
SystemClock
(),
workingDirectory
);
alreadyUpToDate
=
newFlutterVersion
.
channel
==
oldFlutterVersion
.
channel
&&
alreadyUpToDate
=
newFlutterVersion
.
channel
==
oldFlutterVersion
.
channel
&&
newFlutterVersion
.
frameworkRevision
==
oldFlutterVersion
.
frameworkRevision
;
newFlutterVersion
.
frameworkRevision
==
oldFlutterVersion
.
frameworkRevision
;
}
catch
(
e
)
{
}
catch
(
e
)
{
...
@@ -268,7 +297,7 @@ class UpgradeCommandRunner {
...
@@ -268,7 +297,7 @@ class UpgradeCommandRunner {
<
String
>[
<
String
>[
globals
.
fs
.
path
.
join
(
'bin'
,
'flutter'
),
'--no-color'
,
'--no-version-check'
,
'precache'
,
globals
.
fs
.
path
.
join
(
'bin'
,
'flutter'
),
'--no-color'
,
'--no-version-check'
,
'precache'
,
],
],
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
allowReentrantFlutter:
true
,
allowReentrantFlutter:
true
,
environment:
Map
<
String
,
String
>.
of
(
globals
.
platform
.
environment
),
environment:
Map
<
String
,
String
>.
of
(
globals
.
platform
.
environment
),
);
);
...
@@ -296,7 +325,7 @@ class UpgradeCommandRunner {
...
@@ -296,7 +325,7 @@ class UpgradeCommandRunner {
<
String
>[
<
String
>[
globals
.
fs
.
path
.
join
(
'bin'
,
'flutter'
),
'--no-version-check'
,
'doctor'
,
globals
.
fs
.
path
.
join
(
'bin'
,
'flutter'
),
'--no-version-check'
,
'doctor'
,
],
],
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
,
allowReentrantFlutter:
true
,
allowReentrantFlutter:
true
,
);
);
}
}
...
...
packages/flutter_tools/lib/src/commands/version.dart
View file @
e2554a92
...
@@ -57,8 +57,29 @@ class VersionCommand extends FlutterCommand {
...
@@ -57,8 +57,29 @@ class VersionCommand extends FlutterCommand {
final
List
<
String
>
tags
=
await
getTags
();
final
List
<
String
>
tags
=
await
getTags
();
if
(
argResults
.
rest
.
isEmpty
)
{
if
(
argResults
.
rest
.
isEmpty
)
{
tags
.
forEach
(
globals
.
printStatus
);
tags
.
forEach
(
globals
.
printStatus
);
return
const
FlutterCommandResult
(
ExitStatus
.
success
);
return
FlutterCommandResult
.
success
(
);
}
}
globals
.
printStatus
(
'╔══════════════════════════════════════════════════════════════════════════════╗
\n
'
'║ Warning: "flutter version" will leave the SDK in a detached HEAD state. ║
\n
'
'║ If you are using the command to return to a previously installed SDK version ║
\n
'
'║ consider using the "flutter downgrade" command instead. ║
\n
'
'╚══════════════════════════════════════════════════════════════════════════════╝
\n
'
,
emphasis:
true
,
);
if
(
globals
.
stdio
.
stdinHasTerminal
)
{
globals
.
terminal
.
usesTerminalUi
=
true
;
final
String
result
=
await
globals
.
terminal
.
promptForCharInput
(
<
String
>[
'y'
,
'n'
],
logger:
globals
.
logger
,
prompt:
'Are you sure you want to proceed?'
);
if
(
result
==
'n'
)
{
return
FlutterCommandResult
.
success
();
}
}
final
String
version
=
argResults
.
rest
[
0
].
replaceFirst
(
'v'
,
''
);
final
String
version
=
argResults
.
rest
[
0
].
replaceFirst
(
'v'
,
''
);
if
(!
tags
.
contains
(
'v
$version
'
))
{
if
(!
tags
.
contains
(
'v
$version
'
))
{
globals
.
printError
(
'There is no version:
$version
'
);
globals
.
printError
(
'There is no version:
$version
'
);
...
...
packages/flutter_tools/lib/src/persistent_tool_state.dart
View file @
e2554a92
...
@@ -9,6 +9,7 @@ import 'base/config.dart';
...
@@ -9,6 +9,7 @@ import 'base/config.dart';
import
'base/context.dart'
;
import
'base/context.dart'
;
import
'base/file_system.dart'
;
import
'base/file_system.dart'
;
import
'base/logger.dart'
;
import
'base/logger.dart'
;
import
'version.dart'
;
/// A class that represents global (non-project-specific) internal state that
/// A class that represents global (non-project-specific) internal state that
/// must persist across tool invocations.
/// must persist across tool invocations.
...
@@ -37,6 +38,14 @@ abstract class PersistentToolState {
...
@@ -37,6 +38,14 @@ abstract class PersistentToolState {
///
///
/// May give null if the value has not been set.
/// May give null if the value has not been set.
bool
redisplayWelcomeMessage
;
bool
redisplayWelcomeMessage
;
/// Returns the last active version for a given [channel].
///
/// If there was no active prior version, returns `null` instead.
String
lastActiveVersion
(
Channel
channel
);
/// Update the last active version for a given [channel].
void
updateLastActiveVersion
(
String
fullGitHash
,
Channel
channel
);
}
}
class
_DefaultPersistentToolState
implements
PersistentToolState
{
class
_DefaultPersistentToolState
implements
PersistentToolState
{
...
@@ -63,6 +72,12 @@ class _DefaultPersistentToolState implements PersistentToolState {
...
@@ -63,6 +72,12 @@ class _DefaultPersistentToolState implements PersistentToolState {
static
const
String
_kFileName
=
'.flutter_tool_state'
;
static
const
String
_kFileName
=
'.flutter_tool_state'
;
static
const
String
_kRedisplayWelcomeMessage
=
'redisplay-welcome-message'
;
static
const
String
_kRedisplayWelcomeMessage
=
'redisplay-welcome-message'
;
static
const
Map
<
Channel
,
String
>
_lastActiveVersionKeys
=
<
Channel
,
String
>{
Channel
.
master
:
'last-active-master-version'
,
Channel
.
dev
:
'last-active-dev-version'
,
Channel
.
beta
:
'last-active-beta-version'
,
Channel
.
stable
:
'last-active-stable-version'
};
final
Config
_config
;
final
Config
_config
;
...
@@ -71,8 +86,26 @@ class _DefaultPersistentToolState implements PersistentToolState {
...
@@ -71,8 +86,26 @@ class _DefaultPersistentToolState implements PersistentToolState {
return
_config
.
getValue
(
_kRedisplayWelcomeMessage
)
as
bool
;
return
_config
.
getValue
(
_kRedisplayWelcomeMessage
)
as
bool
;
}
}
@override
String
lastActiveVersion
(
Channel
channel
)
{
final
String
versionKey
=
_versionKeyFor
(
channel
);
assert
(
versionKey
!=
null
);
return
_config
.
getValue
(
versionKey
)
as
String
;
}
@override
@override
set
redisplayWelcomeMessage
(
bool
value
)
{
set
redisplayWelcomeMessage
(
bool
value
)
{
_config
.
setValue
(
_kRedisplayWelcomeMessage
,
value
);
_config
.
setValue
(
_kRedisplayWelcomeMessage
,
value
);
}
}
@override
void
updateLastActiveVersion
(
String
fullGitHash
,
Channel
channel
)
{
final
String
versionKey
=
_versionKeyFor
(
channel
);
assert
(
versionKey
!=
null
);
_config
.
setValue
(
versionKey
,
fullGitHash
);
}
String
_versionKeyFor
(
Channel
channel
)
{
return
_lastActiveVersionKeys
[
channel
];
}
}
}
packages/flutter_tools/lib/src/version.dart
View file @
e2554a92
...
@@ -15,14 +15,45 @@ import 'cache.dart';
...
@@ -15,14 +15,45 @@ import 'cache.dart';
import
'convert.dart'
;
import
'convert.dart'
;
import
'globals.dart'
as
globals
;
import
'globals.dart'
as
globals
;
/// The names of each channel/branch in order of increasing stability.
enum
Channel
{
master
,
dev
,
beta
,
stable
,
}
/// Retrieve a human-readable name for a given [channel].
///
/// Requires [FlutterVersion.officialChannels] to be correctly ordered.
String
getNameForChannel
(
Channel
channel
)
{
return
FlutterVersion
.
officialChannels
.
elementAt
(
channel
.
index
);
}
/// Retrieve the [Channel] representation for a string [name].
///
/// Returns `null` if [name] is not in the list of official channels, according
/// to [FlutterVersion.officialChannels].
Channel
getChannelForName
(
String
name
)
{
if
(
FlutterVersion
.
officialChannels
.
contains
(
name
))
{
return
Channel
.
values
[
FlutterVersion
.
officialChannels
.
toList
().
indexOf
(
name
)];
}
return
null
;
}
class
FlutterVersion
{
class
FlutterVersion
{
FlutterVersion
([
this
.
_clock
=
const
SystemClock
()])
{
FlutterVersion
([
this
.
_clock
=
const
SystemClock
(),
this
.
_workingDirectory
])
{
_frameworkRevision
=
_runGit
(
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%H'
]).
join
(
' '
));
_frameworkRevision
=
_runGit
(
_gitTagVersion
=
GitTagVersion
.
determine
();
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%H'
]).
join
(
' '
),
processUtils
,
_workingDirectory
,
);
_gitTagVersion
=
GitTagVersion
.
determine
(
processUtils
,
_workingDirectory
);
_frameworkVersion
=
gitTagVersion
.
frameworkVersionFor
(
_frameworkRevision
);
_frameworkVersion
=
gitTagVersion
.
frameworkVersionFor
(
_frameworkRevision
);
}
}
final
SystemClock
_clock
;
final
SystemClock
_clock
;
final
String
_workingDirectory
;
String
_repositoryUrl
;
String
_repositoryUrl
;
String
get
repositoryUrl
{
String
get
repositoryUrl
{
...
@@ -60,11 +91,19 @@ class FlutterVersion {
...
@@ -60,11 +91,19 @@ class FlutterVersion {
/// `master`, `dev`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, ...
/// `master`, `dev`, `beta`, `stable`; or old ones, like `alpha`, `hackathon`, ...
String
get
channel
{
String
get
channel
{
if
(
_channel
==
null
)
{
if
(
_channel
==
null
)
{
final
String
channel
=
_runGit
(
'git rev-parse --abbrev-ref --symbolic @{u}'
);
final
String
channel
=
_runGit
(
'git rev-parse --abbrev-ref --symbolic @{u}'
,
processUtils
,
_workingDirectory
,
);
final
int
slash
=
channel
.
indexOf
(
'/'
);
final
int
slash
=
channel
.
indexOf
(
'/'
);
if
(
slash
!=
-
1
)
{
if
(
slash
!=
-
1
)
{
final
String
remote
=
channel
.
substring
(
0
,
slash
);
final
String
remote
=
channel
.
substring
(
0
,
slash
);
_repositoryUrl
=
_runGit
(
'git ls-remote --get-url
$remote
'
);
_repositoryUrl
=
_runGit
(
'git ls-remote --get-url
$remote
'
,
processUtils
,
_workingDirectory
,
);
_channel
=
channel
.
substring
(
slash
+
1
);
_channel
=
channel
.
substring
(
slash
+
1
);
}
else
if
(
channel
.
isEmpty
)
{
}
else
if
(
channel
.
isEmpty
)
{
_channel
=
'unknown'
;
_channel
=
'unknown'
;
...
@@ -88,7 +127,11 @@ class FlutterVersion {
...
@@ -88,7 +127,11 @@ class FlutterVersion {
String
_frameworkAge
;
String
_frameworkAge
;
String
get
frameworkAge
{
String
get
frameworkAge
{
return
_frameworkAge
??=
_runGit
(
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%ar'
]).
join
(
' '
));
return
_frameworkAge
??=
_runGit
(
gitLog
(<
String
>[
'-n'
,
'1'
,
'--pretty=format:%ar'
]).
join
(
' '
),
processUtils
,
_workingDirectory
,
);
}
}
String
_frameworkVersion
;
String
_frameworkVersion
;
...
@@ -226,7 +269,7 @@ class FlutterVersion {
...
@@ -226,7 +269,7 @@ class FlutterVersion {
/// the branch name will be returned as `'[user-branch]'`.
/// the branch name will be returned as `'[user-branch]'`.
String
getBranchName
({
bool
redactUnknownBranches
=
false
})
{
String
getBranchName
({
bool
redactUnknownBranches
=
false
})
{
_branch
??=
()
{
_branch
??=
()
{
final
String
branch
=
_runGit
(
'git rev-parse --abbrev-ref HEAD'
);
final
String
branch
=
_runGit
(
'git rev-parse --abbrev-ref HEAD'
,
processUtils
);
return
branch
==
'HEAD'
?
channel
:
branch
;
return
branch
==
'HEAD'
?
channel
:
branch
;
}();
}();
if
(
redactUnknownBranches
||
_branch
.
isEmpty
)
{
if
(
redactUnknownBranches
||
_branch
.
isEmpty
)
{
...
@@ -599,10 +642,10 @@ String _runSync(List<String> command, { bool lenient = true }) {
...
@@ -599,10 +642,10 @@ String _runSync(List<String> command, { bool lenient = true }) {
return
''
;
return
''
;
}
}
String
_runGit
(
String
command
)
{
String
_runGit
(
String
command
,
ProcessUtils
processUtils
,
[
String
workingDirectory
]
)
{
return
processUtils
.
runSync
(
return
processUtils
.
runSync
(
command
.
split
(
' '
),
command
.
split
(
' '
),
workingDirectory:
Cache
.
flutterRoot
,
workingDirectory:
workingDirectory
??
Cache
.
flutterRoot
,
).
stdout
.
trim
();
).
stdout
.
trim
();
}
}
...
@@ -658,8 +701,8 @@ class GitTagVersion {
...
@@ -658,8 +701,8 @@ class GitTagVersion {
/// The git hash (or an abbreviation thereof) for this commit.
/// The git hash (or an abbreviation thereof) for this commit.
final
String
hash
;
final
String
hash
;
static
GitTagVersion
determine
()
{
static
GitTagVersion
determine
(
ProcessUtils
processUtils
,
[
String
workingDirectory
]
)
{
return
parse
(
_runGit
(
'git describe --match v*.*.* --first-parent --long --tags'
));
return
parse
(
_runGit
(
'git describe --match v*.*.* --first-parent --long --tags'
,
processUtils
,
workingDirectory
));
}
}
static
GitTagVersion
parse
(
String
version
)
{
static
GitTagVersion
parse
(
String
version
)
{
...
...
packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart
0 → 100644
View file @
e2554a92
// 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
'package:file/file.dart'
;
import
'package:file/memory.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/terminal.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/commands/downgrade.dart'
;
import
'package:flutter_tools/src/persistent_tool_state.dart'
;
import
'package:flutter_tools/src/version.dart'
;
import
'package:mockito/mockito.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/mocks.dart'
;
void
main
(
)
{
FileSystem
fileSystem
;
BufferLogger
bufferLogger
;
AnsiTerminal
terminal
;
ProcessManager
processManager
;
MockStdio
mockStdio
;
FlutterVersion
flutterVersion
;
setUpAll
(()
{
Cache
.
disableLocking
();
});
tearDownAll
(()
{
Cache
.
enableLocking
();
});
setUp
(()
{
flutterVersion
=
MockFlutterVersion
();
mockStdio
=
MockStdio
();
processManager
=
FakeProcessManager
.
any
();
terminal
=
MockTerminal
();
fileSystem
=
MemoryFileSystem
.
test
();
bufferLogger
=
BufferLogger
(
terminal:
terminal
,
outputPreferences:
OutputPreferences
.
test
());
});
testUsingContext
(
'Downgrade exits on unknown channel'
,
()
async
{
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"invalid"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
),
processManager:
processManager
,
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
expect
(
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]),
throwsToolExit
(
message:
'Flutter is not currently on a known channel.'
));
});
testUsingContext
(
'Downgrade exits on no recorded version'
,
()
async
{
when
(
flutterVersion
.
channel
).
thenReturn
(
'dev'
);
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"abcd"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
),
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--tags'
,
'abcd'
],
exitCode:
0
,
stdout:
'v1.2.3'
)
]),
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
expect
(
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]),
throwsToolExit
(
message:
'There is no previously recorded version for channel "dev".
\n
'
'Channel "master" was previously on: v1.2.3.'
),
);
});
testUsingContext
(
'Downgrade exits on unknown recorded version'
,
()
async
{
when
(
flutterVersion
.
channel
).
thenReturn
(
'master'
);
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"invalid"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
),
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--tags'
,
'invalid'
],
exitCode:
1
,
)
]),
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
expect
(
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]),
throwsToolExit
(
message:
'Failed to parse version for downgrade'
));
});
testUsingContext
(
'Downgrade prompts for user input when terminal is attached - y'
,
()
async
{
when
(
flutterVersion
.
channel
).
thenReturn
(
'master'
);
when
(
mockStdio
.
hasTerminal
).
thenReturn
(
true
);
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"g6b00b5e88"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
),
processManager:
processManager
,
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
when
(
terminal
.
promptForCharInput
(
const
<
String
>[
'y'
,
'n'
],
prompt:
anyNamed
(
'prompt'
),
logger:
anyNamed
(
'logger'
),
)).
thenAnswer
((
Invocation
invocation
)
async
=>
'y'
);
await
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]);
verify
(
terminal
.
promptForCharInput
(
const
<
String
>[
'y'
,
'n'
],
prompt:
anyNamed
(
'prompt'
),
logger:
anyNamed
(
'logger'
),
)).
called
(
1
);
expect
(
bufferLogger
.
statusText
,
contains
(
'Success'
));
});
testUsingContext
(
'Downgrade prompts for user input when terminal is attached - n'
,
()
async
{
when
(
flutterVersion
.
channel
).
thenReturn
(
'master'
);
when
(
mockStdio
.
hasTerminal
).
thenReturn
(
true
);
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"g6b00b5e88"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
),
processManager:
processManager
,
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
when
(
terminal
.
promptForCharInput
(
const
<
String
>[
'y'
,
'n'
],
prompt:
anyNamed
(
'prompt'
),
logger:
anyNamed
(
'logger'
),
)).
thenAnswer
((
Invocation
invocation
)
async
=>
'n'
);
await
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]);
verify
(
terminal
.
promptForCharInput
(
const
<
String
>[
'y'
,
'n'
],
prompt:
anyNamed
(
'prompt'
),
logger:
anyNamed
(
'logger'
),
)).
called
(
1
);
expect
(
bufferLogger
.
statusText
,
isNot
(
contains
(
'Success'
)));
});
testUsingContext
(
'Downgrade does not prompt when there is no terminal'
,
()
async
{
when
(
flutterVersion
.
channel
).
thenReturn
(
'master'
);
when
(
mockStdio
.
hasTerminal
).
thenReturn
(
false
);
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"g6b00b5e88"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
,
),
processManager:
processManager
,
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
await
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]);
verifyNever
(
terminal
.
promptForCharInput
(
const
<
String
>[
'y'
,
'n'
],
prompt:
anyNamed
(
'prompt'
),
logger:
anyNamed
(
'logger'
),
));
expect
(
bufferLogger
.
statusText
,
contains
(
'Success'
));
});
testUsingContext
(
'Downgrade performs correct git commands'
,
()
async
{
when
(
flutterVersion
.
channel
).
thenReturn
(
'master'
);
when
(
mockStdio
.
hasTerminal
).
thenReturn
(
false
);
fileSystem
.
currentDirectory
.
childFile
(
'.flutter_tool_state'
)
.
writeAsStringSync
(
'{"last-active-master-version":"g6b00b5e88"}'
);
final
DowngradeCommand
command
=
DowngradeCommand
(
persistentToolState:
PersistentToolState
.
test
(
directory:
fileSystem
.
currentDirectory
,
logger:
bufferLogger
,
),
processManager:
FakeProcessManager
.
list
(<
FakeCommand
>[
const
FakeCommand
(
command:
<
String
>[
'git'
,
'describe'
,
'--tags'
,
'g6b00b5e88'
],
stdout:
'v1.2.3'
,
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'reset'
,
'--hard'
,
'g6b00b5e88'
],
),
const
FakeCommand
(
command:
<
String
>[
'git'
,
'checkout'
,
'master'
,
'--'
]
),
]),
terminal:
terminal
,
stdio:
mockStdio
,
flutterVersion:
flutterVersion
,
logger:
bufferLogger
,
);
applyMocksToCommand
(
command
);
await
createTestCommandRunner
(
command
).
run
(
const
<
String
>[
'downgrade'
]);
expect
(
bufferLogger
.
statusText
,
contains
(
'Success'
));
});
}
class
MockTerminal
extends
Mock
implements
AnsiTerminal
{}
class
MockStdio
extends
Mock
implements
Stdio
{}
packages/flutter_tools/test/commands.shard/hermetic/version_test.dart
View file @
e2554a92
...
@@ -8,11 +8,13 @@ import 'dart:io';
...
@@ -8,11 +8,13 @@ import 'dart:io';
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:flutter_tools/src/base/common.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/terminal.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/cache.dart'
;
import
'package:flutter_tools/src/commands/version.dart'
;
import
'package:flutter_tools/src/commands/version.dart'
;
import
'package:flutter_tools/src/version.dart'
;
import
'package:flutter_tools/src/version.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
import
'package:process/process.dart'
;
import
'package:flutter_tools/src/globals.dart'
as
globals
;
import
'../../src/common.dart'
;
import
'../../src/common.dart'
;
import
'../../src/context.dart'
;
import
'../../src/context.dart'
;
...
@@ -20,10 +22,18 @@ import '../../src/mocks.dart' show MockProcess;
...
@@ -20,10 +22,18 @@ import '../../src/mocks.dart' show MockProcess;
void
main
(
)
{
void
main
(
)
{
group
(
'version'
,
()
{
group
(
'version'
,
()
{
MockStdio
mockStdio
;
setUpAll
(()
{
setUpAll
(()
{
Cache
.
disableLocking
();
Cache
.
disableLocking
();
});
});
setUp
(()
{
mockStdio
=
MockStdio
();
when
(
mockStdio
.
stdinHasTerminal
).
thenReturn
(
false
);
when
(
mockStdio
.
hasTerminal
).
thenReturn
(
false
);
});
testUsingContext
(
'version ls'
,
()
async
{
testUsingContext
(
'version ls'
,
()
async
{
final
VersionCommand
command
=
VersionCommand
();
final
VersionCommand
command
=
VersionCommand
();
await
createTestCommandRunner
(
command
).
run
(<
String
>[
await
createTestCommandRunner
(
command
).
run
(<
String
>[
...
@@ -33,11 +43,18 @@ void main() {
...
@@ -33,11 +43,18 @@ void main() {
expect
(
testLogger
.
statusText
,
equals
(
'v10.0.0
\r\n
v20.0.0
\n
'
));
expect
(
testLogger
.
statusText
,
equals
(
'v10.0.0
\r\n
v20.0.0
\n
'
));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
ProcessManager:
()
=>
MockProcessManager
(),
Stdio:
()
=>
mockStdio
,
});
});
testUsingContext
(
'version switch'
,
()
async
{
testUsingContext
(
'version switch prompt is accepted'
,
()
async
{
when
(
mockStdio
.
stdinHasTerminal
).
thenReturn
(
true
);
const
String
version
=
'10.0.0'
;
const
String
version
=
'10.0.0'
;
final
VersionCommand
command
=
VersionCommand
();
final
VersionCommand
command
=
VersionCommand
();
when
(
globals
.
terminal
.
promptForCharInput
(<
String
>[
'y'
,
'n'
],
logger:
anyNamed
(
'logger'
),
prompt:
'Are you sure you want to proceed?'
)
).
thenAnswer
((
Invocation
invocation
)
async
=>
'y'
);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'version'
,
'--no-pub'
,
'--no-pub'
,
...
@@ -46,6 +63,29 @@ void main() {
...
@@ -46,6 +63,29 @@ void main() {
expect
(
testLogger
.
statusText
,
contains
(
'Switching Flutter to version
$version
'
));
expect
(
testLogger
.
statusText
,
contains
(
'Switching Flutter to version
$version
'
));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
ProcessManager:
()
=>
MockProcessManager
(),
Stdio:
()
=>
mockStdio
,
AnsiTerminal:
()
=>
MockTerminal
(),
});
testUsingContext
(
'version switch prompt is declined'
,
()
async
{
when
(
mockStdio
.
stdinHasTerminal
).
thenReturn
(
true
);
const
String
version
=
'10.0.0'
;
final
VersionCommand
command
=
VersionCommand
();
when
(
globals
.
terminal
.
promptForCharInput
(<
String
>[
'y'
,
'n'
],
logger:
anyNamed
(
'logger'
),
prompt:
'Are you sure you want to proceed?'
)
).
thenAnswer
((
Invocation
invocation
)
async
=>
'n'
);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
version
,
]);
expect
(
testLogger
.
statusText
,
isNot
(
contains
(
'Switching Flutter to version
$version
'
)));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
Stdio:
()
=>
mockStdio
,
AnsiTerminal:
()
=>
MockTerminal
(),
});
});
testUsingContext
(
'version switch, latest commit query fails'
,
()
async
{
testUsingContext
(
'version switch, latest commit query fails'
,
()
async
{
...
@@ -59,6 +99,7 @@ void main() {
...
@@ -59,6 +99,7 @@ void main() {
expect
(
testLogger
.
errorText
,
contains
(
'git failed'
));
expect
(
testLogger
.
errorText
,
contains
(
'git failed'
));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(
latestCommitFails:
true
),
ProcessManager:
()
=>
MockProcessManager
(
latestCommitFails:
true
),
Stdio:
()
=>
mockStdio
,
});
});
testUsingContext
(
'latest commit is parsable when query fails'
,
()
{
testUsingContext
(
'latest commit is parsable when query fails'
,
()
{
...
@@ -69,6 +110,7 @@ void main() {
...
@@ -69,6 +110,7 @@ void main() {
);
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(
latestCommitFails:
true
),
ProcessManager:
()
=>
MockProcessManager
(
latestCommitFails:
true
),
Stdio:
()
=>
mockStdio
,
});
});
testUsingContext
(
'switch to not supported version without force'
,
()
async
{
testUsingContext
(
'switch to not supported version without force'
,
()
async
{
...
@@ -82,6 +124,7 @@ void main() {
...
@@ -82,6 +124,7 @@ void main() {
expect
(
testLogger
.
errorText
,
contains
(
'Version command is not supported in'
));
expect
(
testLogger
.
errorText
,
contains
(
'Version command is not supported in'
));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
ProcessManager:
()
=>
MockProcessManager
(),
Stdio:
()
=>
mockStdio
,
});
});
testUsingContext
(
'switch to not supported version with force'
,
()
async
{
testUsingContext
(
'switch to not supported version with force'
,
()
async
{
...
@@ -96,6 +139,7 @@ void main() {
...
@@ -96,6 +139,7 @@ void main() {
expect
(
testLogger
.
statusText
,
contains
(
'Switching Flutter to version
$version
with force'
));
expect
(
testLogger
.
statusText
,
contains
(
'Switching Flutter to version
$version
with force'
));
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
ProcessManager:
()
=>
MockProcessManager
(),
Stdio:
()
=>
mockStdio
,
});
});
testUsingContext
(
'tool exit on confusing version'
,
()
async
{
testUsingContext
(
'tool exit on confusing version'
,
()
async
{
...
@@ -111,6 +155,7 @@ void main() {
...
@@ -111,6 +155,7 @@ void main() {
);
);
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
ProcessManager:
()
=>
MockProcessManager
(),
Stdio:
()
=>
mockStdio
,
});
});
testUsingContext
(
"exit tool if can't get the tags"
,
()
async
{
testUsingContext
(
"exit tool if can't get the tags"
,
()
async
{
...
@@ -123,10 +168,13 @@ void main() {
...
@@ -123,10 +168,13 @@ void main() {
}
}
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(
failGitTag:
true
),
ProcessManager:
()
=>
MockProcessManager
(
failGitTag:
true
),
Stdio:
()
=>
mockStdio
,
});
});
});
});
}
}
class
MockTerminal
extends
Mock
implements
AnsiTerminal
{}
class
MockStdio
extends
Mock
implements
Stdio
{}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{
class
MockProcessManager
extends
Mock
implements
ProcessManager
{
MockProcessManager
({
MockProcessManager
({
this
.
failGitTag
=
false
,
this
.
failGitTag
=
false
,
...
...
packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart
View file @
e2554a92
...
@@ -57,10 +57,11 @@ void main() {
...
@@ -57,10 +57,11 @@ void main() {
testUsingContext
(
'throws on unknown tag, official branch, noforce'
,
()
async
{
testUsingContext
(
'throws on unknown tag, official branch, noforce'
,
()
async
{
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
false
,
force:
false
,
false
,
continueFlow:
false
,
const
GitTagVersion
.
unknown
(),
testFlow:
false
,
flutterVersion
,
gitTagVersion:
const
GitTagVersion
.
unknown
(),
flutterVersion:
flutterVersion
,
);
);
expect
(
result
,
throwsToolExit
());
expect
(
result
,
throwsToolExit
());
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -69,10 +70,11 @@ void main() {
...
@@ -69,10 +70,11 @@ void main() {
testUsingContext
(
'does not throw on unknown tag, official branch, force'
,
()
async
{
testUsingContext
(
'does not throw on unknown tag, official branch, force'
,
()
async
{
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
true
,
force:
true
,
false
,
continueFlow:
false
,
const
GitTagVersion
.
unknown
(),
testFlow:
false
,
flutterVersion
,
gitTagVersion:
const
GitTagVersion
.
unknown
(),
flutterVersion:
flutterVersion
,
);
);
expect
(
await
result
,
FlutterCommandResult
.
success
());
expect
(
await
result
,
FlutterCommandResult
.
success
());
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -83,10 +85,11 @@ void main() {
...
@@ -83,10 +85,11 @@ void main() {
testUsingContext
(
'throws tool exit with uncommitted changes'
,
()
async
{
testUsingContext
(
'throws tool exit with uncommitted changes'
,
()
async
{
fakeCommandRunner
.
willHaveUncomittedChanges
=
true
;
fakeCommandRunner
.
willHaveUncomittedChanges
=
true
;
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
false
,
force:
false
,
false
,
continueFlow:
false
,
gitTagVersion
,
testFlow:
false
,
flutterVersion
,
gitTagVersion:
gitTagVersion
,
flutterVersion:
flutterVersion
,
);
);
expect
(
result
,
throwsToolExit
());
expect
(
result
,
throwsToolExit
());
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -97,10 +100,11 @@ void main() {
...
@@ -97,10 +100,11 @@ void main() {
fakeCommandRunner
.
willHaveUncomittedChanges
=
true
;
fakeCommandRunner
.
willHaveUncomittedChanges
=
true
;
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
true
,
force:
true
,
false
,
continueFlow:
false
,
gitTagVersion
,
testFlow:
false
,
flutterVersion
,
gitTagVersion:
gitTagVersion
,
flutterVersion:
flutterVersion
,
);
);
expect
(
await
result
,
FlutterCommandResult
.
success
());
expect
(
await
result
,
FlutterCommandResult
.
success
());
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -110,10 +114,11 @@ void main() {
...
@@ -110,10 +114,11 @@ void main() {
testUsingContext
(
"Doesn't throw on known tag, dev branch, no force"
,
()
async
{
testUsingContext
(
"Doesn't throw on known tag, dev branch, no force"
,
()
async
{
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
false
,
force:
false
,
false
,
continueFlow:
false
,
gitTagVersion
,
testFlow:
false
,
flutterVersion
,
gitTagVersion:
gitTagVersion
,
flutterVersion:
flutterVersion
,
);
);
expect
(
await
result
,
FlutterCommandResult
.
success
());
expect
(
await
result
,
FlutterCommandResult
.
success
());
},
overrides:
<
Type
,
Generator
>{
},
overrides:
<
Type
,
Generator
>{
...
@@ -124,10 +129,11 @@ void main() {
...
@@ -124,10 +129,11 @@ void main() {
testUsingContext
(
"Doesn't continue on known tag, dev branch, no force, already up-to-date"
,
()
async
{
testUsingContext
(
"Doesn't continue on known tag, dev branch, no force, already up-to-date"
,
()
async
{
fakeCommandRunner
.
alreadyUpToDate
=
true
;
fakeCommandRunner
.
alreadyUpToDate
=
true
;
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
final
Future
<
FlutterCommandResult
>
result
=
fakeCommandRunner
.
runCommand
(
false
,
force:
false
,
false
,
continueFlow:
false
,
gitTagVersion
,
testFlow:
false
,
flutterVersion
,
gitTagVersion:
gitTagVersion
,
flutterVersion:
flutterVersion
,
);
);
expect
(
await
result
,
FlutterCommandResult
.
success
());
expect
(
await
result
,
FlutterCommandResult
.
success
());
verifyNever
(
globals
.
processManager
.
start
(
verifyNever
(
globals
.
processManager
.
start
(
...
...
packages/flutter_tools/test/general.shard/persistent_tool_state_test.dart
View file @
e2554a92
...
@@ -6,6 +6,7 @@ import 'package:file/memory.dart';
...
@@ -6,6 +6,7 @@ import 'package:file/memory.dart';
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/persistent_tool_state.dart'
;
import
'package:flutter_tools/src/persistent_tool_state.dart'
;
import
'package:flutter_tools/src/version.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:mockito/mockito.dart'
;
import
'../src/common.dart'
;
import
'../src/common.dart'
;
...
@@ -14,8 +15,8 @@ class MockLogger extends Mock implements Logger {}
...
@@ -14,8 +15,8 @@ class MockLogger extends Mock implements Logger {}
void
main
(
)
{
void
main
(
)
{
testWithoutContext
(
'state can be set and persists'
,
()
{
testWithoutContext
(
'state can be set and persists'
,
()
{
final
MemoryFileSystem
f
s
=
MemoryFileSystem
();
final
MemoryFileSystem
f
ileSystem
=
MemoryFileSystem
();
final
Directory
directory
=
f
s
.
directory
(
'state_dir'
);
final
Directory
directory
=
f
ileSystem
.
directory
(
'state_dir'
);
directory
.
createSync
();
directory
.
createSync
();
final
File
stateFile
=
directory
.
childFile
(
'.flutter_tool_state'
);
final
File
stateFile
=
directory
.
childFile
(
'.flutter_tool_state'
);
final
PersistentToolState
state1
=
PersistentToolState
.
test
(
final
PersistentToolState
state1
=
PersistentToolState
.
test
(
...
@@ -35,4 +36,28 @@ void main() {
...
@@ -35,4 +36,28 @@ void main() {
);
);
expect
(
state2
.
redisplayWelcomeMessage
,
false
);
expect
(
state2
.
redisplayWelcomeMessage
,
false
);
});
});
testWithoutContext
(
'channel versions can be cached and stored'
,
()
{
final
MemoryFileSystem
fileSystem
=
MemoryFileSystem
();
final
Directory
directory
=
fileSystem
.
directory
(
'state_dir'
)..
createSync
();
final
PersistentToolState
state1
=
PersistentToolState
.
test
(
directory:
directory
,
logger:
MockLogger
(),
);
state1
.
updateLastActiveVersion
(
'abc'
,
Channel
.
master
);
state1
.
updateLastActiveVersion
(
'def'
,
Channel
.
dev
);
state1
.
updateLastActiveVersion
(
'ghi'
,
Channel
.
beta
);
state1
.
updateLastActiveVersion
(
'jkl'
,
Channel
.
stable
);
final
PersistentToolState
state2
=
PersistentToolState
.
test
(
directory:
directory
,
logger:
MockLogger
(),
);
expect
(
state2
.
lastActiveVersion
(
Channel
.
master
),
'abc'
);
expect
(
state2
.
lastActiveVersion
(
Channel
.
dev
),
'def'
);
expect
(
state2
.
lastActiveVersion
(
Channel
.
beta
),
'ghi'
);
expect
(
state2
.
lastActiveVersion
(
Channel
.
stable
),
'jkl'
);
});
}
}
packages/flutter_tools/test/integration.shard/downgrade_upgrade_integration_test.dart
0 → 100644
View file @
e2554a92
// 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
'package:flutter_tools/src/base/file_system.dart'
;
import
'package:flutter_tools/src/base/io.dart'
;
import
'package:flutter_tools/src/base/logger.dart'
;
import
'package:flutter_tools/src/base/process.dart'
;
import
'package:flutter_tools/src/base/terminal.dart'
;
import
'package:platform/platform.dart'
;
import
'package:process/process.dart'
;
import
'../src/common.dart'
;
const
String
_kInitialVersion
=
'v1.9.1+hotfix.6'
;
const
String
_kBranch
=
'stable'
;
const
FileSystem
fileSystem
=
LocalFileSystem
();
const
ProcessManager
processManager
=
LocalProcessManager
();
final
ProcessUtils
processUtils
=
ProcessUtils
(
processManager:
processManager
,
logger:
StdoutLogger
(
terminal:
AnsiTerminal
(
platform:
const
LocalPlatform
(),
stdio:
const
Stdio
(),
),
stdio:
const
Stdio
(),
outputPreferences:
OutputPreferences
.
test
(
wrapText:
true
),
timeoutConfiguration:
const
TimeoutConfiguration
(),
));
final
String
flutterBin
=
fileSystem
.
path
.
join
(
getFlutterRoot
(),
'bin'
,
'flutter'
);
/// A test for flutter upgrade & downgrade that checks out a parallel flutter repo.
void
main
(
)
{
Directory
parentDirectory
;
setUp
(()
{
parentDirectory
=
fileSystem
.
systemTempDirectory
.
createTempSync
(
'flutter_tools.'
);
parentDirectory
.
createSync
(
recursive:
true
);
});
tearDown
(()
{
try
{
parentDirectory
.
deleteSync
(
recursive:
true
);
}
on
FileSystemException
{
print
(
'Failed to delete test directory'
);
}
});
test
(
'Can upgrade and downgrade a Flutter checkout'
,
()
async
{
final
Directory
testDirectory
=
parentDirectory
.
childDirectory
(
'flutter'
);
testDirectory
.
createSync
(
recursive:
true
);
// Enable longpaths for windows integration test.
await
processManager
.
run
(<
String
>[
'git'
,
'config'
,
'--system'
,
'core.longpaths'
,
'true'
,
]);
// Step 1. Clone the dev branch of flutter into the test directory.
await
processUtils
.
stream
(<
String
>[
'git'
,
'clone'
,
'https://github.com/flutter/flutter.git'
,
],
workingDirectory:
parentDirectory
.
path
,
trace:
true
);
// Step 2. Switch to the dev branch.
await
processUtils
.
stream
(<
String
>[
'git'
,
'checkout'
,
'--track'
,
'-b'
,
_kBranch
,
'origin/
$_kBranch
'
,
],
workingDirectory:
testDirectory
.
path
,
trace:
true
);
// Step 3. Revert to a prior version.
await
processUtils
.
stream
(<
String
>[
'git'
,
'reset'
,
'--hard'
,
_kInitialVersion
,
],
workingDirectory:
testDirectory
.
path
,
trace:
true
);
// Step 4. Upgrade to the newest dev. This should update the persistent
// tool state with the sha for v1.14.3
await
processUtils
.
stream
(<
String
>[
flutterBin
,
'upgrade'
,
'--working-directory=
${testDirectory.path}
'
],
workingDirectory:
testDirectory
.
path
,
trace:
true
);
// Step 5. Verify that the version is different.
final
RunResult
versionResult
=
await
processUtils
.
run
(<
String
>[
'git'
,
'describe'
,
'--match'
,
'v*.*.*'
,
'--first-parent'
,
'--long'
,
'--tags'
,
],
workingDirectory:
testDirectory
.
path
);
expect
(
versionResult
.
stdout
,
isNot
(
contains
(
_kInitialVersion
)));
// Step 6. Downgrade back to initial version.
await
processUtils
.
stream
(<
String
>[
flutterBin
,
'downgrade'
,
'--no-prompt'
,
'--working-directory=
${testDirectory.path}
'
],
workingDirectory:
testDirectory
.
path
,
trace:
true
);
// Step 7. Verify downgraded version matches original version.
final
RunResult
oldVersionResult
=
await
processUtils
.
run
(<
String
>[
'git'
,
'describe'
,
'--match'
,
'v*.*.*'
,
'--first-parent'
,
'--long'
,
'--tags'
,
],
workingDirectory:
testDirectory
.
path
);
expect
(
oldVersionResult
.
stdout
,
contains
(
_kInitialVersion
));
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment