Unverified Commit a15a81be authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Fix androidSdk NPE (#47187)

parent 1cdf0f44
......@@ -86,7 +86,7 @@ class _AndroidBuilderImpl extends AndroidBuilder {
buildNumber: buildNumber,
);
} finally {
androidSdk.reinitialize();
androidSdk?.reinitialize();
}
}
......@@ -106,7 +106,7 @@ class _AndroidBuilderImpl extends AndroidBuilder {
localGradleErrors: gradleErrors,
);
} finally {
androidSdk.reinitialize();
androidSdk?.reinitialize();
}
}
......@@ -126,7 +126,7 @@ class _AndroidBuilderImpl extends AndroidBuilder {
localGradleErrors: gradleErrors,
);
} finally {
androidSdk.reinitialize();
androidSdk?.reinitialize();
}
}
}
......@@ -55,7 +55,7 @@ String getAdbPath([ AndroidSdk existingSdk ]) {
if (sdk?.latestVersion == null) {
return os.which('adb')?.path;
} else {
return sdk.adbPath;
return sdk?.adbPath;
}
}
......
......@@ -149,7 +149,7 @@ Future<void> checkGradleDependencies() async {
workingDirectory: flutterProject.android.hostAppGradleRoot.path,
environment: gradleEnvironment,
);
androidSdk.reinitialize();
androidSdk?.reinitialize();
progress.stop();
}
......@@ -224,9 +224,13 @@ Future<void> buildGradleApp({
bool shouldBuildPluginAsAar = false,
int retries = 1,
}) async {
if (androidSdk == null) {
exitWithNoSdkMessage();
}
assert(project != null);
assert(androidBuildInfo != null);
assert(target != null);
assert(isBuildingBundle != null);
assert(localGradleErrors != null);
assert(androidSdk != null);
if (!project.android.isUsingGradle) {
_exitWithProjectNotUsingGradleMessage();
}
......@@ -489,10 +493,7 @@ Future<void> buildGradleAar({
assert(target != null);
assert(androidBuildInfo != null);
assert(outputDirectory != null);
if (androidSdk == null) {
exitWithNoSdkMessage();
}
assert(androidSdk != null);
final FlutterManifest manifest = project.manifest;
if (!manifest.isModule && !manifest.isPlugin) {
......
......@@ -41,7 +41,7 @@ class ApplicationPackageFactory {
case TargetPlatform.android_arm64:
case TargetPlatform.android_x64:
case TargetPlatform.android_x86:
if (androidSdk?.licensesAvailable == true && androidSdk.latestVersion == null) {
if (androidSdk?.licensesAvailable == true && androidSdk?.latestVersion == null) {
await checkGradleDependencies();
}
return applicationBinary == null
......
......@@ -5,6 +5,8 @@
import 'dart:async';
import '../android/android_builder.dart';
import '../android/android_sdk.dart';
import '../android/gradle_utils.dart';
import '../base/common.dart';
import '../base/os.dart';
import '../build_info.dart';
......@@ -85,6 +87,9 @@ class BuildAarCommand extends BuildSubCommand {
@override
Future<FlutterCommandResult> runCommand() async {
if (androidSdk == null) {
exitWithNoSdkMessage();
}
final Set<AndroidBuildInfo> androidBuildInfo = <AndroidBuildInfo>{};
final Iterable<AndroidArch> targetArchitectures =
......
......@@ -5,6 +5,8 @@
import 'dart:async';
import '../android/android_builder.dart';
import '../android/android_sdk.dart';
import '../android/gradle_utils.dart';
import '../base/terminal.dart';
import '../build_info.dart';
import '../cache.dart';
......@@ -77,6 +79,9 @@ class BuildApkCommand extends BuildSubCommand {
@override
Future<FlutterCommandResult> runCommand() async {
if (androidSdk == null) {
exitWithNoSdkMessage();
}
final BuildInfo buildInfo = getBuildInfo();
final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(
buildInfo,
......
......@@ -5,6 +5,8 @@
import 'dart:async';
import '../android/android_builder.dart';
import '../android/android_sdk.dart';
import '../android/gradle_utils.dart';
import '../build_info.dart';
import '../cache.dart';
import '../project.dart';
......@@ -69,6 +71,9 @@ class BuildAppBundleCommand extends BuildSubCommand {
@override
Future<FlutterCommandResult> runCommand() async {
if (androidSdk == null) {
exitWithNoSdkMessage();
}
final AndroidBuildInfo androidBuildInfo = AndroidBuildInfo(getBuildInfo(),
targetArchs: stringsArg('target-platform').map<AndroidArch>(getAndroidArchForName),
shrink: boolArg('shrink'),
......
......@@ -29,14 +29,15 @@ FlutterProjectFactory get projectFactory => context.get<FlutterProjectFactory>()
class FlutterProjectFactory {
FlutterProjectFactory();
final Map<String, FlutterProject> _projects =
@visibleForTesting
final Map<String, FlutterProject> projects =
<String, FlutterProject>{};
/// Returns a [FlutterProject] view of the given directory or a ToolExit error,
/// if `pubspec.yaml` or `example/pubspec.yaml` is invalid.
FlutterProject fromDirectory(Directory directory) {
assert(directory != null);
return _projects.putIfAbsent(directory.path, /* ifAbsent */ () {
return projects.putIfAbsent(directory.path, /* ifAbsent */ () {
final FlutterManifest manifest = FlutterProject._readManifest(
directory.childFile(bundle.defaultManifestPath).path,
);
......
......@@ -5,13 +5,12 @@
import 'dart:io' show Process, ProcessResult;
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build_aar.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
......@@ -90,18 +89,14 @@ void main() {
Directory tempDir;
AndroidSdk mockAndroidSdk;
Usage mockUsage;
FileSystem memoryFileSystem;
setUp(() {
mockUsage = MockUsage();
when(mockUsage.isFirstRun).thenReturn(true);
memoryFileSystem = MemoryFileSystem();
tempDir = memoryFileSystem.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
memoryFileSystem.currentDirectory = tempDir;
tempDir = fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
mockProcessManager = MockProcessManager();
when(mockProcessManager.run(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
......@@ -118,65 +113,49 @@ void main() {
when(mockAndroidSdk.directory).thenReturn('irrelevant');
});
tearDown(() {
tryToDelete(tempDir);
});
group('AndroidSdk', () {
testUsingContext('validateSdkWellFormed() not called, sdk reinitialized', () async {
final Directory gradleCacheDir = memoryFileSystem
.directory('/flutter_root/bin/cache/artifacts/gradle_wrapper')
..createSync(recursive: true);
gradleCacheDir.childFile(platform.isWindows ? 'gradlew.bat' : 'gradlew').createSync();
tempDir.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync('''name: test
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
plugin:
androidPackage: com.example.blah
pluginClass: BlahPlugin
''');
tempDir.childFile('.packages').createSync(recursive: true);
final Directory androidDir = tempDir.childDirectory('android');
androidDir
.childFile('build.gradle')
.createSync(recursive: true);
androidDir
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
androidDir
.childFile('gradle.properties')
.createSync(recursive: true);
androidDir
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.createSync(recursive: true);
tempDir
.childDirectory('build')
.childDirectory('outputs')
.childDirectory('repo')
.createSync(recursive: true);
tempDir
.childDirectory('lib')
.childFile('main.dart')
.createSync(recursive: true);
await runBuildAarCommand(tempDir.path);
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=module']);
await expectLater(
runBuildAarCommand(
projectPath,
arguments: <String>['--no-pub'],
),
throwsToolExit(),
);
verifyNever(mockAndroidSdk.validateSdkWellFormed());
verify(mockAndroidSdk.reinitialize()).called(1);
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws throwsToolExit if AndroidSdk is null', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=module']);
await expectLater(() async {
await runBuildAarCommand(
projectPath,
arguments: <String>['--no-pub'],
);
}, throwsToolExit(
message: '[!] No Android SDK found. Try setting the ANDROID_HOME environment variable',
));
},
overrides: <Type, Generator>{
AndroidSdk: () => null,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
FileSystem: () => memoryFileSystem,
});
});
});
......@@ -191,7 +170,6 @@ Future<BuildAarCommand> runBuildAarCommand(
await runner.run(<String>[
'aar',
'--no-pub',
'--flutter-root=/flutter_root',
...?arguments,
fs.path.join(target, 'lib', 'main.dart'),
]);
......
......@@ -5,7 +5,6 @@
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/base/context.dart';
......@@ -140,70 +139,15 @@ void main() {
});
group('AndroidSdk', () {
FileSystem memoryFileSystem;
setUp(() {
memoryFileSystem = MemoryFileSystem();
tempDir = memoryFileSystem.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
memoryFileSystem.currentDirectory = tempDir;
gradlew = memoryFileSystem.path.join(tempDir.path, 'flutter_project', 'android',
platform.isWindows ? 'gradlew.bat' : 'gradlew');
});
testUsingContext('validateSdkWellFormed() not called, sdk reinitialized', () async {
final Directory gradleCacheDir = memoryFileSystem
.directory('/flutter_root/bin/cache/artifacts/gradle_wrapper')
..createSync(recursive: true);
gradleCacheDir.childFile(platform.isWindows ? 'gradlew.bat' : 'gradlew').createSync();
tempDir.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync('''name: test
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
''');
tempDir.childFile('.packages').createSync(recursive: true);
final Directory androidDir = tempDir.childDirectory('android');
androidDir
.childFile('build.gradle')
.createSync(recursive: true);
androidDir
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
androidDir
.childFile('gradle.properties')
.createSync(recursive: true);
androidDir
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.createSync(recursive: true);
tempDir
.childDirectory('build')
.childDirectory('outputs')
.childDirectory('repo')
.createSync(recursive: true);
tempDir
.childDirectory('lib')
.childFile('main.dart')
.createSync(recursive: true);
when(mockProcessManager.run(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(0, 0, 'any', '')));
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
await expectLater(
runBuildApkCommand(tempDir.path, arguments: <String>['--no-pub', '--flutter-root=/flutter_root']),
runBuildApkCommand(
projectPath,
arguments: <String>['--no-pub'],
),
throwsToolExit(message: 'Gradle task assembleRelease failed with exit code 1'),
);
......@@ -212,7 +156,26 @@ flutter:
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FileSystem: () => memoryFileSystem,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws throwsToolExit if AndroidSdk is null', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
await expectLater(() async {
await runBuildApkCommand(
projectPath,
arguments: <String>['--no-pub'],
);
}, throwsToolExit(
message: '[!] No Android SDK found. Try setting the ANDROID_HOME environment variable',
));
},
overrides: <Type, Generator>{
AndroidSdk: () => null,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
});
});
......@@ -451,18 +414,6 @@ Future<BuildApkCommand> runBuildApkCommand(
return command;
}
class FakeFlutterProjectFactory extends FlutterProjectFactory {
FakeFlutterProjectFactory(this.directoryOverride) :
assert(directoryOverride != null);
final Directory directoryOverride;
@override
FlutterProject fromDirectory(Directory _) {
return super.fromDirectory(directoryOverride.childDirectory('flutter_project'));
}
}
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
......
......@@ -5,7 +5,6 @@
import 'dart:io';
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/base/context.dart';
......@@ -125,67 +124,15 @@ void main() {
});
group('AndroidSdk', () {
FileSystem memoryFileSystem;
setUp(() {
memoryFileSystem = MemoryFileSystem();
tempDir = memoryFileSystem.systemTempDirectory.createTempSync('flutter_tools_packages_test.');
memoryFileSystem.currentDirectory = tempDir;
gradlew = memoryFileSystem.path.join(tempDir.path, 'flutter_project', 'android',
platform.isWindows ? 'gradlew.bat' : 'gradlew');
});
testUsingContext('validateSdkWellFormed() not called, sdk reinitialized', () async {
final Directory gradleCacheDir = memoryFileSystem
.directory('/flutter_root/bin/cache/artifacts/gradle_wrapper')
..createSync(recursive: true);
gradleCacheDir.childFile(platform.isWindows ? 'gradlew.bat' : 'gradlew').createSync();
tempDir.childFile('pubspec.yaml')
..createSync(recursive: true)
..writeAsStringSync('''name: test
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
''');
tempDir.childFile('.packages').createSync(recursive: true);
final Directory androidDir = tempDir.childDirectory('android');
androidDir.childFile('build.gradle').createSync(recursive: true);
androidDir
.childDirectory('app')
.childFile('build.gradle')
..createSync(recursive: true)
..writeAsStringSync('apply from: irrelevant/flutter.gradle');
androidDir
.childFile('gradle.properties')
.createSync(recursive: true);
androidDir
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.createSync(recursive: true);
tempDir.childDirectory('build')
.childDirectory('outputs')
.childDirectory('repo')
.createSync(recursive: true);
tempDir.childDirectory('lib')
.childFile('main.dart')
.createSync(recursive: true);
when(mockProcessManager.run(any,
workingDirectory: anyNamed('workingDirectory'),
environment: anyNamed('environment')))
.thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(0, 0, 'any', '')));
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
await expectLater(
runBuildAppBundleCommand(tempDir.path, arguments: <String>['--no-pub', '--flutter-root=/flutter_root']),
runBuildAppBundleCommand(
projectPath,
arguments: <String>['--no-pub'],
),
throwsToolExit(message: 'Gradle task bundleRelease failed with exit code 1'),
);
......@@ -194,8 +141,27 @@ flutter:
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
});
testUsingContext('throws throwsToolExit if AndroidSdk is null', () async {
final String projectPath = await createProject(tempDir,
arguments: <String>['--no-pub', '--template=app']);
await expectLater(() async {
await runBuildAppBundleCommand(
projectPath,
arguments: <String>['--no-pub'],
);
}, throwsToolExit(
message: '[!] No Android SDK found. Try setting the ANDROID_HOME environment variable',
));
},
overrides: <Type, Generator>{
AndroidSdk: () => null,
FlutterProjectFactory: () => FakeFlutterProjectFactory(tempDir),
ProcessManager: () => mockProcessManager,
FileSystem: () => memoryFileSystem,
});
});
......@@ -437,18 +403,6 @@ Future<BuildAppBundleCommand> runBuildAppBundleCommand(
return command;
}
class FakeFlutterProjectFactory extends FlutterProjectFactory {
FakeFlutterProjectFactory(this._directoryOverride) :
assert(_directoryOverride != null);
final Directory _directoryOverride;
@override
FlutterProject fromDirectory(Directory _) {
return super.fromDirectory(_directoryOverride.childDirectory('flutter_project'));
}
}
class MockAndroidSdk extends Mock implements AndroidSdk {}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
......
......@@ -5,6 +5,7 @@
import 'package:meta/meta.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/project.dart';
......@@ -33,3 +34,18 @@ class FakeAndroidBuilder implements AndroidBuilder {
@required String target,
}) async {}
}
/// Creates a [FlutterProject] in a directory named [flutter_project]
/// within [directoryOverride].
class FakeFlutterProjectFactory extends FlutterProjectFactory {
FakeFlutterProjectFactory(this.directoryOverride) :
assert(directoryOverride != null);
final Directory directoryOverride;
@override
FlutterProject fromDirectory(Directory _) {
projects.clear();
return super.fromDirectory(directoryOverride.childDirectory('flutter_project'));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment