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
e4b809b7
Unverified
Commit
e4b809b7
authored
Nov 27, 2019
by
Zachary Anderson
Committed by
GitHub
Nov 27, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tool] Crash less when git fails during 'version' (#45628)
parent
876303b3
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
151 additions
and
47 deletions
+151
-47
version.dart
packages/flutter_tools/lib/src/commands/version.dart
+2
-1
doctor.dart
packages/flutter_tools/lib/src/doctor.dart
+9
-2
flutter_command.dart
packages/flutter_tools/lib/src/runner/flutter_command.dart
+2
-1
version.dart
packages/flutter_tools/lib/src/version.dart
+73
-24
version_test.dart
...tter_tools/test/commands.shard/hermetic/version_test.dart
+65
-19
No files found.
packages/flutter_tools/lib/src/commands/version.dart
View file @
e4b809b7
...
...
@@ -18,6 +18,7 @@ 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'
,
...
...
@@ -117,7 +118,7 @@ class VersionCommand extends FlutterCommand {
printStatus
(
flutterVersion
.
toString
());
final
String
projectRoot
=
findProjectRoot
();
if
(
projectRoot
!=
null
)
{
if
(
projectRoot
!=
null
&&
shouldRunPub
)
{
printStatus
(
''
);
await
pub
.
get
(
context:
PubContext
.
pubUpgrade
,
...
...
packages/flutter_tools/lib/src/doctor.dart
View file @
e4b809b7
...
...
@@ -596,8 +596,15 @@ class FlutterValidator extends DoctorValidator {
final
FlutterVersion
version
=
FlutterVersion
.
instance
;
versionChannel
=
version
.
channel
;
frameworkVersion
=
version
.
frameworkVersion
;
messages
.
add
(
ValidationMessage
(
userMessages
.
flutterVersion
(
frameworkVersion
,
Cache
.
flutterRoot
)));
messages
.
add
(
ValidationMessage
(
userMessages
.
flutterRevision
(
version
.
frameworkRevisionShort
,
version
.
frameworkAge
,
version
.
frameworkDate
)));
messages
.
add
(
ValidationMessage
(
userMessages
.
flutterVersion
(
frameworkVersion
,
Cache
.
flutterRoot
,
)));
messages
.
add
(
ValidationMessage
(
userMessages
.
flutterRevision
(
version
.
frameworkRevisionShort
,
version
.
frameworkAge
,
version
.
frameworkDate
,
)));
messages
.
add
(
ValidationMessage
(
userMessages
.
engineRevision
(
version
.
engineRevisionShort
)));
messages
.
add
(
ValidationMessage
(
userMessages
.
dartRevision
(
version
.
dartSdkVersion
)));
}
on
VersionCheckError
catch
(
e
)
{
...
...
packages/flutter_tools/lib/src/runner/flutter_command.dart
View file @
e4b809b7
...
...
@@ -173,9 +173,10 @@ abstract class FlutterCommand extends Command<void> {
return
bundle
.
defaultMainPath
;
}
void
usesPubOption
()
{
void
usesPubOption
(
{
bool
hide
=
false
}
)
{
argParser
.
addFlag
(
'pub'
,
defaultsTo:
true
,
hide:
hide
,
help:
'Whether to run "flutter pub get" before executing this command.'
);
_usesPubOption
=
true
;
}
...
...
packages/flutter_tools/lib/src/version.dart
View file @
e4b809b7
...
...
@@ -130,9 +130,19 @@ class FlutterVersion {
};
/// A date String describing the last framework commit.
String
get
frameworkCommitDate
=>
_latestGitCommitDate
();
static
String
_latestGitCommitDate
([
String
branch
])
{
///
/// If a git command fails, this will return a placeholder date.
String
get
frameworkCommitDate
=>
_latestGitCommitDate
(
lenient:
true
);
// The date of the latest commit on the given branch. If no branch is
// specified, then it is the current local branch.
//
// If lenient is true, and the git command fails, a placeholder date is
// returned. Otherwise, the VersionCheckError exception is propagated.
static
String
_latestGitCommitDate
({
String
branch
,
bool
lenient
=
false
,
})
{
final
List
<
String
>
args
=
gitLog
(<
String
>[
if
(
branch
!=
null
)
branch
,
'-n'
,
...
...
@@ -140,7 +150,21 @@ class FlutterVersion {
'--pretty=format:%ad'
,
'--date=iso'
,
]);
return
_runSync
(
args
,
lenient:
false
);
try
{
// Don't plumb 'lenient' through directly so that we can print an error
// if something goes wrong.
return
_runSync
(
args
,
lenient:
false
);
}
on
VersionCheckError
catch
(
e
)
{
if
(
lenient
)
{
final
DateTime
dummyDate
=
DateTime
.
fromMillisecondsSinceEpoch
(
0
);
printError
(
'Failed to find the latest git commit date:
$e
\n
'
'Returning
$dummyDate
instead.'
);
// Return something that DateTime.parse() can parse.
return
dummyDate
.
toString
();
}
else
{
rethrow
;
}
}
}
/// The name of the temporary git remote used to check for the latest
...
...
@@ -153,8 +177,8 @@ class FlutterVersion {
/// The date of the latest framework commit in the remote repository.
///
/// Throws [
ToolExit] if a git command fails, for example, when the remote git
/// repository is not reachable due to a network issue.
/// Throws [
VersionCheckError] if a git command fails, for example, when the
/// re
mote git re
pository is not reachable due to a network issue.
static
Future
<
String
>
fetchRemoteFrameworkCommitDate
(
String
branch
)
async
{
await
_removeVersionCheckRemoteIfExists
();
try
{
...
...
@@ -166,7 +190,10 @@ class FlutterVersion {
'https://github.com/flutter/flutter.git'
,
]);
await
_run
(<
String
>[
'git'
,
'fetch'
,
_versionCheckRemote
,
branch
]);
return
_latestGitCommitDate
(
'
$_versionCheckRemote
/
$branch
'
);
return
_latestGitCommitDate
(
branch:
'
$_versionCheckRemote
/
$branch
'
,
lenient:
false
,
);
}
finally
{
await
_removeVersionCheckRemoteIfExists
();
}
...
...
@@ -219,7 +246,13 @@ class FlutterVersion {
String
tentativeAncestorRevision
,
})
{
final
ProcessResult
result
=
processManager
.
runSync
(
<
String
>[
'git'
,
'merge-base'
,
'--is-ancestor'
,
tentativeAncestorRevision
,
tentativeDescendantRevision
],
<
String
>[
'git'
,
'merge-base'
,
'--is-ancestor'
,
tentativeAncestorRevision
,
tentativeDescendantRevision
],
workingDirectory:
Cache
.
flutterRoot
,
);
return
result
.
exitCode
==
0
;
...
...
@@ -291,7 +324,16 @@ class FlutterVersion {
return
;
}
final
DateTime
localFrameworkCommitDate
=
DateTime
.
parse
(
frameworkCommitDate
);
DateTime
localFrameworkCommitDate
;
try
{
localFrameworkCommitDate
=
DateTime
.
parse
(
_latestGitCommitDate
(
lenient:
false
));
}
on
VersionCheckError
{
// Don't perform the update check if the verison check failed.
return
;
}
final
Duration
frameworkAge
=
_clock
.
now
().
difference
(
localFrameworkCommitDate
);
final
bool
installationSeemsOutdated
=
frameworkAge
>
versionAgeConsideredUpToDate
(
channel
);
...
...
@@ -299,12 +341,11 @@ class FlutterVersion {
// to the server if we haven't checked recently so won't happen on every
// command.
final
DateTime
latestFlutterCommitDate
=
await
_getLatestAvailableFlutterDate
();
final
VersionCheckResult
remoteVersionStatus
=
latestFlutterCommitDate
==
null
?
VersionCheckResult
.
unknown
:
latestFlutterCommitDate
.
isAfter
(
localFrameworkCommitDate
)
?
VersionCheckResult
.
newVersionAvailable
:
VersionCheckResult
.
versionIsCurrent
;
final
VersionCheckResult
remoteVersionStatus
=
latestFlutterCommitDate
==
null
?
VersionCheckResult
.
unknown
:
latestFlutterCommitDate
.
isAfter
(
localFrameworkCommitDate
)
?
VersionCheckResult
.
newVersionAvailable
:
VersionCheckResult
.
versionIsCurrent
;
// Do not load the stamp before the above server check as it may modify the stamp file.
final
VersionCheckStamp
stamp
=
await
VersionCheckStamp
.
load
();
...
...
@@ -314,15 +355,15 @@ class FlutterVersion {
// We show a warning if either we know there is a new remote version, or we couldn't tell but the local
// version is outdated.
final
bool
canShowWarning
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
||
(
remoteVersionStatus
==
VersionCheckResult
.
unknown
&&
installationSeemsOutdated
);
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
||
(
remoteVersionStatus
==
VersionCheckResult
.
unknown
&&
installationSeemsOutdated
);
if
(
beenAWhileSinceWarningWasPrinted
&&
canShowWarning
)
{
final
String
updateMessage
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
?
newVersionAvailableMessage
()
:
versionOutOfDateMessage
(
frameworkAge
);
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
?
newVersionAvailableMessage
()
:
versionOutOfDateMessage
(
frameworkAge
);
printStatus
(
updateMessage
,
emphasis:
true
);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
stamp
.
store
(
...
...
@@ -379,7 +420,9 @@ class FlutterVersion {
final
VersionCheckStamp
versionCheckStamp
=
await
VersionCheckStamp
.
load
();
if
(
versionCheckStamp
.
lastTimeVersionWasChecked
!=
null
)
{
final
Duration
timeSinceLastCheck
=
_clock
.
now
().
difference
(
versionCheckStamp
.
lastTimeVersionWasChecked
);
final
Duration
timeSinceLastCheck
=
_clock
.
now
().
difference
(
versionCheckStamp
.
lastTimeVersionWasChecked
,
);
// Don't ping the server too often. Return cached value if it's fresh.
if
(
timeSinceLastCheck
<
checkAgeConsideredUpToDate
)
{
...
...
@@ -389,7 +432,9 @@ class FlutterVersion {
// Cache is empty or it's been a while since the last server ping. Ping the server.
try
{
final
DateTime
remoteFrameworkCommitDate
=
DateTime
.
parse
(
await
FlutterVersion
.
fetchRemoteFrameworkCommitDate
(
channel
));
final
DateTime
remoteFrameworkCommitDate
=
DateTime
.
parse
(
await
FlutterVersion
.
fetchRemoteFrameworkCommitDate
(
channel
),
);
await
versionCheckStamp
.
store
(
newTimeVersionWasChecked:
_clock
.
now
(),
newKnownRemoteVersion:
remoteFrameworkCommitDate
,
...
...
@@ -533,7 +578,10 @@ class VersionCheckError implements Exception {
/// If [lenient] is true and the command fails, returns an empty string.
/// Otherwise, throws a [ToolExit] exception.
String
_runSync
(
List
<
String
>
command
,
{
bool
lenient
=
true
})
{
final
ProcessResult
results
=
processManager
.
runSync
(
command
,
workingDirectory:
Cache
.
flutterRoot
);
final
ProcessResult
results
=
processManager
.
runSync
(
command
,
workingDirectory:
Cache
.
flutterRoot
,
);
if
(
results
.
exitCode
==
0
)
{
return
(
results
.
stdout
as
String
).
trim
();
...
...
@@ -542,6 +590,7 @@ String _runSync(List<String> command, { bool lenient = true }) {
if
(!
lenient
)
{
throw
VersionCheckError
(
'Command exited with code
${results.exitCode}
:
${command.join(' ')}
\n
'
'Standard out:
${results.stdout}
\n
'
'Standard error:
${results.stderr}
'
);
}
...
...
packages/flutter_tools/test/commands.shard/hermetic/version_test.dart
View file @
e4b809b7
...
...
@@ -10,7 +10,6 @@ import 'package:flutter_tools/src/base/common.dart';
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:flutter_tools/src/dart/pub.dart'
;
import
'package:flutter_tools/src/version.dart'
;
import
'package:mockito/mockito.dart'
;
import
'package:process/process.dart'
;
...
...
@@ -27,60 +26,95 @@ void main() {
testUsingContext
(
'version ls'
,
()
async
{
final
VersionCommand
command
=
VersionCommand
();
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
]);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
]);
expect
(
testLogger
.
statusText
,
equals
(
'v10.0.0
\r\n
v20.0.0
\n
'
''
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
Pub:
()
=>
const
Pub
(),
});
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
]);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
version
,
]);
expect
(
testLogger
.
statusText
,
contains
(
'Switching Flutter to version
$version
'
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
Pub:
()
=>
const
Pub
(),
});
testUsingContext
(
'version switch, latest commit query fails'
,
()
async
{
const
String
version
=
'10.0.0'
;
final
VersionCommand
command
=
VersionCommand
();
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
version
,
]);
expect
(
testLogger
.
errorText
,
contains
(
'git failed'
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(
latestCommitFails:
true
),
});
testUsingContext
(
'latest commit is parsable when query fails'
,
()
{
final
FlutterVersion
flutterVersion
=
FlutterVersion
();
expect
(
()
=>
DateTime
.
parse
(
flutterVersion
.
frameworkCommitDate
),
returnsNormally
,
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(
latestCommitFails:
true
),
});
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
]);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
version
,
]);
expect
(
testLogger
.
errorText
,
contains
(
'Version command is not supported in'
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
Pub:
()
=>
const
Pub
(),
});
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
]);
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
'--force'
,
version
,
]);
expect
(
testLogger
.
statusText
,
contains
(
'Switching Flutter to version
$version
with force'
));
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
Pub:
()
=>
const
Pub
(),
});
testUsingContext
(
'tool exit on confusing version'
,
()
async
{
const
String
version
=
'master'
;
final
VersionCommand
command
=
VersionCommand
();
final
Future
<
void
>
runCommand
=
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
version
]);
expect
(()
async
=>
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
runCommand
]),
throwsA
(
isInstanceOf
<
ToolExit
>()));
expect
(()
async
=>
await
createTestCommandRunner
(
command
).
run
(<
String
>[
'version'
,
'--no-pub'
,
version
,
]),
throwsA
(
isInstanceOf
<
ToolExit
>()),
);
},
overrides:
<
Type
,
Generator
>{
ProcessManager:
()
=>
MockProcessManager
(),
Pub:
()
=>
const
Pub
(),
});
testUsingContext
(
'exit tool if can
\'
t get the tags'
,
()
async
{
final
VersionCommand
command
=
VersionCommand
();
try
{
await
command
.
getTags
();
fail
(
'ToolExit expected'
);
...
...
@@ -94,11 +128,15 @@ void main() {
}
class
MockProcessManager
extends
Mock
implements
ProcessManager
{
MockProcessManager
({
this
.
failGitTag
=
false
});
MockProcessManager
({
this
.
failGitTag
=
false
,
this
.
latestCommitFails
=
false
,
});
String
version
=
''
;
bool
failGitTag
;
final
bool
failGitTag
;
final
bool
latestCommitFails
;
@override
Future
<
ProcessResult
>
run
(
...
...
@@ -142,6 +180,14 @@ class MockProcessManager extends Mock implements ProcessManager {
return
ProcessResult
(
0
,
0
,
'
$version
-0-g00000000'
,
''
);
}
}
final
List
<
String
>
commitDateCommand
=
<
String
>[
'-n'
,
'1'
,
'--pretty=format:%ad'
,
'--date=iso'
,
];
if
(
latestCommitFails
&&
commandStr
==
FlutterVersion
.
gitLog
(
commitDateCommand
).
join
(
' '
))
{
return
ProcessResult
(
0
,
-
9
,
''
,
'git failed'
);
}
return
ProcessResult
(
0
,
0
,
''
,
''
);
}
...
...
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