Unverified Commit 175b3724 authored by Emmanuel Garcia's avatar Emmanuel Garcia Committed by GitHub

Refactor gradle.dart (#43479)

parent 0028887a
......@@ -6,19 +6,23 @@ import 'dart:async';
import 'package:meta/meta.dart';
import '../base/common.dart';
import '../android/gradle_errors.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../build_info.dart';
import '../project.dart';
import 'android_sdk.dart';
import 'gradle.dart';
/// The builder in the current context.
AndroidBuilder get androidBuilder => context.get<AndroidBuilder>() ?? _AndroidBuilderImpl();
AndroidBuilder get androidBuilder {
return context.get<AndroidBuilder>() ?? const _AndroidBuilderImpl();
}
/// Provides the methods to build Android artifacts.
// TODO(egarciad): https://github.com/flutter/flutter/issues/43863
abstract class AndroidBuilder {
const AndroidBuilder();
/// Builds an AAR artifact.
Future<void> buildAar({
@required FlutterProject project,
......@@ -44,7 +48,7 @@ abstract class AndroidBuilder {
/// Default implementation of [AarBuilder].
class _AndroidBuilderImpl extends AndroidBuilder {
_AndroidBuilderImpl();
const _AndroidBuilderImpl();
/// Builds the AAR and POM files for the current Flutter module or plugin.
@override
......@@ -54,27 +58,18 @@ class _AndroidBuilderImpl extends AndroidBuilder {
@required String target,
@required String outputDir,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
'The build process for Android has changed, and the current project configuration '
'is no longer valid. Please consult\n\n'
' https://github.com/flutter/flutter/wiki/Upgrading-Flutter-projects-to-build-with-gradle\n\n'
'for details on how to upgrade the project.'
);
}
if (!project.manifest.isModule && !project.manifest.isPlugin) {
throwToolExit('AARs can only be built for plugin or module projects.');
}
// Validate that we can find an Android SDK.
if (androidSdk == null) {
throwToolExit('No Android SDK found. Try setting the `ANDROID_SDK_ROOT` environment variable.');
}
try {
Directory outputDirectory =
fs.directory(outputDir ?? project.android.buildDirectory);
if (project.isModule) {
// Module projects artifacts are located in `build/host`.
outputDirectory = outputDirectory.childDirectory('host');
}
await buildGradleAar(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
outputDir: outputDir,
outputDir: outputDirectory,
);
} finally {
androidSdk.reinitialize();
......@@ -88,24 +83,13 @@ class _AndroidBuilderImpl extends AndroidBuilder {
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
'The build process for Android has changed, and the current project configuration '
'is no longer valid. Please consult\n\n'
' https://github.com/flutter/flutter/wiki/Upgrading-Flutter-projects-to-build-with-gradle\n\n'
'for details on how to upgrade the project.'
);
}
// Validate that we can find an android sdk.
if (androidSdk == null) {
throwToolExit('No Android SDK found. Try setting the ANDROID_SDK_ROOT environment variable.');
}
try {
await buildGradleProject(
await buildGradleApp(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: false,
localGradleErrors: gradleErrors,
);
} finally {
androidSdk.reinitialize();
......@@ -119,54 +103,16 @@ class _AndroidBuilderImpl extends AndroidBuilder {
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {
if (!project.android.isUsingGradle) {
throwToolExit(
'The build process for Android has changed, and the current project configuration '
'is no longer valid. Please consult\n\n'
'https://github.com/flutter/flutter/wiki/Upgrading-Flutter-projects-to-build-with-gradle\n\n'
'for details on how to upgrade the project.'
);
}
// Validate that we can find an android sdk.
if (androidSdk == null) {
throwToolExit('No Android SDK found. Try setting the ANDROID_HOME environment variable.');
}
try {
await buildGradleProject(
await buildGradleApp(
project: project,
androidBuildInfo: androidBuildInfo,
target: target,
isBuildingBundle: true,
localGradleErrors: gradleErrors,
);
} finally {
androidSdk.reinitialize();
}
}
}
/// A fake implementation of [AndroidBuilder].
@visibleForTesting
class FakeAndroidBuilder implements AndroidBuilder {
@override
Future<void> buildAar({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
@required String outputDir,
}) async {}
@override
Future<void> buildApk({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {}
@override
Future<void> buildAab({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {}
}
......@@ -236,7 +236,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
// Read all $HOME/.AndroidStudio*/system/.home files. There may be several
// pointing to the same installation, so we grab only the latest one.
if (fs.directory(homeDirPath).existsSync()) {
if (homeDirPath != null && fs.directory(homeDirPath).existsSync()) {
for (FileSystemEntity entity in fs.directory(homeDirPath).listSync(followLinks: false)) {
if (entity is Directory && entity.basename.startsWith('.AndroidStudio')) {
final AndroidStudio studio = AndroidStudio.fromHomeDot(entity);
......
This diff is collapsed.
This diff is collapsed.
......@@ -23,6 +23,17 @@ enum TerminalColor {
AnsiTerminal get terminal {
return context?.get<AnsiTerminal>() ?? _defaultAnsiTerminal;
}
/// Warning mark to use in stdout or stderr.
String get warningMark {
return terminal.bolden(terminal.color('[!]', TerminalColor.red));
}
/// Success mark to use in stdout.
String get successMark {
return terminal.bolden(terminal.color('✓', TerminalColor.green));
}
final AnsiTerminal _defaultAnsiTerminal = AnsiTerminal();
OutputPreferences get outputPreferences {
......
......@@ -6,7 +6,7 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'android/gradle.dart';
import 'android/gradle_utils.dart';
import 'base/common.dart';
import 'base/context.dart';
import 'base/file_system.dart';
......@@ -914,7 +914,7 @@ class AndroidMavenArtifacts extends ArtifactSet {
'--project-cache-dir', tempDir.path,
'resolveDependencies',
],
environment: gradleEnv);
environment: gradleEnvironment);
if (processResult.exitCode != 0) {
printError('Failed to download the Android dependencies');
}
......
......@@ -10,7 +10,7 @@ import 'package:yaml/yaml.dart' as yaml;
import '../android/android.dart' as android;
import '../android/android_sdk.dart' as android_sdk;
import '../android/gradle.dart' as gradle;
import '../android/gradle_utils.dart' as gradle;
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/net.dart';
......
......@@ -7,7 +7,7 @@ import 'dart:async';
import 'android/android_sdk.dart';
import 'android/android_studio.dart';
import 'android/android_workflow.dart';
import 'android/gradle.dart';
import 'android/gradle_utils.dart';
import 'application_package.dart';
import 'artifacts.dart';
import 'asset.dart';
......
......@@ -7,7 +7,7 @@ import 'dart:async';
import 'package:meta/meta.dart';
import 'package:yaml/yaml.dart';
import 'android/gradle.dart' as gradle;
import 'android/gradle_utils.dart' as gradle;
import 'base/common.dart';
import 'base/context.dart';
import 'base/file_system.dart';
......@@ -574,6 +574,11 @@ class AndroidProject {
return _firstMatchInFile(gradleFile, _groupPattern)?.group(1);
}
/// The build directory where the Android artifacts are placed.
Directory get buildDirectory {
return parent.directory.childDirectory('build');
}
Future<void> ensureReadyForPlatformSpecificTooling() async {
if (isModule && _shouldRegenerateFromTemplate()) {
_regenerateLibrary();
......
// Copyright 2019 The Chromium 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/memory.dart';
import 'package:flutter_tools/src/android/gradle_utils.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:process/process.dart';
import '../../src/common.dart';
import '../../src/context.dart';
void main() {
group('injectGradleWrapperIfNeeded', () {
MemoryFileSystem memoryFileSystem;
Directory tempDir;
Directory gradleWrapperDirectory;
setUp(() {
memoryFileSystem = MemoryFileSystem();
tempDir = memoryFileSystem.systemTempDirectory.createTempSync('flutter_artifacts_test.');
gradleWrapperDirectory = memoryFileSystem.directory(
memoryFileSystem.path.join(tempDir.path, 'bin', 'cache', 'artifacts', 'gradle_wrapper'));
gradleWrapperDirectory.createSync(recursive: true);
gradleWrapperDirectory
.childFile('gradlew')
.writeAsStringSync('irrelevant');
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
.createSync(recursive: true);
gradleWrapperDirectory
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.jar')
.writeAsStringSync('irrelevant');
});
testUsingContext('Inject the wrapper when all files are missing', () {
final Directory sampleAppAndroid = fs.directory('/sample-app/android');
sampleAppAndroid.createSync(recursive: true);
injectGradleWrapperIfNeeded(sampleAppAndroid);
expect(sampleAppAndroid.childFile('gradlew').existsSync(), isTrue);
expect(sampleAppAndroid
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.jar')
.existsSync(), isTrue);
expect(sampleAppAndroid
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.existsSync(), isTrue);
expect(sampleAppAndroid
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.readAsStringSync(),
'distributionBase=GRADLE_USER_HOME\n'
'distributionPath=wrapper/dists\n'
'zipStoreBase=GRADLE_USER_HOME\n'
'zipStorePath=wrapper/dists\n'
'distributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip\n');
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Inject the wrapper when some files are missing', () {
final Directory sampleAppAndroid = fs.directory('/sample-app/android');
sampleAppAndroid.createSync(recursive: true);
// There's an existing gradlew
sampleAppAndroid.childFile('gradlew').writeAsStringSync('existing gradlew');
injectGradleWrapperIfNeeded(sampleAppAndroid);
expect(sampleAppAndroid.childFile('gradlew').existsSync(), isTrue);
expect(sampleAppAndroid.childFile('gradlew').readAsStringSync(),
equals('existing gradlew'));
expect(sampleAppAndroid
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.jar')
.existsSync(), isTrue);
expect(sampleAppAndroid
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.existsSync(), isTrue);
expect(sampleAppAndroid
.childDirectory('gradle')
.childDirectory('wrapper')
.childFile('gradle-wrapper.properties')
.readAsStringSync(),
'distributionBase=GRADLE_USER_HOME\n'
'distributionPath=wrapper/dists\n'
'zipStoreBase=GRADLE_USER_HOME\n'
'zipStorePath=wrapper/dists\n'
'distributionUrl=https\\://services.gradle.org/distributions/gradle-5.6.2-all.zip\n');
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('Gives executable permission to gradle', () {
final Directory sampleAppAndroid = fs.directory('/sample-app/android');
sampleAppAndroid.createSync(recursive: true);
// Make gradlew in the wrapper executable.
os.makeExecutable(gradleWrapperDirectory.childFile('gradlew'));
injectGradleWrapperIfNeeded(sampleAppAndroid);
final File gradlew = sampleAppAndroid.childFile('gradlew');
expect(gradlew.existsSync(), isTrue);
expect(gradlew.statSync().modeString().contains('x'), isTrue);
}, overrides: <Type, Generator>{
Cache: () => Cache(rootOverride: tempDir),
FileSystem: () => memoryFileSystem,
ProcessManager: () => FakeProcessManager.any(),
OperatingSystemUtils: () => OperatingSystemUtils(),
});
});
}
\ No newline at end of file
......@@ -11,7 +11,7 @@ import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/android/gradle.dart';
import 'package:flutter_tools/src/android/gradle_utils.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/cache.dart';
......@@ -316,7 +316,7 @@ void main() {
expect(args[1], '-b');
expect(args[2].endsWith('resolve_dependencies.gradle'), isTrue);
expect(args[5], 'resolveDependencies');
expect(invocation.namedArguments[#environment], gradleEnv);
expect(invocation.namedArguments[#environment], gradleEnvironment);
return Future<ProcessResult>.value(ProcessResult(0, 0, '', ''));
});
......
......@@ -8,7 +8,6 @@ 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/android/gradle.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';
......@@ -17,6 +16,7 @@ import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import '../../src/android_common.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
......@@ -120,7 +120,9 @@ void main() {
group('AndroidSdk', () {
testUsingContext('validateSdkWellFormed() not called, sdk reinitialized', () async {
final Directory gradleCacheDir = memoryFileSystem.directory('/flutter_root/bin/cache/artifacts/gradle_wrapper')..createSync(recursive: true);
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')
......@@ -141,11 +143,31 @@ flutter:
''');
tempDir.childFile('.packages').createSync(recursive: true);
final Directory androidDir = tempDir.childDirectory('android');
androidDir.childFile('build.gradle').createSync(recursive: true);
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);
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);
verifyNever(mockAndroidSdk.validateSdkWellFormed());
......@@ -153,7 +175,6 @@ flutter:
},
overrides: <Type, Generator>{
AndroidSdk: () => mockAndroidSdk,
GradleUtils: () => GradleUtils(),
ProcessManager: () => mockProcessManager,
FileSystem: () => memoryFileSystem,
});
......
// Copyright 2019 The Chromium 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:meta/meta.dart';
import 'package:flutter_tools/src/android/android_builder.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/project.dart';
/// A fake implementation of [AndroidBuilder].
class FakeAndroidBuilder implements AndroidBuilder {
@override
Future<void> buildAar({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
@required String outputDir,
}) async {}
@override
Future<void> buildApk({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {}
@override
Future<void> buildAab({
@required FlutterProject project,
@required AndroidBuildInfo androidBuildInfo,
@required String target,
}) async {}
}
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