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
2d2cd1f5
Unverified
Commit
2d2cd1f5
authored
Dec 29, 2021
by
Christopher Fujino
Committed by
GitHub
Dec 29, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tools] Refactor checkVersionFreshness (#95056)
parent
7addb913
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
185 additions
and
120 deletions
+185
-120
globals.dart
packages/flutter_tools/lib/src/globals.dart
+3
-0
version.dart
packages/flutter_tools/lib/src/version.dart
+154
-92
version_test.dart
packages/flutter_tools/test/general.shard/version_test.dart
+28
-28
No files found.
packages/flutter_tools/lib/src/globals.dart
View file @
2d2cd1f5
...
...
@@ -278,3 +278,6 @@ FlutterProjectFactory get projectFactory {
CustomDevicesConfig
get
customDevicesConfig
=>
context
.
get
<
CustomDevicesConfig
>()!;
PreRunValidator
get
preRunValidator
=>
context
.
get
<
PreRunValidator
>()
??
const
NoOpPreRunValidator
();
// TODO(fujino): Migrate to 'main' https://github.com/flutter/flutter/issues/95041
const
String
kDefaultFrameworkChannel
=
'master'
;
packages/flutter_tools/lib/src/version.dart
View file @
2d2cd1f5
...
...
@@ -18,6 +18,7 @@ const String _unknownFrameworkVersion = '0.0.0-unknown';
/// The names of each channel/branch in order of increasing stability.
enum
Channel
{
// TODO(fujino): update to main https://github.com/flutter/flutter/issues/95041
master
,
dev
,
beta
,
...
...
@@ -26,7 +27,7 @@ enum Channel {
// Beware: Keep order in accordance with stability
const
Set
<
String
>
kOfficialChannels
=
<
String
>{
'master'
,
globals
.
kDefaultFrameworkChannel
,
'dev'
,
'beta'
,
'stable'
,
...
...
@@ -241,15 +242,15 @@ class FlutterVersion {
}
final
DateTime
?
latestFlutterCommitDate
=
await
_getLatestAvailableFlutterDate
();
await
checkVersionFreshness
(
this
,
return
VersionFreshnessValidator
(
version:
this
,
clock:
_clock
,
localFrameworkCommitDate:
localFrameworkCommitDate
,
latestFlutterCommitDate:
latestFlutterCommitDate
,
logger:
globals
.
logger
,
cache:
globals
.
cache
,
pauseTime:
timeToPauseToLetUserReadTheMessage
,
);
pauseTime:
VersionFreshnessValidator
.
timeToPauseToLetUserReadTheMessage
,
)
.
run
()
;
}
/// The name of the temporary git remote used to check for the latest
...
...
@@ -361,13 +362,14 @@ class FlutterVersion {
globals
.
cache
.
checkLockAcquired
();
final
VersionCheckStamp
versionCheckStamp
=
await
VersionCheckStamp
.
load
(
globals
.
cache
,
globals
.
logger
);
final
DateTime
now
=
_clock
.
now
();
if
(
versionCheckStamp
.
lastTimeVersionWasChecked
!=
null
)
{
final
Duration
timeSinceLastCheck
=
_clock
.
now
()
.
difference
(
final
Duration
timeSinceLastCheck
=
now
.
difference
(
versionCheckStamp
.
lastTimeVersionWasChecked
!,
);
// Don't ping the server too often. Return cached value if it's fresh.
if
(
timeSinceLastCheck
<
checkAgeConsideredUpToDate
)
{
if
(
timeSinceLastCheck
<
VersionFreshnessValidator
.
checkAgeConsideredUpToDate
)
{
return
versionCheckStamp
.
lastKnownRemoteVersion
;
}
}
...
...
@@ -378,7 +380,7 @@ class FlutterVersion {
await
FlutterVersion
.
fetchRemoteFrameworkCommitDate
(
channel
),
);
await
versionCheckStamp
.
store
(
newTimeVersionWasChecked:
_clock
.
now
()
,
newTimeVersionWasChecked:
now
,
newKnownRemoteVersion:
remoteFrameworkCommitDate
,
);
return
remoteFrameworkCommitDate
;
...
...
@@ -390,7 +392,7 @@ class FlutterVersion {
// Still update the timestamp to avoid us hitting the server on every single
// command if for some reason we cannot connect (eg. we may be offline).
await
versionCheckStamp
.
store
(
newTimeVersionWasChecked:
_clock
.
now
()
,
newTimeVersionWasChecked:
now
,
);
return
null
;
}
...
...
@@ -743,53 +745,152 @@ enum VersionCheckResult {
newVersionAvailable
,
}
@visibleForTesting
Future
<
void
>
checkVersionFreshness
(
FlutterVersion
version
,
{
required
DateTime
localFrameworkCommitDate
,
required
DateTime
?
latestFlutterCommitDate
,
required
SystemClock
clock
,
required
Cache
cache
,
required
Logger
logger
,
Duration
pauseTime
=
Duration
.
zero
,
})
async
{
// Don't perform update checks if we're not on an official channel.
if
(!
kOfficialChannels
.
contains
(
version
.
channel
))
{
return
;
}
final
Duration
frameworkAge
=
clock
.
now
().
difference
(
localFrameworkCommitDate
);
final
bool
installationSeemsOutdated
=
frameworkAge
>
versionAgeConsideredUpToDate
(
version
.
channel
);
// Get whether there's a newer version on the remote. This only goes
// to the server if we haven't checked recently so won't happen on every
// command.
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
(
cache
,
logger
);
final
DateTime
lastTimeWarningWasPrinted
=
stamp
.
lastTimeWarningWasPrinted
??
clock
.
ago
(
maxTimeSinceLastWarning
*
2
);
final
bool
beenAWhileSinceWarningWasPrinted
=
clock
.
now
().
difference
(
lastTimeWarningWasPrinted
)
>
maxTimeSinceLastWarning
;
// 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
);
if
(
beenAWhileSinceWarningWasPrinted
&&
canShowWarning
)
{
final
String
updateMessage
=
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
?
newVersionAvailableMessage
()
:
versionOutOfDateMessage
(
frameworkAge
);
/// Determine whether or not the provided [version] is "fresh" and notify the user if appropriate.
///
/// To initiate the validation check, call [run].
///
/// We do not want to check with the upstream git remote for newer commits on
/// every tool invocation, as this would significantly slow down running tool
/// commands. Thus, the tool writes to the [VersionCheckStamp] every time that
/// it actually has fetched commits from upstream, and this validator only
/// checks again if it has been more than [checkAgeConsideredUpToDate] since the
/// last fetch.
///
/// We do not want to notify users with "reasonably" fresh versions about new
/// releases. The method [versionAgeConsideredUpToDate] defines a different
/// duration of freshness for each channel. If [localFrameworkCommitDate] is
/// newer than this duration, then we do not show the warning.
///
/// We do not want to annoy users who intentionally disregard the warning and
/// choose not to upgrade. Thus, we only show the message if it has been more
/// than [maxTimeSinceLastWarning] since the last time the user saw the warning.
class
VersionFreshnessValidator
{
VersionFreshnessValidator
({
required
this
.
version
,
required
this
.
localFrameworkCommitDate
,
required
this
.
clock
,
required
this
.
cache
,
required
this
.
logger
,
this
.
latestFlutterCommitDate
,
this
.
pauseTime
=
Duration
.
zero
,
});
final
FlutterVersion
version
;
final
DateTime
localFrameworkCommitDate
;
final
SystemClock
clock
;
final
Cache
cache
;
final
Logger
logger
;
final
Duration
pauseTime
;
final
DateTime
?
latestFlutterCommitDate
;
late
final
DateTime
now
=
clock
.
now
();
late
final
Duration
frameworkAge
=
now
.
difference
(
localFrameworkCommitDate
);
/// The amount of time we wait before pinging the server to check for the
/// availability of a newer version of Flutter.
@visibleForTesting
static
const
Duration
checkAgeConsideredUpToDate
=
Duration
(
days:
3
);
/// The amount of time we wait between issuing a warning.
///
/// This is to avoid annoying users who are unable to upgrade right away.
@visibleForTesting
static
const
Duration
maxTimeSinceLastWarning
=
Duration
(
days:
1
);
/// The amount of time we pause for to let the user read the message about
/// outdated Flutter installation.
///
/// This can be customized in tests to speed them up.
@visibleForTesting
static
Duration
timeToPauseToLetUserReadTheMessage
=
const
Duration
(
seconds:
2
);
// 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.
@visibleForTesting
bool
canShowWarning
(
VersionCheckResult
remoteVersionStatus
)
{
final
bool
installationSeemsOutdated
=
frameworkAge
>
versionAgeConsideredUpToDate
(
version
.
channel
);
if
(
remoteVersionStatus
==
VersionCheckResult
.
newVersionAvailable
)
{
return
true
;
}
if
(!
installationSeemsOutdated
)
{
return
false
;
}
return
remoteVersionStatus
==
VersionCheckResult
.
unknown
;
}
/// We warn the user if the age of their Flutter installation is greater than
/// this duration. The durations are slightly longer than the expected release
/// cadence for each channel, to give the user a grace period before they get
/// notified.
///
/// For example, for the beta channel, this is set to eight weeks because
/// beta releases happen approximately every month.
@visibleForTesting
static
Duration
versionAgeConsideredUpToDate
(
String
channel
)
{
switch
(
channel
)
{
case
'stable'
:
return
const
Duration
(
days:
365
~/
2
);
// Six months
case
'beta'
:
return
const
Duration
(
days:
7
*
8
);
// Eight weeks
case
'dev'
:
return
const
Duration
(
days:
7
*
4
);
// Four weeks
default
:
return
const
Duration
(
days:
7
*
3
);
// Three weeks
}
}
/// Execute validations and print warning to [logger] if necessary.
Future
<
void
>
run
()
async
{
// Don't perform update checks if we're not on an official channel.
if
(!
kOfficialChannels
.
contains
(
version
.
channel
))
{
return
;
}
// Get whether there's a newer version on the remote. This only goes
// to the server if we haven't checked recently so won't happen on every
// command.
final
VersionCheckResult
remoteVersionStatus
;
if
(
latestFlutterCommitDate
==
null
)
{
remoteVersionStatus
=
VersionCheckResult
.
unknown
;
}
else
{
if
(
latestFlutterCommitDate
!.
isAfter
(
localFrameworkCommitDate
))
{
remoteVersionStatus
=
VersionCheckResult
.
newVersionAvailable
;
}
else
{
remoteVersionStatus
=
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
(
cache
,
logger
);
final
DateTime
lastTimeWarningWasPrinted
=
stamp
.
lastTimeWarningWasPrinted
??
clock
.
ago
(
maxTimeSinceLastWarning
*
2
);
final
bool
beenAWhileSinceWarningWasPrinted
=
now
.
difference
(
lastTimeWarningWasPrinted
)
>
maxTimeSinceLastWarning
;
if
(!
beenAWhileSinceWarningWasPrinted
)
{
return
;
}
final
bool
canShowWarningResult
=
canShowWarning
(
remoteVersionStatus
);
if
(!
canShowWarningResult
)
{
return
;
}
// By this point, we should show the update message
final
String
updateMessage
;
switch
(
remoteVersionStatus
)
{
case
VersionCheckResult
.
newVersionAvailable
:
updateMessage
=
newVersionAvailableMessage
();
break
;
case
VersionCheckResult
.
versionIsCurrent
:
case
VersionCheckResult
.
unknown
:
updateMessage
=
versionOutOfDateMessage
(
frameworkAge
);
break
;
}
logger
.
printStatus
(
updateMessage
,
emphasis:
true
);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
stamp
.
store
(
newTimeWarningWasPrinted:
clock
.
now
()
,
newTimeWarningWasPrinted:
now
,
cache:
cache
,
),
Future
<
void
>.
delayed
(
pauseTime
),
...
...
@@ -797,45 +898,6 @@ Future<void> checkVersionFreshness(FlutterVersion version, {
}
}
/// The amount of time we wait before pinging the server to check for the
/// availability of a newer version of Flutter.
@visibleForTesting
const
Duration
checkAgeConsideredUpToDate
=
Duration
(
days:
3
);
/// We warn the user if the age of their Flutter installation is greater than
/// this duration. The durations are slightly longer than the expected release
/// cadence for each channel, to give the user a grace period before they get
/// notified.
///
/// For example, for the beta channel, this is set to five weeks because
/// beta releases happen approximately every month.
@visibleForTesting
Duration
versionAgeConsideredUpToDate
(
String
channel
)
{
switch
(
channel
)
{
case
'stable'
:
return
const
Duration
(
days:
365
~/
2
);
// Six months
case
'beta'
:
return
const
Duration
(
days:
7
*
8
);
// Eight weeks
case
'dev'
:
return
const
Duration
(
days:
7
*
4
);
// Four weeks
default
:
return
const
Duration
(
days:
7
*
3
);
// Three weeks
}
}
/// The amount of time we wait between issuing a warning.
///
/// This is to avoid annoying users who are unable to upgrade right away.
@visibleForTesting
const
Duration
maxTimeSinceLastWarning
=
Duration
(
days:
1
);
/// The amount of time we pause for to let the user read the message about
/// outdated Flutter installation.
///
/// This can be customized in tests to speed them up.
@visibleForTesting
Duration
timeToPauseToLetUserReadTheMessage
=
const
Duration
(
seconds:
2
);
@visibleForTesting
String
versionOutOfDateMessage
(
Duration
frameworkAge
)
{
String
warning
=
'WARNING: your installation of Flutter is
${frameworkAge.inDays}
days old.'
;
...
...
packages/flutter_tools/test/general.shard/version_test.dart
View file @
2d2cd1f5
...
...
@@ -20,8 +20,8 @@ import '../src/context.dart';
import
'../src/fake_process_manager.dart'
;
final
SystemClock
_testClock
=
SystemClock
.
fixed
(
DateTime
(
2015
));
final
DateTime
_stampUpToDate
=
_testClock
.
ago
(
checkAgeConsideredUpToDate
~/
2
);
final
DateTime
_stampOutOfDate
=
_testClock
.
ago
(
checkAgeConsideredUpToDate
*
2
);
final
DateTime
_stampUpToDate
=
_testClock
.
ago
(
VersionFreshnessValidator
.
checkAgeConsideredUpToDate
~/
2
);
final
DateTime
_stampOutOfDate
=
_testClock
.
ago
(
VersionFreshnessValidator
.
checkAgeConsideredUpToDate
*
2
);
void
main
(
)
{
FakeCache
cache
;
...
...
@@ -42,17 +42,17 @@ void main() {
for
(
final
String
channel
in
kOfficialChannels
)
{
DateTime
getChannelUpToDateVersion
()
{
return
_testClock
.
ago
(
versionAgeConsideredUpToDate
(
channel
)
~/
2
);
return
_testClock
.
ago
(
VersionFreshnessValidator
.
versionAgeConsideredUpToDate
(
channel
)
~/
2
);
}
DateTime
getChannelOutOfDateVersion
()
{
return
_testClock
.
ago
(
versionAgeConsideredUpToDate
(
channel
)
*
2
);
return
_testClock
.
ago
(
VersionFreshnessValidator
.
versionAgeConsideredUpToDate
(
channel
)
*
2
);
}
group
(
'
$FlutterVersion
for
$channel
'
,
()
{
setUpAll
(()
{
Cache
.
disableLocking
();
timeToPauseToLetUserReadTheMessage
=
Duration
.
zero
;
VersionFreshnessValidator
.
timeToPauseToLetUserReadTheMessage
=
Duration
.
zero
;
});
testUsingContext
(
'prints nothing when Flutter installation looks fresh'
,
()
async
{
...
...
@@ -151,14 +151,14 @@ void main() {
);
cache
.
versionStamp
=
json
.
encode
(
stamp
);
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelOutOfDateVersion
(),
);
)
.
run
()
;
_expectVersionMessage
(
''
,
logger
);
});
...
...
@@ -172,14 +172,14 @@ void main() {
);
cache
.
versionStamp
=
json
.
encode
(
stamp
);
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
)
.
run
()
;
_expectVersionMessage
(
newVersionAvailableMessage
(),
logger
);
expect
(
cache
.
setVersionStamp
,
true
);
...
...
@@ -195,14 +195,14 @@ void main() {
);
cache
.
versionStamp
=
json
.
encode
(
stamp
);
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
)
.
run
()
;
_expectVersionMessage
(
''
,
logger
);
});
...
...
@@ -212,14 +212,14 @@ void main() {
final
BufferLogger
logger
=
BufferLogger
.
test
();
cache
.
versionStamp
=
'{}'
;
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
)
.
run
()
;
_expectVersionMessage
(
newVersionAvailableMessage
(),
logger
);
expect
(
cache
.
setVersionStamp
,
true
);
...
...
@@ -234,14 +234,14 @@ void main() {
);
cache
.
versionStamp
=
json
.
encode
(
stamp
);
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
getChannelUpToDateVersion
(),
);
)
.
run
()
;
_expectVersionMessage
(
newVersionAvailableMessage
(),
logger
);
});
...
...
@@ -251,14 +251,14 @@ void main() {
final
BufferLogger
logger
=
BufferLogger
.
test
();
cache
.
versionStamp
=
'{}'
;
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelUpToDateVersion
(),
latestFlutterCommitDate:
null
,
// F
ailed to get remote version
);
// latestFlutterCommitDate defaults to null because we f
ailed to get remote version
)
.
run
()
;
_expectVersionMessage
(
''
,
logger
);
});
...
...
@@ -272,14 +272,14 @@ void main() {
);
cache
.
versionStamp
=
json
.
encode
(
stamp
);
await
checkVersionFreshness
(
flutterVersion
,
await
VersionFreshnessValidator
(
version:
flutterVersion
,
cache:
cache
,
clock:
_testClock
,
logger:
logger
,
localFrameworkCommitDate:
getChannelOutOfDateVersion
(),
latestFlutterCommitDate:
null
,
// F
ailed to get remote version
);
// latestFlutterCommitDate defaults to null because we f
ailed to get remote version
)
.
run
()
;
_expectVersionMessage
(
versionOutOfDateMessage
(
_testClock
.
now
().
difference
(
getChannelOutOfDateVersion
())),
logger
);
});
...
...
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