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
a5d23d2a
Unverified
Commit
a5d23d2a
authored
Jul 30, 2019
by
Zachary Anderson
Committed by
GitHub
Jul 30, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[flutter_tool] More gracefully handle Android sdkmanager failure (#37194)
parent
9357e70d
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
84 additions
and
41 deletions
+84
-41
android_workflow.dart
packages/flutter_tools/lib/src/android/android_workflow.dart
+47
-36
user_messages.dart
packages/flutter_tools/lib/src/base/user_messages.dart
+4
-0
android_workflow_test.dart
...ols/test/general.shard/android/android_workflow_test.dart
+29
-2
mocks.dart
packages/flutter_tools/test/src/mocks.dart
+4
-3
No files found.
packages/flutter_tools/lib/src/android/android_workflow.dart
View file @
a5d23d2a
...
...
@@ -258,25 +258,30 @@ class AndroidLicenseValidator extends DoctorValidator {
return
LicensesAccepted
.
unknown
;
}
final
Process
process
=
await
runCommand
(
<
String
>[
androidSdk
.
sdkManagerPath
,
'--licenses'
],
environment:
androidSdk
.
sdkManagerEnv
,
);
process
.
stdin
.
write
(
'n
\n
'
);
// We expect logcat streams to occasionally contain invalid utf-8,
// see: https://github.com/flutter/flutter/pull/8864.
final
Future
<
void
>
output
=
process
.
stdout
.
transform
<
String
>(
const
Utf8Decoder
(
reportErrors:
false
))
.
transform
<
String
>(
const
LineSplitter
())
.
listen
(
_handleLine
)
.
asFuture
<
void
>(
null
);
final
Future
<
void
>
errors
=
process
.
stderr
.
transform
<
String
>(
const
Utf8Decoder
(
reportErrors:
false
))
.
transform
<
String
>(
const
LineSplitter
())
.
listen
(
_handleLine
)
.
asFuture
<
void
>(
null
);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
output
,
errors
]);
return
status
??
LicensesAccepted
.
unknown
;
try
{
final
Process
process
=
await
runCommand
(
<
String
>[
androidSdk
.
sdkManagerPath
,
'--licenses'
],
environment:
androidSdk
.
sdkManagerEnv
,
);
process
.
stdin
.
write
(
'n
\n
'
);
// We expect logcat streams to occasionally contain invalid utf-8,
// see: https://github.com/flutter/flutter/pull/8864.
final
Future
<
void
>
output
=
process
.
stdout
.
transform
<
String
>(
const
Utf8Decoder
(
reportErrors:
false
))
.
transform
<
String
>(
const
LineSplitter
())
.
listen
(
_handleLine
)
.
asFuture
<
void
>(
null
);
final
Future
<
void
>
errors
=
process
.
stderr
.
transform
<
String
>(
const
Utf8Decoder
(
reportErrors:
false
))
.
transform
<
String
>(
const
LineSplitter
())
.
listen
(
_handleLine
)
.
asFuture
<
void
>(
null
);
await
Future
.
wait
<
void
>(<
Future
<
void
>>[
output
,
errors
]);
return
status
??
LicensesAccepted
.
unknown
;
}
on
ProcessException
catch
(
e
)
{
printTrace
(
'Failed to run Android sdk manager:
$e
'
);
return
LicensesAccepted
.
unknown
;
}
}
/// Run the Android SDK manager tool in order to accept SDK licenses.
...
...
@@ -296,23 +301,29 @@ class AndroidLicenseValidator extends DoctorValidator {
throwToolExit
(
userMessages
.
androidSdkManagerOutdated
(
androidSdk
.
sdkManagerPath
));
}
final
Process
process
=
await
runCommand
(
<
String
>[
androidSdk
.
sdkManagerPath
,
'--licenses'
],
environment:
androidSdk
.
sdkManagerEnv
,
);
// The real stdin will never finish streaming. Pipe until the child process
// finishes.
unawaited
(
process
.
stdin
.
addStream
(
stdin
));
// Wait for stdout and stderr to be fully processed, because process.exitCode
// may complete first.
await
waitGroup
<
void
>(<
Future
<
void
>>[
stdout
.
addStream
(
process
.
stdout
),
stderr
.
addStream
(
process
.
stderr
),
]);
final
int
exitCode
=
await
process
.
exitCode
;
return
exitCode
==
0
;
try
{
final
Process
process
=
await
runCommand
(
<
String
>[
androidSdk
.
sdkManagerPath
,
'--licenses'
],
environment:
androidSdk
.
sdkManagerEnv
,
);
// The real stdin will never finish streaming. Pipe until the child process
// finishes.
unawaited
(
process
.
stdin
.
addStream
(
stdin
));
// Wait for stdout and stderr to be fully processed, because process.exitCode
// may complete first.
await
waitGroup
<
void
>(<
Future
<
void
>>[
stdout
.
addStream
(
process
.
stdout
),
stderr
.
addStream
(
process
.
stderr
),
]);
final
int
exitCode
=
await
process
.
exitCode
;
return
exitCode
==
0
;
}
on
ProcessException
catch
(
e
)
{
throwToolExit
(
userMessages
.
androidCannotRunSdkManager
(
androidSdk
.
sdkManagerPath
,
e
.
toString
()));
return
false
;
}
}
static
bool
_canRunSdkManager
()
{
...
...
packages/flutter_tools/lib/src/base/user_messages.dart
View file @
a5d23d2a
...
...
@@ -102,6 +102,10 @@ class UserMessages {
'Android sdkmanager tool not found (
$sdkManagerPath
).
\n
'
'Try re-installing or updating your Android SDK,
\n
'
'visit https://flutter.dev/setup/#android-setup for detailed instructions.'
;
String
androidCannotRunSdkManager
(
String
sdkManagerPath
,
String
error
)
=>
'Android sdkmanager tool was found, but failed to run (
$sdkManagerPath
): "
$error
".
\n
'
'Try re-installing or updating your Android SDK,
\n
'
'visit https://flutter.dev/setup/#android-setup for detailed instructions.'
;
String
androidSdkBuildToolsOutdated
(
String
managerPath
,
int
sdkMinVersion
,
String
buildToolsMinVersion
)
=>
'Flutter requires Android SDK
$sdkMinVersion
and the Android BuildTools
$buildToolsMinVersion
\n
'
'To update using sdkmanager, run:
\n
'
...
...
packages/flutter_tools/test/general.shard/android/android_workflow_test.dart
View file @
a5d23d2a
...
...
@@ -42,8 +42,22 @@ void main() {
return
(
List
<
String
>
command
)
=>
MockProcess
(
stdout:
stdoutStream
);
}
testUsingContext
(
'licensesAccepted returns LicensesAccepted.unknown if cannot find sdkmanager'
,
()
async
{
processManager
.
canRunSucceeds
=
false
;
when
(
sdk
.
sdkManagerPath
).
thenReturn
(
'/foo/bar/sdkmanager'
);
final
AndroidLicenseValidator
licenseValidator
=
AndroidLicenseValidator
();
final
LicensesAccepted
licenseStatus
=
await
licenseValidator
.
licensesAccepted
;
expect
(
licenseStatus
,
LicensesAccepted
.
unknown
);
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
sdk
,
FileSystem:
()
=>
fs
,
Platform:
()
=>
FakePlatform
()..
environment
=
<
String
,
String
>{
'HOME'
:
'/home/me'
},
ProcessManager:
()
=>
processManager
,
Stdio:
()
=>
stdio
,
});
testUsingContext
(
'licensesAccepted returns LicensesAccepted.unknown if cannot run sdkmanager'
,
()
async
{
processManager
.
succeed
=
false
;
processManager
.
runSucceeds
=
false
;
when
(
sdk
.
sdkManagerPath
).
thenReturn
(
'/foo/bar/sdkmanager'
);
final
AndroidLicenseValidator
licenseValidator
=
AndroidLicenseValidator
();
final
LicensesAccepted
licenseStatus
=
await
licenseValidator
.
licensesAccepted
;
...
...
@@ -168,7 +182,20 @@ void main() {
testUsingContext
(
'runLicenseManager errors when sdkmanager is not found'
,
()
async
{
when
(
sdk
.
sdkManagerPath
).
thenReturn
(
'/foo/bar/sdkmanager'
);
processManager
.
succeed
=
false
;
processManager
.
canRunSucceeds
=
false
;
expect
(
AndroidLicenseValidator
.
runLicenseManager
(),
throwsToolExit
());
},
overrides:
<
Type
,
Generator
>{
AndroidSdk:
()
=>
sdk
,
FileSystem:
()
=>
fs
,
Platform:
()
=>
FakePlatform
()..
environment
=
<
String
,
String
>{
'HOME'
:
'/home/me'
},
ProcessManager:
()
=>
processManager
,
Stdio:
()
=>
stdio
,
});
testUsingContext
(
'runLicenseManager errors when sdkmanager fails to run'
,
()
async
{
when
(
sdk
.
sdkManagerPath
).
thenReturn
(
'/foo/bar/sdkmanager'
);
processManager
.
runSucceeds
=
false
;
expect
(
AndroidLicenseValidator
.
runLicenseManager
(),
throwsToolExit
());
},
overrides:
<
Type
,
Generator
>{
...
...
packages/flutter_tools/test/src/mocks.dart
View file @
a5d23d2a
...
...
@@ -152,11 +152,12 @@ typedef ProcessFactory = Process Function(List<String> command);
/// A ProcessManager that starts Processes by delegating to a ProcessFactory.
class
MockProcessManager
implements
ProcessManager
{
ProcessFactory
processFactory
=
(
List
<
String
>
commands
)
=>
MockProcess
();
bool
succeed
=
true
;
bool
canRunSucceeds
=
true
;
bool
runSucceeds
=
true
;
List
<
String
>
commands
;
@override
bool
canRun
(
dynamic
command
,
{
String
workingDirectory
})
=>
succeed
;
bool
canRun
(
dynamic
command
,
{
String
workingDirectory
})
=>
canRunSucceeds
;
@override
Future
<
Process
>
start
(
...
...
@@ -167,7 +168,7 @@ class MockProcessManager implements ProcessManager {
bool
runInShell
=
false
,
ProcessStartMode
mode
=
ProcessStartMode
.
normal
,
})
{
if
(!
succeed
)
{
if
(!
runSucceeds
)
{
final
String
executable
=
command
[
0
];
final
List
<
String
>
arguments
=
command
.
length
>
1
?
command
.
sublist
(
1
)
:
<
String
>[];
throw
ProcessException
(
executable
,
arguments
);
...
...
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