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

Use new Maven artifacts from Gradle (#39157)

parent d30e4228
...@@ -52,7 +52,6 @@ Future<void> main() async { ...@@ -52,7 +52,6 @@ Future<void> main() async {
'assets/flutter_assets/isolate_snapshot_data', 'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin', 'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data', 'assets/flutter_assets/vm_snapshot_data',
'lib/armeabi-v7a/libflutter.so',
// Debug mode intentionally includes `x86` and `x86_64`. // Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so', 'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so', 'lib/x86_64/libflutter.so',
...@@ -79,7 +78,6 @@ Future<void> main() async { ...@@ -79,7 +78,6 @@ Future<void> main() async {
'assets/flutter_assets/isolate_snapshot_data', 'assets/flutter_assets/isolate_snapshot_data',
'assets/flutter_assets/kernel_blob.bin', 'assets/flutter_assets/kernel_blob.bin',
'assets/flutter_assets/vm_snapshot_data', 'assets/flutter_assets/vm_snapshot_data',
'lib/armeabi-v7a/libflutter.so',
// Debug mode intentionally includes `x86` and `x86_64`. // Debug mode intentionally includes `x86` and `x86_64`.
'lib/x86/libflutter.so', 'lib/x86/libflutter.so',
'lib/x86_64/libflutter.so', 'lib/x86_64/libflutter.so',
......
...@@ -57,6 +57,6 @@ dependencies { ...@@ -57,6 +57,6 @@ dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:appcompat-v7:26.1.0' implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:26.1.0' implementation 'com.android.support:design:28.0.0'
} }
...@@ -28,7 +28,7 @@ buildscript { ...@@ -28,7 +28,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.1' classpath "com.android.tools.build:gradle:3.2.1"
} }
} }
...@@ -42,6 +42,8 @@ android { ...@@ -42,6 +42,8 @@ android {
apply plugin: FlutterPlugin apply plugin: FlutterPlugin
class FlutterPlugin implements Plugin<Project> { class FlutterPlugin implements Plugin<Project> {
private static final String MAVEN_REPO = "http://download.flutter.io";
// The platforms that can be passed to the `--Ptarget-platform` flag. // The platforms that can be passed to the `--Ptarget-platform` flag.
private static final String PLATFORM_ARM32 = "android-arm"; private static final String PLATFORM_ARM32 = "android-arm";
private static final String PLATFORM_ARM64 = "android-arm64"; private static final String PLATFORM_ARM64 = "android-arm64";
...@@ -85,6 +87,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -85,6 +87,7 @@ class FlutterPlugin implements Plugin<Project> {
// to match. // to match.
static final String FLUTTER_BUILD_PREFIX = "flutterBuild" static final String FLUTTER_BUILD_PREFIX = "flutterBuild"
private Project project
private Map baseJar = [:] private Map baseJar = [:]
private File flutterRoot private File flutterRoot
private File flutterExecutable private File flutterExecutable
...@@ -92,16 +95,18 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -92,16 +95,18 @@ class FlutterPlugin implements Plugin<Project> {
private String localEngineSrcPath private String localEngineSrcPath
private Properties localProperties private Properties localProperties
private File flutterJar private File flutterJar
private String engineVersion
@Override @Override
void apply(Project project) { void apply(Project project) {
this.project = project
project.extensions.create("flutter", FlutterExtension) project.extensions.create("flutter", FlutterExtension)
project.afterEvaluate this.&addFlutterTasks project.afterEvaluate this.&addFlutterTasks
// By default, assembling APKs generates fat APKs if multiple platforms are passed. // By default, assembling APKs generates fat APKs if multiple platforms are passed.
// Configuring split per ABI allows to generate separate APKs for each abi. // Configuring split per ABI allows to generate separate APKs for each abi.
// This is a noop when building a bundle. // This is a noop when building a bundle.
if (splitPerAbi(project)) { if (shouldSplitPerAbi()) {
project.android { project.android {
splits { splits {
abi { abi {
...@@ -115,14 +120,10 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -115,14 +120,10 @@ class FlutterPlugin implements Plugin<Project> {
} }
} }
} }
getTargetPlatforms(project).each { targetArch -> getTargetPlatforms().each { targetArch ->
String abiValue = PLATFORM_ARCH_MAP[targetArch] String abiValue = PLATFORM_ARCH_MAP[targetArch]
project.android { project.android {
packagingOptions { if (shouldSplitPerAbi()) {
// Prevent the ELF library from getting corrupted.
doNotStrip "*/${abiValue}/libapp.so"
}
if (splitPerAbi(project)) {
splits { splits {
abi { abi {
include abiValue include abiValue
...@@ -131,7 +132,6 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -131,7 +132,6 @@ class FlutterPlugin implements Plugin<Project> {
} }
} }
} }
// Add custom build types // Add custom build types
project.android.buildTypes { project.android.buildTypes {
profile { profile {
...@@ -141,8 +141,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -141,8 +141,7 @@ class FlutterPlugin implements Plugin<Project> {
} }
} }
} }
String flutterRootPath = resolveProperty("flutter.sdk", System.env.FLUTTER_ROOT)
String flutterRootPath = resolveProperty(project, "flutter.sdk", System.env.FLUTTER_ROOT)
if (flutterRootPath == null) { if (flutterRootPath == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable.") throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file or with a FLUTTER_ROOT environment variable.")
} }
...@@ -151,12 +150,14 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -151,12 +150,14 @@ class FlutterPlugin implements Plugin<Project> {
throw new GradleException("flutter.sdk must point to the Flutter SDK directory") throw new GradleException("flutter.sdk must point to the Flutter SDK directory")
} }
engineVersion = Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.version")
.toFile().text.trim()
String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter" String flutterExecutableName = Os.isFamily(Os.FAMILY_WINDOWS) ? "flutter.bat" : "flutter"
flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile(); flutterExecutable = Paths.get(flutterRoot.absolutePath, "bin", flutterExecutableName).toFile();
if (useLocalEngine(project)) { if (useLocalEngine()) {
String engineOutPath = project.property('localEngineOut') File engineOut = project.file(project.property('localEngineOut'))
File engineOut = project.file(engineOutPath)
if (!engineOut.isDirectory()) { if (!engineOut.isDirectory()) {
throw new GradleException('localEngineOut must point to a local engine build') throw new GradleException('localEngineOut must point to a local engine build')
} }
...@@ -175,45 +176,48 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -175,45 +176,48 @@ class FlutterPlugin implements Plugin<Project> {
}) })
} }
} else { } else {
String basePlatformArch = getBasePlatform(project) project.android.buildTypes.each this.&addFlutterDependencies
// This is meant to include the compiled classes only, however it will include `libflutter.so` as well. project.android.buildTypes.whenObjectAdded this.&addFlutterDependencies
Path baseEnginePath = Paths.get(flutterRoot.absolutePath, "bin", "cache", "artifacts", "engine") }
File debugJar = baseEnginePath.resolve("${basePlatformArch}").resolve("flutter.jar").toFile() }
baseJar["debug"] = debugJar
if (!debugJar.isFile()) { /**
project.exec { * Adds the dependencies required by the Flutter project.
executable flutterExecutable.absolutePath * This includes:
args "--suppress-analytics" * 1. The embedding
args "precache" * 2. libflutter.so
} */
if (!debugJar.isFile()) { void addFlutterDependencies(buildType) {
throw new GradleException("Unable to find flutter.jar in SDK: ${debugJar}") project.rootProject.allprojects {
repositories {
maven {
url MAVEN_REPO
} }
} }
baseJar["profile"] = baseEnginePath.resolve("${basePlatformArch}-profile").resolve("flutter.jar").toFile() }
baseJar["release"] = baseEnginePath.resolve("${basePlatformArch}-release").resolve("flutter.jar").toFile() String flutterBuildMode = buildModeFor(buildType)
// Add the embedding dependency.
addApiDependencies(project, buildType.name,
"io.flutter:flutter_embedding_$flutterBuildMode:1.0.0-$engineVersion")
// Add flutter.jar dependencies to all <buildType>Api configurations, including custom ones List<String> platforms = getTargetPlatforms().collect()
// added after applying the Flutter plugin. // Debug mode includes x86 and x64, which are commonly used in emulators.
project.android.buildTypes.each { if (flutterBuildMode == "debug") {
def buildMode = buildModeFor(it) platforms.add("android-x86")
addApiDependencies(project, it.name, project.files { platforms.add("android-x64")
baseJar[buildMode] }
}) platforms.each { platform ->
} String arch = PLATFORM_ARCH_MAP[platform].replace("-", "_")
project.android.buildTypes.whenObjectAdded { // Add the `libflutter.so` dependency.
def buildMode = buildModeFor(it) addApiDependencies(project, buildType.name,
addApiDependencies(project, it.name, project.files { "io.flutter:${arch}_$flutterBuildMode:1.0.0-$engineVersion")
baseJar[buildMode]
})
}
} }
} }
/** /**
* Returns the directory where the plugins are built. * Returns the directory where the plugins are built.
*/ */
private File getPluginBuildDir(Project project) { private File getPluginBuildDir() {
// Module projects specify this flag to include plugins in the same repo as the module project. // Module projects specify this flag to include plugins in the same repo as the module project.
if (project.ext.has("pluginBuildDir")) { if (project.ext.has("pluginBuildDir")) {
return project.ext.get("pluginBuildDir") return project.ext.get("pluginBuildDir")
...@@ -221,13 +225,75 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -221,13 +225,75 @@ class FlutterPlugin implements Plugin<Project> {
return project.buildDir return project.buildDir
} }
private Properties getPluginList(Project project) { /**
* Configures the Flutter plugin dependencies.
*
* The plugins are added to pubspec.yaml. Then, upon running `flutter pub get`,
* the tool generates a `.flutter-plugins` file, which contains a 1:1 map to each plugin location.
* Finally, the project's `settings.gradle` loads each plugin's android directory as a subproject.
*/
private void configurePlugins() {
if (!buildPluginAsAar()) {
getPluginList().each this.&configurePlugin
return
}
addPluginTasks()
List<String> tasksToExecute = project.gradle.startParameter.taskNames
Set buildTypes = getBuildTypesForTasks(tasksToExecute)
if (tasksToExecute.contains("clean")) {
// Because the plugins are built during configuration, the task "clean"
// cannot run in conjunction with an assembly task.
if (!buildTypes.empty) {
throw new GradleException("Can't run the clean task along with other assemble tasks")
}
}
// Build plugins when a task "assembly*" will be called later.
if (!buildTypes.empty) {
// Build the plugin during configuration.
// This is required when Jetifier is enabled, otherwise the implementation dependency
// cannot be added.
buildAarPlugins(buildTypes)
}
}
private void configurePlugin(String name, String _) {
Project pluginProject = project.rootProject.findProject(":$name")
if (pluginProject == null) {
project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
return
}
// Add plugin dependency to the app project.
project.dependencies {
if (project.getConfigurations().findByName("implementation")) {
implementation pluginProject
} else {
compile pluginProject
}
}
Closure addEmbeddingCompileOnlyDependency = { buildType ->
String flutterBuildMode = buildModeFor(buildType)
// Add the embedding as a compile only dependency to the plugin.
addFlutterJarCompileOnlyDependency(pluginProject, buildType.name,
flutterJar ?: "io.flutter:flutter_embedding_$flutterBuildMode:1.0.0-$engineVersion")
}
pluginProject.afterEvaluate {
pluginProject.android.buildTypes {
profile {
initWith debug
}
}
pluginProject.android.buildTypes.each addEmbeddingCompileOnlyDependency
pluginProject.android.buildTypes.whenObjectAdded addEmbeddingCompileOnlyDependency
}
}
private Properties getPluginList() {
File pluginsFile = new File(project.projectDir.parentFile.parentFile, '.flutter-plugins') File pluginsFile = new File(project.projectDir.parentFile.parentFile, '.flutter-plugins')
return readPropertiesIfExist(pluginsFile) return readPropertiesIfExist(pluginsFile)
} }
private void addPluginTasks(Project project) { private void addPluginTasks() {
Properties plugins = getPluginList(project) Properties plugins = getPluginList()
project.android.buildTypes.each { buildType -> project.android.buildTypes.each { buildType ->
plugins.each { name, path -> plugins.each { name, path ->
String buildModeValue = buildType.debuggable ? "debug" : "release" String buildModeValue = buildType.debuggable ? "debug" : "release"
...@@ -240,17 +306,17 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -240,17 +306,17 @@ class FlutterPlugin implements Plugin<Project> {
project.tasks.create(name: taskName, type: FlutterPluginTask) { project.tasks.create(name: taskName, type: FlutterPluginTask) {
flutterExecutable this.flutterExecutable flutterExecutable this.flutterExecutable
buildMode buildModeValue buildMode buildModeValue
verbose isVerbose(project) verbose isVerbose()
pluginDir project.file(path) pluginDir project.file(path)
sourceDir project.file(project.flutter.source) sourceDir project.file(project.flutter.source)
intermediateDir getPluginBuildDir(project) intermediateDir getPluginBuildDir()
} }
} }
} }
} }
} }
private void buildPlugins(Project project, Set buildTypes) { private void buildAarPlugins(Set buildTypes) {
List<Project> projects = [project] List<Project> projects = [project]
// Module projects set the `hostProjects` extra property in `include_flutter.groovy`. // Module projects set the `hostProjects` extra property in `include_flutter.groovy`.
// This is required to set the local repository in each host app project. // This is required to set the local repository in each host app project.
...@@ -260,7 +326,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -260,7 +326,7 @@ class FlutterPlugin implements Plugin<Project> {
projects.each { hostProject -> projects.each { hostProject ->
hostProject.repositories { hostProject.repositories {
maven { maven {
url "${getPluginBuildDir(project)}/outputs/repo" url "${getPluginBuildDir()}/outputs/repo"
} }
} }
} }
...@@ -295,7 +361,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -295,7 +361,7 @@ class FlutterPlugin implements Plugin<Project> {
* Returns a set with the build type names that apply to the given list of tasks * Returns a set with the build type names that apply to the given list of tasks
* required to configure the plugin dependencies. * required to configure the plugin dependencies.
*/ */
private Set getBuildTypesForTasks(Project project, List<String> tasksToExecute) { private Set getBuildTypesForTasks(List<String> tasksToExecute) {
Set buildTypes = [] Set buildTypes = []
tasksToExecute.each { task -> tasksToExecute.each { task ->
project.android.buildTypes.each { buildType -> project.android.buildTypes.each { buildType ->
...@@ -320,7 +386,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -320,7 +386,7 @@ class FlutterPlugin implements Plugin<Project> {
return "${parts[0]}${parts[1..-1].collect { it.capitalize() }.join('')}" return "${parts[0]}${parts[1..-1].collect { it.capitalize() }.join('')}"
} }
private String resolveProperty(Project project, String name, String defaultValue) { private String resolveProperty(String name, String defaultValue) {
if (localProperties == null) { if (localProperties == null) {
localProperties = readPropertiesIfExist(new File(project.projectDir.parentFile, "local.properties")) localProperties = readPropertiesIfExist(new File(project.projectDir.parentFile, "local.properties"))
} }
...@@ -345,7 +411,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -345,7 +411,7 @@ class FlutterPlugin implements Plugin<Project> {
return result return result
} }
private static List<String> getTargetPlatforms(Project project) { private List<String> getTargetPlatforms() {
if (!project.hasProperty('target-platform')) { if (!project.hasProperty('target-platform')) {
return DEFAULT_PLATFORMS return DEFAULT_PLATFORMS
} }
...@@ -357,18 +423,18 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -357,18 +423,18 @@ class FlutterPlugin implements Plugin<Project> {
} }
} }
private static Boolean splitPerAbi(Project project) { private Boolean shouldSplitPerAbi() {
if (project.hasProperty('split-per-abi')) { if (project.hasProperty('split-per-abi')) {
return project.property('split-per-abi').toBoolean() return project.property('split-per-abi').toBoolean()
} }
return false; return false;
} }
private static Boolean useLocalEngine(Project project) { private Boolean useLocalEngine() {
return project.hasProperty('localEngineOut') return project.hasProperty('localEngineOut')
} }
private static Boolean isVerbose(Project project) { private Boolean isVerbose() {
if (project.hasProperty('verbose')) { if (project.hasProperty('verbose')) {
return project.property('verbose').toBoolean() return project.property('verbose').toBoolean()
} }
...@@ -379,20 +445,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -379,20 +445,7 @@ class FlutterPlugin implements Plugin<Project> {
return System.getProperty('build-plugins-as-aars') == 'true' return System.getProperty('build-plugins-as-aars') == 'true'
} }
/** private void addFlutterJarCompileOnlyDependency(Project project, String variantName, Object dependency) {
* Returns the platform that is used to extract the `libflutter.so` and the .class files.
*
* Note: This is only needed to add the .class files.
* Unfortunately, the engine artifacts include the .class and libflutter.so files.
*/
private static String getBasePlatform(Project project) {
if (PLATFORM_ARM64 in getTargetPlatforms(project)) {
return PLATFORM_ARM64;
}
return PLATFORM_ARM32;
}
private void addFlutterJarCompileOnlyDependency(Project project, String variantName, FileCollection files) {
if (project.state.failure) { if (project.state.failure) {
return return
} }
...@@ -402,7 +455,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -402,7 +455,7 @@ class FlutterPlugin implements Plugin<Project> {
} else { } else {
configuration = "${variantName}Provided"; configuration = "${variantName}Provided";
} }
project.dependencies.add(configuration, files) project.dependencies.add(configuration, dependency)
} }
private static void addApiDependencies(Project project, String variantName, Object dependency, Closure config = null) { private static void addApiDependencies(Project project, String variantName, Object dependency, Closure config = null) {
...@@ -455,7 +508,6 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -455,7 +508,6 @@ class FlutterPlugin implements Plugin<Project> {
if (project.hasProperty('target')) { if (project.hasProperty('target')) {
target = project.property('target') target = project.property('target')
} }
String[] fileSystemRootsValue = null String[] fileSystemRootsValue = null
if (project.hasProperty('filesystem-roots')) { if (project.hasProperty('filesystem-roots')) {
fileSystemRootsValue = project.property('filesystem-roots').split('\\|') fileSystemRootsValue = project.property('filesystem-roots').split('\\|')
...@@ -492,10 +544,9 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -492,10 +544,9 @@ class FlutterPlugin implements Plugin<Project> {
if (project.hasProperty('extra-gen-snapshot-options')) { if (project.hasProperty('extra-gen-snapshot-options')) {
extraGenSnapshotOptionsValue = project.property('extra-gen-snapshot-options') extraGenSnapshotOptionsValue = project.property('extra-gen-snapshot-options')
} }
def targetPlatforms = getTargetPlatforms()
def targetPlatforms = getTargetPlatforms(project)
def addFlutterDeps = { variant -> def addFlutterDeps = { variant ->
if (splitPerAbi(project)) { if (shouldSplitPerAbi()) {
variant.outputs.each { output -> variant.outputs.each { output ->
// Assigns the new version code to versionCodeOverride, which changes the version code // Assigns the new version code to versionCodeOverride, which changes the version code
// for only the output APK, not for the variant itself. Skipping this step simply // for only the output APK, not for the variant itself. Skipping this step simply
...@@ -508,31 +559,17 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -508,31 +559,17 @@ class FlutterPlugin implements Plugin<Project> {
} }
} }
} }
String flutterBuildMode = buildModeFor(variant.buildType)
if (flutterBuildMode == 'debug' && project.tasks.findByName("${FLUTTER_BUILD_PREFIX}X86Jar")) {
Task task = project.tasks.findByName("compile${variant.name.capitalize()}JavaWithJavac")
if (task) {
task.dependsOn project.flutterBuildX86Jar
}
task = project.tasks.findByName("compile${variant.name.capitalize()}Kotlin")
if (task) {
task.dependsOn project.flutterBuildX86Jar
}
}
def compileTasks = targetPlatforms.collect { targetArch -> def compileTasks = targetPlatforms.collect { targetArch ->
String abiValue = PLATFORM_ARCH_MAP[targetArch]
String taskName = toCammelCase(["compile", FLUTTER_BUILD_PREFIX, variant.name, targetArch.replace('android-', '')]) String taskName = toCammelCase(["compile", FLUTTER_BUILD_PREFIX, variant.name, targetArch.replace('android-', '')])
FlutterTask compileTask = project.tasks.create(name: taskName, type: FlutterTask) { project.tasks.create(name: taskName, type: FlutterTask) {
flutterRoot this.flutterRoot flutterRoot this.flutterRoot
flutterExecutable this.flutterExecutable flutterExecutable this.flutterExecutable
buildMode flutterBuildMode buildMode buildModeFor(variant.buildType)
localEngine this.localEngine localEngine this.localEngine
localEngineSrcPath this.localEngineSrcPath localEngineSrcPath this.localEngineSrcPath
abi abiValue abi PLATFORM_ARCH_MAP[targetArch]
targetPath target targetPath target
verbose isVerbose(project) verbose isVerbose()
fileSystemRoots fileSystemRootsValue fileSystemRoots fileSystemRootsValue
fileSystemScheme fileSystemSchemeValue fileSystemScheme fileSystemSchemeValue
trackWidgetCreation trackWidgetCreationValue trackWidgetCreation trackWidgetCreationValue
...@@ -547,51 +584,24 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -547,51 +584,24 @@ class FlutterPlugin implements Plugin<Project> {
extraGenSnapshotOptions extraGenSnapshotOptionsValue extraGenSnapshotOptions extraGenSnapshotOptionsValue
} }
} }
def libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar") def libJar = project.file("${project.buildDir}/${AndroidProject.FD_INTERMEDIATES}/flutter/${variant.name}/libs.jar")
def libFlutterPlatforms = targetPlatforms.collect() Task packFlutterAppAotTask = project.tasks.create(name: "packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}", type: Jar) {
// x86/x86_64 native library used for debugging only, for now.
if (flutterBuildMode == 'debug') {
libFlutterPlatforms.add('android-x86')
libFlutterPlatforms.add('android-x64')
}
Task packFlutterSnapshotsAndLibsTask = project.tasks.create(name: "packLibs${FLUTTER_BUILD_PREFIX}${variant.name.capitalize()}", type: Jar) {
destinationDir libJar.parentFile destinationDir libJar.parentFile
archiveName libJar.name archiveName libJar.name
libFlutterPlatforms.each { targetArch ->
// This check prevents including `libflutter.so` twice, since it's included in the base platform jar.
// Unfortunately, the `pickFirst` setting in `packagingOptions` does not work when the project `:flutter`
// is included as an implementation dependency, which causes duplicated `libflutter.so`.
if (getBasePlatform(project) == targetArch) {
return
}
// Don't include `libflutter.so` for other architectures when a local engine is specified.
if (useLocalEngine(project)) {
return
}
def engineArtifactSubdir = getEngineArtifactDirName(variant.buildType, targetArch);
// Include `libflutter.so`.
// TODO(blasten): The libs should be outside `flutter.jar` when the artifacts are downloaded.
from(project.zipTree("${flutterRoot}/bin/cache/artifacts/engine/${engineArtifactSubdir}/flutter.jar")) {
include 'lib/**'
}
}
dependsOn compileTasks dependsOn compileTasks
// Add the ELF library.
compileTasks.each { compileTask -> compileTasks.each { compileTask ->
from(compileTask.intermediateDir) { from(compileTask.intermediateDir) {
include '*.so' include '*.so'
// Move `app.so` to `lib/<abi>/libapp.so`
rename { String filename -> rename { String filename ->
return "lib/${compileTask.abi}/lib${filename}" return "lib/${compileTask.abi}/lib${filename}"
} }
} }
} }
} }
// Include the snapshots and libflutter.so in `lib/`.
addApiDependencies(project, variant.name, project.files { addApiDependencies(project, variant.name, project.files {
packFlutterSnapshotsAndLibsTask packFlutterAppAotTask
}) })
// We know that the flutter app is a subproject in another Android app when these tasks exist. // We know that the flutter app is a subproject in another Android app when these tasks exist.
Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets") Task packageAssets = project.tasks.findByPath(":flutter:package${variant.name.capitalize()}Assets")
Task cleanPackageAssets = project.tasks.findByPath(":flutter:cleanPackage${variant.name.capitalize()}Assets") Task cleanPackageAssets = project.tasks.findByPath(":flutter:cleanPackage${variant.name.capitalize()}Assets")
...@@ -618,57 +628,7 @@ class FlutterPlugin implements Plugin<Project> { ...@@ -618,57 +628,7 @@ class FlutterPlugin implements Plugin<Project> {
} else { } else {
project.android.libraryVariants.all addFlutterDeps project.android.libraryVariants.all addFlutterDeps
} }
configurePlugins()
if (buildPluginAsAar()) {
addPluginTasks(project)
List<String> tasksToExecute = project.gradle.startParameter.taskNames
Set buildTypes = getBuildTypesForTasks(project, tasksToExecute)
if (tasksToExecute.contains("clean")) {
// Because the plugins are built during configuration, the task "clean"
// cannot run in conjunction with an assembly task.
if (!buildTypes.empty) {
throw new GradleException("Can't run the clean task along with other assemble tasks")
}
}
// Build plugins when a task "assembly*" will be called later.
if (!buildTypes.empty) {
// Build the plugin during configuration.
// This is required when Jetifier is enabled, otherwise the implementation dependency
// cannot be added.
buildPlugins(project, buildTypes)
}
} else {
getPluginList(project).each { name, _ ->
def pluginProject = project.rootProject.findProject(":$name")
if (pluginProject != null) {
project.dependencies {
if (project.getConfigurations().findByName("implementation")) {
implementation pluginProject
} else {
compile pluginProject
}
}
pluginProject.afterEvaluate {
pluginProject.android.buildTypes {
profile {
initWith debug
}
}
pluginProject.android.buildTypes.each {
def buildMode = buildModeFor(it)
addFlutterJarCompileOnlyDependency(pluginProject, it.name, project.files( flutterJar ?: baseJar[buildMode] ))
}
pluginProject.android.buildTypes.whenObjectAdded {
def buildMode = buildModeFor(it)
addFlutterJarCompileOnlyDependency(pluginProject, it.name, project.files( flutterJar ?: baseJar[buildMode] ))
}
}
} else {
project.logger.error("Plugin project :$name not found. Please update settings.gradle.")
}
}
}
} }
} }
......
// 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.
//
//
// This script is used to warm the Gradle cache by downloading the Flutter dependencies
// used during the build. This script is invoked when `flutter precache` is run.
//
// Command:
// gradle -b <flutter-sdk>packages/flutter_tools/gradle/resolve_dependencies.gradle
// resolveDependencies
//
// This way, Gradle can run with the `--offline` flag later on to eliminate any
// network request during the build process.
//
// This includes:
// 1. The embedding
// 2. libflutter.so
import java.nio.file.Paths
repositories {
google()
jcenter()
maven {
url "http://download.flutter.io"
}
}
File flutterRoot = projectDir.parentFile.parentFile.parentFile
assert flutterRoot.isDirectory()
String engineVersion = Paths.get(flutterRoot.absolutePath, "bin", "internal", "engine.version")
.toFile().text.trim()
configurations {
flutterRelease.extendsFrom releaseImplementation
flutterDebug.extendsFrom debugImplementation
flutterProfile.extendsFrom debugImplementation
}
dependencies {
flutterRelease "io.flutter:flutter_embedding_release:1.0.0-$engineVersion"
flutterRelease "io.flutter:armeabi_v7a_release:1.0.0-$engineVersion"
flutterRelease "io.flutter:arm64_v8a_release:1.0.0-$engineVersion"
flutterProfile "io.flutter:flutter_embedding_profile:1.0.0-$engineVersion"
flutterProfile "io.flutter:armeabi_v7a_profile:1.0.0-$engineVersion"
flutterProfile "io.flutter:arm64_v8a_profile:1.0.0-$engineVersion"
flutterDebug "io.flutter:flutter_embedding_debug:1.0.0-$engineVersion"
flutterDebug "io.flutter:armeabi_v7a_debug:1.0.0-$engineVersion"
flutterDebug "io.flutter:arm64_v8a_debug:1.0.0-$engineVersion"
flutterDebug "io.flutter:x86_debug:1.0.0-$engineVersion"
flutterDebug "io.flutter:x86_64_debug:1.0.0-$engineVersion"
}
task resolveDependencies {
configurations.each { configuration ->
if (configuration.name.startsWith("flutter")) {
configuration.resolve()
}
}
}
...@@ -84,7 +84,7 @@ Future<void> main(List<String> args) async { ...@@ -84,7 +84,7 @@ Future<void> main(List<String> args) async {
LogsCommand(), LogsCommand(),
MakeHostAppEditableCommand(), MakeHostAppEditableCommand(),
PackagesCommand(), PackagesCommand(),
PrecacheCommand(), PrecacheCommand(verboseHelp: verboseHelp),
RunCommand(verboseHelp: verboseHelp), RunCommand(verboseHelp: verboseHelp),
ScreenshotCommand(), ScreenshotCommand(),
ShellCompletionCommand(), ShellCompletionCommand(),
......
...@@ -6,14 +6,16 @@ import 'dart:async'; ...@@ -6,14 +6,16 @@ import 'dart:async';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'android/gradle.dart';
import 'base/common.dart'; import 'base/common.dart';
import 'base/context.dart'; import 'base/context.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/io.dart' show SocketException; import 'base/io.dart' show Process, SocketException;
import 'base/logger.dart'; import 'base/logger.dart';
import 'base/net.dart'; import 'base/net.dart';
import 'base/os.dart'; import 'base/os.dart';
import 'base/platform.dart'; import 'base/platform.dart';
import 'base/process.dart';
import 'globals.dart'; import 'globals.dart';
/// A tag for a set of development artifacts that need to be cached. /// A tag for a set of development artifacts that need to be cached.
...@@ -30,7 +32,10 @@ class DevelopmentArtifact { ...@@ -30,7 +32,10 @@ class DevelopmentArtifact {
final bool unstable; final bool unstable;
/// Artifacts required for Android development. /// Artifacts required for Android development.
static const DevelopmentArtifact android = DevelopmentArtifact._('android'); static const DevelopmentArtifact androidGenSnapshot = DevelopmentArtifact._('android_gen_snapshot');
static const DevelopmentArtifact androidMaven = DevelopmentArtifact._('android_maven');
// Artifacts used for internal builds.
static const DevelopmentArtifact androidInternalBuild = DevelopmentArtifact._('android_internal_build');
/// Artifacts required for iOS development. /// Artifacts required for iOS development.
static const DevelopmentArtifact iOS = DevelopmentArtifact._('ios'); static const DevelopmentArtifact iOS = DevelopmentArtifact._('ios');
...@@ -58,7 +63,9 @@ class DevelopmentArtifact { ...@@ -58,7 +63,9 @@ class DevelopmentArtifact {
/// The values of DevelopmentArtifacts. /// The values of DevelopmentArtifacts.
static final List<DevelopmentArtifact> values = <DevelopmentArtifact>[ static final List<DevelopmentArtifact> values = <DevelopmentArtifact>[
android, androidGenSnapshot,
androidMaven,
androidInternalBuild,
iOS, iOS,
web, web,
macOS, macOS,
...@@ -74,12 +81,16 @@ class DevelopmentArtifact { ...@@ -74,12 +81,16 @@ class DevelopmentArtifact {
class Cache { class Cache {
/// [rootOverride] is configurable for testing. /// [rootOverride] is configurable for testing.
/// [artifacts] is configurable for testing. /// [artifacts] is configurable for testing.
Cache({ Directory rootOverride, List<CachedArtifact> artifacts }) : _rootOverride = rootOverride { Cache({ Directory rootOverride, List<ArtifactSet> artifacts }) : _rootOverride = rootOverride {
if (artifacts == null) { if (artifacts == null) {
_artifacts.add(MaterialFonts(this)); _artifacts.add(MaterialFonts(this));
_artifacts.add(AndroidEngineArtifacts(this));
_artifacts.add(IOSEngineArtifacts(this));
_artifacts.add(GradleWrapper(this)); _artifacts.add(GradleWrapper(this));
_artifacts.add(AndroidMavenArtifacts());
_artifacts.add(AndroidGenSnapshotArtifacts(this));
_artifacts.add(AndroidInternalBuildArtifacts(this));
_artifacts.add(IOSEngineArtifacts(this));
_artifacts.add(FlutterWebSdk(this)); _artifacts.add(FlutterWebSdk(this));
_artifacts.add(FlutterSdk(this)); _artifacts.add(FlutterSdk(this));
_artifacts.add(WindowsEngineArtifacts(this)); _artifacts.add(WindowsEngineArtifacts(this));
...@@ -101,7 +112,7 @@ class Cache { ...@@ -101,7 +112,7 @@ class Cache {
]; ];
final Directory _rootOverride; final Directory _rootOverride;
final List<CachedArtifact> _artifacts = <CachedArtifact>[]; final List<ArtifactSet> _artifacts = <ArtifactSet>[];
// Initialized by FlutterCommandRunner on startup. // Initialized by FlutterCommandRunner on startup.
static String flutterRoot; static String flutterRoot;
...@@ -245,11 +256,16 @@ class Cache { ...@@ -245,11 +256,16 @@ class Cache {
return _dyLdLibEntry; return _dyLdLibEntry;
} }
final List<String> paths = <String>[]; final List<String> paths = <String>[];
for (CachedArtifact artifact in _artifacts) { for (ArtifactSet artifact in _artifacts) {
final String currentPath = artifact.dyLdLibPath; final Map<String, String> env = artifact.environment;
if (currentPath.isNotEmpty) { if (env == null || !env.containsKey('DYLD_LIBRARY_PATH')) {
paths.add(currentPath); continue;
}
final String path = env['DYLD_LIBRARY_PATH'];
if (path.isEmpty) {
continue;
} }
paths.add(path);
} }
_dyLdLibEntry = MapEntry<String, String>('DYLD_LIBRARY_PATH', paths.join(':')); _dyLdLibEntry = MapEntry<String, String>('DYLD_LIBRARY_PATH', paths.join(':'));
return _dyLdLibEntry; return _dyLdLibEntry;
...@@ -289,7 +305,7 @@ class Cache { ...@@ -289,7 +305,7 @@ class Cache {
return isOlderThanReference(entity: entity, referenceFile: flutterToolsStamp); return isOlderThanReference(entity: entity, referenceFile: flutterToolsStamp);
} }
bool isUpToDate() => _artifacts.every((CachedArtifact artifact) => artifact.isUpToDate()); bool isUpToDate() => _artifacts.every((ArtifactSet artifact) => artifact.isUpToDate());
Future<String> getThirdPartyFile(String urlStr, String serviceName) async { Future<String> getThirdPartyFile(String urlStr, String serviceName) async {
final Uri url = Uri.parse(urlStr); final Uri url = Uri.parse(urlStr);
...@@ -318,22 +334,27 @@ class Cache { ...@@ -318,22 +334,27 @@ class Cache {
if (!_lockEnabled) { if (!_lockEnabled) {
return; return;
} }
try { for (ArtifactSet artifact in _artifacts) {
for (CachedArtifact artifact in _artifacts) { if (!requiredArtifacts.contains(artifact.developmentArtifact)) {
if (!artifact.isUpToDate()) { printTrace('Artifact $artifact is not required, skipping update.');
await artifact.update(requiredArtifacts); continue;
}
} }
} on SocketException catch (e) { if (artifact.isUpToDate()) {
if (_hostsBlockedInChina.contains(e.address?.host)) { continue;
printError( }
'Failed to retrieve Flutter tool dependencies: ${e.message}.\n' try {
'If you\'re in China, please see this page: ' await artifact.update();
'https://flutter.dev/community/china', } on SocketException catch (e) {
emphasis: true, if (_hostsBlockedInChina.contains(e.address?.host)) {
); printError(
'Failed to retrieve Flutter tool dependencies: ${e.message}.\n'
'If you\'re in China, please see this page: '
'https://flutter.dev/community/china',
emphasis: true,
);
}
rethrow;
} }
rethrow;
} }
} }
...@@ -354,23 +375,42 @@ class Cache { ...@@ -354,23 +375,42 @@ class Cache {
} }
} }
/// An artifact managed by the cache. /// Representation of a set of artifacts used by the tool.
abstract class CachedArtifact { abstract class ArtifactSet {
CachedArtifact(this.name, this.cache, this.developmentArtifacts); ArtifactSet(this.developmentArtifact) : assert(developmentArtifact != null);
/// The development artifact.
final DevelopmentArtifact developmentArtifact;
/// [true] if the artifact is up to date.
bool isUpToDate();
/// The environment variables (if any) required to consume the artifacts.
Map<String, String> get environment {
return const <String, String>{};
}
/// Updates the artifact.
Future<void> update();
}
/// An artifact set managed by the cache.
abstract class CachedArtifact extends ArtifactSet {
CachedArtifact(
this.name,
this.cache,
DevelopmentArtifact developmentArtifact,
) : super(developmentArtifact);
final String name;
final Cache cache; final Cache cache;
/// The canonical name of the artifact.
final String name;
// The name of the stamp file. Defaults to the same as the // The name of the stamp file. Defaults to the same as the
// artifact name. // artifact name.
String get stampName => name; String get stampName => name;
/// Returns a string to be set as environment DYLD_LIBARY_PATH variable
String get dyLdLibPath => '';
/// All development artifacts this cache provides.
final Set<DevelopmentArtifact> developmentArtifacts;
Directory get location => cache.getArtifactDirectory(name); Directory get location => cache.getArtifactDirectory(name);
String get version => cache.getVersionFor(name); String get version => cache.getVersionFor(name);
...@@ -380,6 +420,7 @@ abstract class CachedArtifact { ...@@ -380,6 +420,7 @@ abstract class CachedArtifact {
/// starting from scratch. /// starting from scratch.
final List<File> _downloadedFiles = <File>[]; final List<File> _downloadedFiles = <File>[];
@override
bool isUpToDate() { bool isUpToDate() {
if (!location.existsSync()) { if (!location.existsSync()) {
return false; return false;
...@@ -390,13 +431,8 @@ abstract class CachedArtifact { ...@@ -390,13 +431,8 @@ abstract class CachedArtifact {
return isUpToDateInner(); return isUpToDateInner();
} }
Future<void> update(Set<DevelopmentArtifact> requiredArtifacts) async { @override
// If the set of required artifacts does not include any from this cache, Future<void> update() async {
// then we can claim we are up to date to skip downloading.
if (!requiredArtifacts.any(developmentArtifacts.contains)) {
printTrace('Artifact $this is not required, skipping update.');
return;
}
if (!location.existsSync()) { if (!location.existsSync()) {
try { try {
location.createSync(recursive: true); location.createSync(recursive: true);
...@@ -499,7 +535,7 @@ class MaterialFonts extends CachedArtifact { ...@@ -499,7 +535,7 @@ class MaterialFonts extends CachedArtifact {
MaterialFonts(Cache cache) : super( MaterialFonts(Cache cache) : super(
'material_fonts', 'material_fonts',
cache, cache,
const <DevelopmentArtifact>{ DevelopmentArtifact.universal }, DevelopmentArtifact.universal,
); );
@override @override
...@@ -517,7 +553,7 @@ class FlutterWebSdk extends CachedArtifact { ...@@ -517,7 +553,7 @@ class FlutterWebSdk extends CachedArtifact {
FlutterWebSdk(Cache cache) : super( FlutterWebSdk(Cache cache) : super(
'flutter_web_sdk', 'flutter_web_sdk',
cache, cache,
const <DevelopmentArtifact>{ DevelopmentArtifact.web }, DevelopmentArtifact.web,
); );
@override @override
...@@ -558,8 +594,8 @@ abstract class EngineCachedArtifact extends CachedArtifact { ...@@ -558,8 +594,8 @@ abstract class EngineCachedArtifact extends CachedArtifact {
EngineCachedArtifact( EngineCachedArtifact(
this.stampName, this.stampName,
Cache cache, Cache cache,
Set<DevelopmentArtifact> requiredArtifacts, DevelopmentArtifact developmentArtifact,
) : super('engine', cache, requiredArtifacts); ) : super('engine', cache, developmentArtifact);
@override @override
final String stampName; final String stampName;
...@@ -680,7 +716,7 @@ class FlutterSdk extends EngineCachedArtifact { ...@@ -680,7 +716,7 @@ class FlutterSdk extends EngineCachedArtifact {
FlutterSdk(Cache cache) : super( FlutterSdk(Cache cache) : super(
'flutter_sdk', 'flutter_sdk',
cache, cache,
const <DevelopmentArtifact>{ DevelopmentArtifact.universal }, DevelopmentArtifact.universal,
); );
@override @override
...@@ -714,7 +750,7 @@ class MacOSEngineArtifacts extends EngineCachedArtifact { ...@@ -714,7 +750,7 @@ class MacOSEngineArtifacts extends EngineCachedArtifact {
MacOSEngineArtifacts(Cache cache) : super( MacOSEngineArtifacts(Cache cache) : super(
'macos-sdk', 'macos-sdk',
cache, cache,
const <DevelopmentArtifact> { DevelopmentArtifact.macOS }, DevelopmentArtifact.macOS,
); );
@override @override
...@@ -736,7 +772,7 @@ class WindowsEngineArtifacts extends EngineCachedArtifact { ...@@ -736,7 +772,7 @@ class WindowsEngineArtifacts extends EngineCachedArtifact {
WindowsEngineArtifacts(Cache cache) : super( WindowsEngineArtifacts(Cache cache) : super(
'windows-sdk', 'windows-sdk',
cache, cache,
const <DevelopmentArtifact> { DevelopmentArtifact.windows }, DevelopmentArtifact.windows,
); );
@override @override
...@@ -758,7 +794,7 @@ class LinuxEngineArtifacts extends EngineCachedArtifact { ...@@ -758,7 +794,7 @@ class LinuxEngineArtifacts extends EngineCachedArtifact {
LinuxEngineArtifacts(Cache cache) : super( LinuxEngineArtifacts(Cache cache) : super(
'linux-sdk', 'linux-sdk',
cache, cache,
const <DevelopmentArtifact> { DevelopmentArtifact.linux }, DevelopmentArtifact.linux,
); );
@override @override
...@@ -776,11 +812,12 @@ class LinuxEngineArtifacts extends EngineCachedArtifact { ...@@ -776,11 +812,12 @@ class LinuxEngineArtifacts extends EngineCachedArtifact {
List<String> getLicenseDirs() => const <String>[]; List<String> getLicenseDirs() => const <String>[];
} }
class AndroidEngineArtifacts extends EngineCachedArtifact { /// The artifact used to generate snapshots for Android builds.
AndroidEngineArtifacts(Cache cache) : super( class AndroidGenSnapshotArtifacts extends EngineCachedArtifact {
AndroidGenSnapshotArtifacts(Cache cache) : super(
'android-sdk', 'android-sdk',
cache, cache,
const <DevelopmentArtifact>{ DevelopmentArtifact.android }, DevelopmentArtifact.androidGenSnapshot,
); );
@override @override
...@@ -794,23 +831,19 @@ class AndroidEngineArtifacts extends EngineCachedArtifact { ...@@ -794,23 +831,19 @@ class AndroidEngineArtifacts extends EngineCachedArtifact {
..._osxBinaryDirs, ..._osxBinaryDirs,
..._linuxBinaryDirs, ..._linuxBinaryDirs,
..._windowsBinaryDirs, ..._windowsBinaryDirs,
..._androidBinaryDirs,
..._dartSdks, ..._dartSdks,
] ]
else if (platform.isWindows) else if (platform.isWindows)
...<List<String>>[ ...<List<String>>[
..._windowsBinaryDirs, ..._windowsBinaryDirs,
..._androidBinaryDirs,
] ]
else if (platform.isMacOS) else if (platform.isMacOS)
...<List<String>>[ ...<List<String>>[
..._osxBinaryDirs, ..._osxBinaryDirs,
..._androidBinaryDirs,
] ]
else if (platform.isLinux) else if (platform.isLinux)
...<List<String>>[ ...<List<String>>[
..._linuxBinaryDirs, ..._linuxBinaryDirs,
..._androidBinaryDirs,
] ]
]; ];
} }
...@@ -819,11 +852,79 @@ class AndroidEngineArtifacts extends EngineCachedArtifact { ...@@ -819,11 +852,79 @@ class AndroidEngineArtifacts extends EngineCachedArtifact {
List<String> getLicenseDirs() { return <String>[]; } List<String> getLicenseDirs() { return <String>[]; }
} }
/// Artifacts used for internal builds. The flutter tool builds Android projects
/// using the artifacts cached by [AndroidMavenArtifacts].
class AndroidInternalBuildArtifacts extends EngineCachedArtifact {
AndroidInternalBuildArtifacts(Cache cache) : super(
'android-internal-build-artifacts',
cache,
DevelopmentArtifact.androidInternalBuild,
);
@override
List<String> getPackageDirs() => const <String>[];
@override
List<List<String>> getBinaryDirs() {
return _androidBinaryDirs;
}
@override
List<String> getLicenseDirs() { return <String>[]; }
}
/// A cached artifact containing the Maven dependencies used to build Android projects.
class AndroidMavenArtifacts extends ArtifactSet {
AndroidMavenArtifacts() : super(DevelopmentArtifact.androidMaven);
@override
Future<void> update() async {
final Directory tempDir =
fs.systemTempDirectory.createTempSync('gradle_wrapper.');
injectGradleWrapperIfNeeded(tempDir);
final Status status = logger.startProgress('Downloading Android Maven dependencies...',
timeout: timeoutConfiguration.slowOperation);
final File gradle = tempDir.childFile(
platform.isWindows ? 'gradlew.bat' : 'gradlew',
);
assert(gradle.existsSync());
os.makeExecutable(gradle);
try {
final String gradleExecutable = gradle.absolute.path;
final String flutterSdk = escapePath(Cache.flutterRoot);
final Process process = await runCommand(
<String>[
gradleExecutable,
'-b', fs.path.join(flutterSdk, 'packages', 'flutter_tools', 'gradle', 'resolve_dependencies.gradle'),
'--project-cache-dir', tempDir.path,
'resolveDependencies',
]);
final int exitCode = await process.exitCode;
if (exitCode != 0) {
printError('Failed to download the Android dependencies');
}
} finally {
status.stop();
tempDir.deleteSync(recursive: true);
}
}
@override
bool isUpToDate() {
// The dependencies are downloaded and cached by Gradle.
// The tool doesn't know if the dependencies are already cached at this point.
// Therefore, call Gradle to figure this out.
return false;
}
}
class IOSEngineArtifacts extends EngineCachedArtifact { class IOSEngineArtifacts extends EngineCachedArtifact {
IOSEngineArtifacts(Cache cache) : super( IOSEngineArtifacts(Cache cache) : super(
'ios-sdk', 'ios-sdk',
cache, cache,
<DevelopmentArtifact>{ DevelopmentArtifact.iOS }, DevelopmentArtifact.iOS,
); );
@override @override
...@@ -856,7 +957,7 @@ class GradleWrapper extends CachedArtifact { ...@@ -856,7 +957,7 @@ class GradleWrapper extends CachedArtifact {
GradleWrapper(Cache cache) : super( GradleWrapper(Cache cache) : super(
'gradle_wrapper', 'gradle_wrapper',
cache, cache,
const <DevelopmentArtifact>{ DevelopmentArtifact.universal }, DevelopmentArtifact.universal,
); );
List<String> get _gradleScripts => <String>['gradlew', 'gradlew.bat']; List<String> get _gradleScripts => <String>['gradlew', 'gradlew.bat'];
...@@ -897,11 +998,13 @@ class GradleWrapper extends CachedArtifact { ...@@ -897,11 +998,13 @@ class GradleWrapper extends CachedArtifact {
/// Common functionality for pulling Fuchsia SDKs. /// Common functionality for pulling Fuchsia SDKs.
abstract class _FuchsiaSDKArtifacts extends CachedArtifact { abstract class _FuchsiaSDKArtifacts extends CachedArtifact {
_FuchsiaSDKArtifacts(Cache cache, String platform) _FuchsiaSDKArtifacts(Cache cache, String platform) :
:_path = 'fuchsia/sdk/core/$platform-amd64', _path = 'fuchsia/sdk/core/$platform-amd64',
super('fuchsia-$platform', cache, const <DevelopmentArtifact> { super(
DevelopmentArtifact.fuchsia, 'fuchsia-$platform',
}); cache,
DevelopmentArtifact.fuchsia,
);
final String _path; final String _path;
...@@ -917,10 +1020,11 @@ abstract class _FuchsiaSDKArtifacts extends CachedArtifact { ...@@ -917,10 +1020,11 @@ abstract class _FuchsiaSDKArtifacts extends CachedArtifact {
/// The pre-built flutter runner for Fuchsia development. /// The pre-built flutter runner for Fuchsia development.
class FlutterRunnerSDKArtifacts extends CachedArtifact { class FlutterRunnerSDKArtifacts extends CachedArtifact {
FlutterRunnerSDKArtifacts(Cache cache) FlutterRunnerSDKArtifacts(Cache cache) : super(
: super('flutter_runner', cache, const <DevelopmentArtifact>{ 'flutter_runner',
cache,
DevelopmentArtifact.flutterRunner, DevelopmentArtifact.flutterRunner,
}); );
@override @override
Directory get location => cache.getArtifactDirectory('flutter_runner'); Directory get location => cache.getArtifactDirectory('flutter_runner');
...@@ -971,7 +1075,7 @@ class IosUsbArtifacts extends CachedArtifact { ...@@ -971,7 +1075,7 @@ class IosUsbArtifacts extends CachedArtifact {
name, name,
cache, cache,
// This is universal to ensure every command checks for them first // This is universal to ensure every command checks for them first
const <DevelopmentArtifact>{ DevelopmentArtifact.universal }, DevelopmentArtifact.universal,
); );
static const List<String> artifactNames = <String>[ static const List<String> artifactNames = <String>[
...@@ -984,8 +1088,10 @@ class IosUsbArtifacts extends CachedArtifact { ...@@ -984,8 +1088,10 @@ class IosUsbArtifacts extends CachedArtifact {
]; ];
@override @override
String get dyLdLibPath { Map<String, String> get environment {
return cache.getArtifactDirectory(name).path; return <String, String>{
'DYLD_LIBRARY_PATH': cache.getArtifactDirectory(name).path,
};
} }
@override @override
...@@ -1093,6 +1199,12 @@ const List<List<String>> _windowsBinaryDirs = <List<String>>[ ...@@ -1093,6 +1199,12 @@ const List<List<String>> _windowsBinaryDirs = <List<String>>[
<String>['android-arm64-release/windows-x64', 'android-arm64-release/windows-x64.zip'], <String>['android-arm64-release/windows-x64', 'android-arm64-release/windows-x64.zip'],
]; ];
const List<List<String>> _iosBinaryDirs = <List<String>>[
<String>['ios', 'ios/artifacts.zip'],
<String>['ios-profile', 'ios-profile/artifacts.zip'],
<String>['ios-release', 'ios-release/artifacts.zip'],
];
const List<List<String>> _androidBinaryDirs = <List<String>>[ const List<List<String>> _androidBinaryDirs = <List<String>>[
<String>['android-x86', 'android-x86/artifacts.zip'], <String>['android-x86', 'android-x86/artifacts.zip'],
<String>['android-x64', 'android-x64/artifacts.zip'], <String>['android-x64', 'android-x64/artifacts.zip'],
...@@ -1104,12 +1216,6 @@ const List<List<String>> _androidBinaryDirs = <List<String>>[ ...@@ -1104,12 +1216,6 @@ const List<List<String>> _androidBinaryDirs = <List<String>>[
<String>['android-arm64-release', 'android-arm64-release/artifacts.zip'], <String>['android-arm64-release', 'android-arm64-release/artifacts.zip'],
]; ];
const List<List<String>> _iosBinaryDirs = <List<String>>[
<String>['ios', 'ios/artifacts.zip'],
<String>['ios-profile', 'ios-profile/artifacts.zip'],
<String>['ios-release', 'ios-release/artifacts.zip'],
];
const List<List<String>> _dartSdks = <List<String>> [ const List<List<String>> _dartSdks = <List<String>> [
<String>['darwin-x64', 'dart-sdk-darwin-x64.zip'], <String>['darwin-x64', 'dart-sdk-darwin-x64.zip'],
<String>['linux-x64', 'dart-sdk-linux-x64.zip'], <String>['linux-x64', 'dart-sdk-linux-x64.zip'],
......
...@@ -9,7 +9,7 @@ import '../base/os.dart'; ...@@ -9,7 +9,7 @@ import '../base/os.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult; import '../runner/flutter_command.dart' show FlutterCommandResult;
import 'build.dart'; import 'build.dart';
class BuildAarCommand extends BuildSubCommand { class BuildAarCommand extends BuildSubCommand {
...@@ -52,12 +52,6 @@ class BuildAarCommand extends BuildSubCommand { ...@@ -52,12 +52,6 @@ class BuildAarCommand extends BuildSubCommand {
return usage; return usage;
} }
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.android,
};
@override @override
final String description = 'Build a repository containing an AAR and a POM file.\n\n' final String description = 'Build a repository containing an AAR and a POM file.\n\n'
'The POM file is used to include the dependencies that the AAR was compiled against.\n\n' 'The POM file is used to include the dependencies that the AAR was compiled against.\n\n'
......
...@@ -10,7 +10,7 @@ import '../build_info.dart'; ...@@ -10,7 +10,7 @@ import '../build_info.dart';
import '../globals.dart'; import '../globals.dart';
import '../project.dart'; import '../project.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
import '../runner/flutter_command.dart' show DevelopmentArtifact, FlutterCommandResult; import '../runner/flutter_command.dart' show FlutterCommandResult;
import 'build.dart'; import 'build.dart';
class BuildApkCommand extends BuildSubCommand { class BuildApkCommand extends BuildSubCommand {
...@@ -68,12 +68,6 @@ class BuildApkCommand extends BuildSubCommand { ...@@ -68,12 +68,6 @@ class BuildApkCommand extends BuildSubCommand {
return usage; return usage;
} }
@override
Future<Set<DevelopmentArtifact>> get requiredArtifacts async => const <DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.android,
};
@override @override
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> runCommand() async {
final BuildInfo buildInfo = getBuildInfo(); final BuildInfo buildInfo = getBuildInfo();
......
...@@ -37,7 +37,7 @@ class DoctorCommand extends FlutterCommand { ...@@ -37,7 +37,7 @@ class DoctorCommand extends FlutterCommand {
// This is required because we use gen_snapshot to check if the host // This is required because we use gen_snapshot to check if the host
// machine can execute the provided artifacts. See `_genSnapshotRuns` // machine can execute the provided artifacts. See `_genSnapshotRuns`
// in `doctor.dart`. // in `doctor.dart`.
DevelopmentArtifact.android, DevelopmentArtifact.androidGenSnapshot,
}; };
} }
......
...@@ -10,13 +10,23 @@ import '../runner/flutter_command.dart'; ...@@ -10,13 +10,23 @@ import '../runner/flutter_command.dart';
import '../version.dart'; import '../version.dart';
class PrecacheCommand extends FlutterCommand { class PrecacheCommand extends FlutterCommand {
PrecacheCommand() { PrecacheCommand({bool verboseHelp = false}) {
argParser.addFlag('all-platforms', abbr: 'a', negatable: false, argParser.addFlag('all-platforms', abbr: 'a', negatable: false,
help: 'Precache artifacts for all host platforms.'); help: 'Precache artifacts for all host platforms.');
argParser.addFlag('force', abbr: 'f', negatable: false, argParser.addFlag('force', abbr: 'f', negatable: false,
help: 'Force downloading of artifacts.'); help: 'Force downloading of artifacts.');
argParser.addFlag('android', negatable: true, defaultsTo: true, argParser.addFlag('android', negatable: true, defaultsTo: true,
help: 'Precache artifacts for Android development.'); help: 'Precache artifacts for Android development.',
hide: verboseHelp);
argParser.addFlag('android_gen_snapshot', negatable: true, defaultsTo: true,
help: 'Precache gen_snapshot for Android development.',
hide: !verboseHelp);
argParser.addFlag('android_maven', negatable: true, defaultsTo: true,
help: 'Precache Gradle dependencies for Android development.',
hide: !verboseHelp);
argParser.addFlag('android_internal_build', negatable: true, defaultsTo: false,
help: 'Precache dependencies for internal Android development.',
hide: !verboseHelp);
argParser.addFlag('ios', negatable: true, defaultsTo: true, argParser.addFlag('ios', negatable: true, defaultsTo: true,
help: 'Precache artifacts for iOS development.'); help: 'Precache artifacts for iOS development.');
argParser.addFlag('web', negatable: true, defaultsTo: false, argParser.addFlag('web', negatable: true, defaultsTo: false,
...@@ -58,6 +68,10 @@ class PrecacheCommand extends FlutterCommand { ...@@ -58,6 +68,10 @@ class PrecacheCommand extends FlutterCommand {
if (argResults[artifact.name]) { if (argResults[artifact.name]) {
requiredArtifacts.add(artifact); requiredArtifacts.add(artifact);
} }
// The `android` flag expands to android_gen_snapshot, android_maven, android_internal_build.
if (artifact.name.startsWith('android_') && argResults['android']) {
requiredArtifacts.add(artifact);
}
} }
final bool forceUpdate = argResults['force']; final bool forceUpdate = argResults['force'];
if (forceUpdate || !cache.isUpToDate()) { if (forceUpdate || !cache.isUpToDate()) {
......
...@@ -644,7 +644,7 @@ DevelopmentArtifact _artifactFromTargetPlatform(TargetPlatform targetPlatform) { ...@@ -644,7 +644,7 @@ DevelopmentArtifact _artifactFromTargetPlatform(TargetPlatform targetPlatform) {
case TargetPlatform.android_arm64: case TargetPlatform.android_arm64:
case TargetPlatform.android_x64: case TargetPlatform.android_x64:
case TargetPlatform.android_x86: case TargetPlatform.android_x86:
return DevelopmentArtifact.android; return DevelopmentArtifact.androidGenSnapshot;
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
return DevelopmentArtifact.web; return DevelopmentArtifact.web;
case TargetPlatform.ios: case TargetPlatform.ios:
......
...@@ -47,9 +47,9 @@ dependencies { ...@@ -47,9 +47,9 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
{{/androidX}} {{/androidX}}
{{^androidX}} {{^androidX}}
implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:design:27.1.1' implementation 'com.android.support:design:28.0.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
{{/androidX}} {{/androidX}}
......
...@@ -8,8 +8,10 @@ import 'package:file_testing/file_testing.dart'; ...@@ -8,8 +8,10 @@ import 'package:file_testing/file_testing.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/base/common.dart'; 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/cache.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException; import 'package:flutter_tools/src/base/io.dart' show InternetAddress, SocketException;
...@@ -136,18 +138,30 @@ void main() { ...@@ -136,18 +138,30 @@ void main() {
when(artifact1.isUpToDate()).thenReturn(true); when(artifact1.isUpToDate()).thenReturn(true);
when(artifact2.isUpToDate()).thenReturn(false); when(artifact2.isUpToDate()).thenReturn(false);
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]); final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
await cache.updateAll(<DevelopmentArtifact>{}); await cache.updateAll(<DevelopmentArtifact>{
verifyNever(artifact1.update(<DevelopmentArtifact>{})); null,
verify(artifact2.update(<DevelopmentArtifact>{})); });
verifyNever(artifact1.update());
verify(artifact2.update());
}); });
testUsingContext('getter dyLdLibEntry concatenates the output of each artifact\'s dyLdLibEntry getter', () async { testUsingContext('getter dyLdLibEntry concatenates the output of each artifact\'s dyLdLibEntry getter', () async {
final CachedArtifact artifact1 = MockCachedArtifact(); final IosUsbArtifacts artifact1 = MockIosUsbArtifacts();
final CachedArtifact artifact2 = MockCachedArtifact(); final IosUsbArtifacts artifact2 = MockIosUsbArtifacts();
final CachedArtifact artifact3 = MockCachedArtifact(); final IosUsbArtifacts artifact3 = MockIosUsbArtifacts();
when(artifact1.dyLdLibPath).thenReturn('/path/to/alpha:/path/to/beta'); when(artifact1.environment)
when(artifact2.dyLdLibPath).thenReturn('/path/to/gamma:/path/to/delta:/path/to/epsilon'); .thenReturn(<String, String>{
when(artifact3.dyLdLibPath).thenReturn(''); // Empty output 'DYLD_LIBRARY_PATH': '/path/to/alpha:/path/to/beta',
});
when(artifact2.environment)
.thenReturn(<String, String>{
'DYLD_LIBRARY_PATH': '/path/to/gamma:/path/to/delta:/path/to/epsilon',
});
when(artifact3.environment)
.thenReturn(<String, String>{
'DYLD_LIBRARY_PATH': '',
});
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2, artifact3]); final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2, artifact3]);
expect(cache.dyLdLibEntry.key, 'DYLD_LIBRARY_PATH'); expect(cache.dyLdLibEntry.key, 'DYLD_LIBRARY_PATH');
expect( expect(
cache.dyLdLibEntry.value, cache.dyLdLibEntry.value,
...@@ -163,18 +177,20 @@ void main() { ...@@ -163,18 +177,20 @@ void main() {
when(artifact2.isUpToDate()).thenReturn(false); when(artifact2.isUpToDate()).thenReturn(false);
final MockInternetAddress address = MockInternetAddress(); final MockInternetAddress address = MockInternetAddress();
when(address.host).thenReturn('storage.googleapis.com'); when(address.host).thenReturn('storage.googleapis.com');
when(artifact1.update(<DevelopmentArtifact>{})).thenThrow(SocketException( when(artifact1.update()).thenThrow(SocketException(
'Connection reset by peer', 'Connection reset by peer',
address: address, address: address,
)); ));
final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]); final Cache cache = Cache(artifacts: <CachedArtifact>[artifact1, artifact2]);
try { try {
await cache.updateAll(<DevelopmentArtifact>{}); await cache.updateAll(<DevelopmentArtifact>{
null,
});
fail('Mock thrown exception expected'); fail('Mock thrown exception expected');
} catch (e) { } catch (e) {
verify(artifact1.update(<DevelopmentArtifact>{})); verify(artifact1.update());
// Don't continue when retrieval fails. // Don't continue when retrieval fails.
verifyNever(artifact2.update(<DevelopmentArtifact>{})); verifyNever(artifact2.update());
expect( expect(
testLogger.errorText, testLogger.errorText,
contains('https://flutter.dev/community/china'), contains('https://flutter.dev/community/china'),
...@@ -226,6 +242,7 @@ void main() { ...@@ -226,6 +242,7 @@ void main() {
binaryDirs: <List<String>>[ binaryDirs: <List<String>>[
<String>['bin_dir', 'unused_url_path'], <String>['bin_dir', 'unused_url_path'],
], ],
requiredArtifacts: DevelopmentArtifact.universal,
); );
await artifact.updateInner(); await artifact.updateInner();
final Directory dir = memoryFileSystem.systemTempDirectory final Directory dir = memoryFileSystem.systemTempDirectory
...@@ -244,25 +261,56 @@ void main() { ...@@ -244,25 +261,56 @@ void main() {
}); });
}); });
testUsingContext('throws tool exit on fs exception', () async { group('AndroidMavenArtifacts', () {
final FakeCachedArtifact fakeCachedArtifact = FakeCachedArtifact( MemoryFileSystem memoryFileSystem;
cache: MockCache(), MockProcessManager processManager;
requiredArtifacts: <DevelopmentArtifact>{ MockCache mockCache;
DevelopmentArtifact.android, MockProcess mockProcess;
}
); setUp(() {
final Directory mockDirectory = MockDirectory(); memoryFileSystem = MemoryFileSystem();
when(fakeCachedArtifact.cache.getArtifactDirectory(any)) processManager = MockProcessManager();
.thenReturn(mockDirectory); mockCache = MockCache();
when(mockDirectory.existsSync()).thenReturn(false); mockProcess = MockProcess();
when(mockDirectory.createSync(recursive: true)) });
.thenThrow(const FileSystemException());
test('development artifact', () async {
expect(() => fakeCachedArtifact.update(<DevelopmentArtifact>{ final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts();
DevelopmentArtifact.android, expect(mavenArtifacts.developmentArtifact, DevelopmentArtifact.androidMaven);
}), throwsA(isInstanceOf<ToolExit>())); });
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), testUsingContext('update', () async {
final AndroidMavenArtifacts mavenArtifacts = AndroidMavenArtifacts();
expect(mavenArtifacts.isUpToDate(), isFalse);
final Directory gradleWrapperDir = fs.systemTempDirectory.createTempSync('gradle_wrapper.');
when(mockCache.getArtifactDirectory('gradle_wrapper')).thenReturn(gradleWrapperDir);
fs.directory(gradleWrapperDir.childDirectory('gradle').childDirectory('wrapper'))
.createSync(recursive: true);
fs.file(fs.path.join(gradleWrapperDir.path, 'gradlew')).writeAsStringSync('irrelevant');
fs.file(fs.path.join(gradleWrapperDir.path, 'gradlew.bat')).writeAsStringSync('irrelevant');
when(processManager.start(any))
.thenAnswer((Invocation invocation){
final List<String> args = invocation.positionalArguments[0];
expect(args.length, 6);
expect(args[1], '-b');
expect(args[2].endsWith('resolve_dependencies.gradle'), isTrue);
expect(args[5], 'resolveDependencies');
return Future<Process>.value(mockProcess);
});
when(mockProcess.exitCode).thenAnswer((_) async => 0);
await mavenArtifacts.update();
expect(mavenArtifacts.isUpToDate(), isFalse);
}, overrides: <Type, Generator>{
Cache: ()=> mockCache,
FileSystem: () => memoryFileSystem,
ProcessManager: () => processManager,
});
}); });
} }
...@@ -270,7 +318,7 @@ class FakeCachedArtifact extends EngineCachedArtifact { ...@@ -270,7 +318,7 @@ class FakeCachedArtifact extends EngineCachedArtifact {
FakeCachedArtifact({ FakeCachedArtifact({
String stampName = 'STAMP', String stampName = 'STAMP',
@required Cache cache, @required Cache cache,
Set<DevelopmentArtifact> requiredArtifacts = const <DevelopmentArtifact>{}, DevelopmentArtifact requiredArtifacts,
this.binaryDirs = const <List<String>>[], this.binaryDirs = const <List<String>>[],
this.licenseDirs = const <String>[], this.licenseDirs = const <String>[],
this.packageDirs = const <String>[], this.packageDirs = const <String>[],
...@@ -290,12 +338,15 @@ class FakeCachedArtifact extends EngineCachedArtifact { ...@@ -290,12 +338,15 @@ class FakeCachedArtifact extends EngineCachedArtifact {
List<String> getPackageDirs() => packageDirs; List<String> getPackageDirs() => packageDirs;
} }
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockFileSystem extends Mock implements FileSystem {} class MockFileSystem extends Mock implements FileSystem {}
class MockFile extends Mock implements File {} class MockFile extends Mock implements File {}
class MockDirectory extends Mock implements Directory {} class MockDirectory extends Mock implements Directory {}
class MockRandomAccessFile extends Mock implements RandomAccessFile {} class MockRandomAccessFile extends Mock implements RandomAccessFile {}
class MockCachedArtifact extends Mock implements CachedArtifact {} class MockCachedArtifact extends Mock implements CachedArtifact {}
class MockIosUsbArtifacts extends Mock implements IosUsbArtifacts {}
class MockInternetAddress extends Mock implements InternetAddress {} class MockInternetAddress extends Mock implements InternetAddress {}
class MockCache extends Mock implements Cache {} class MockCache extends Mock implements Cache {}
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {} class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {}
...@@ -27,12 +27,24 @@ void main() { ...@@ -27,12 +27,24 @@ void main() {
final PrecacheCommand command = PrecacheCommand(); final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['precache', '--ios', '--android', '--web', '--macos', '--linux', '--windows', '--fuchsia', '--flutter_runner'] const <String>[
'precache',
'--ios',
'--android',
'--web',
'--macos',
'--linux',
'--windows',
'--fuchsia',
'--flutter_runner',
]
); );
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{ expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal, DevelopmentArtifact.universal,
DevelopmentArtifact.iOS, DevelopmentArtifact.iOS,
DevelopmentArtifact.android, DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
DevelopmentArtifact.web, DevelopmentArtifact.web,
DevelopmentArtifact.macOS, DevelopmentArtifact.macOS,
DevelopmentArtifact.linux, DevelopmentArtifact.linux,
...@@ -44,6 +56,54 @@ void main() { ...@@ -44,6 +56,54 @@ void main() {
Cache: () => cache, Cache: () => cache,
}); });
testUsingContext('Expands android artifacts when the android flag is used', () async {
// Release lock between test cases.
Cache.releaseLockEarly();
final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command);
await createTestCommandRunner(command).run(
const <String>[
'precache',
'--no-ios',
'--android',
]
);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
testUsingContext('Adds artifact flags to requested android artifacts', () async {
// Release lock between test cases.
Cache.releaseLockEarly();
final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command);
await createTestCommandRunner(command).run(
const <String>[
'precache',
'--no-ios',
'--android_gen_snapshot',
'--android_maven',
'--android_internal_build',
]
);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal,
DevelopmentArtifact.androidGenSnapshot,
DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{
Cache: () => cache,
});
final MockFlutterVersion flutterVersion = MockFlutterVersion(); final MockFlutterVersion flutterVersion = MockFlutterVersion();
when(flutterVersion.isMaster).thenReturn(false); when(flutterVersion.isMaster).thenReturn(false);
...@@ -53,18 +113,31 @@ void main() { ...@@ -53,18 +113,31 @@ void main() {
final PrecacheCommand command = PrecacheCommand(); final PrecacheCommand command = PrecacheCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['precache', '--ios', '--android', '--web', '--macos', '--linux', '--windows', '--fuchsia', '--flutter_runner'] const <String>[
'precache',
'--ios',
'--android_gen_snapshot',
'--android_maven',
'--android_internal_build',
'--web',
'--macos',
'--linux',
'--windows',
'--fuchsia',
'--flutter_runner',
]
); );
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{ expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal, DevelopmentArtifact.universal,
DevelopmentArtifact.iOS, DevelopmentArtifact.iOS,
DevelopmentArtifact.android, DevelopmentArtifact.androidGenSnapshot,
})); DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => cache, Cache: () => cache,
FlutterVersion: () => flutterVersion, FlutterVersion: () => flutterVersion,
}); });
testUsingContext('Downloads artifacts when --force is provided', () async { testUsingContext('Downloads artifacts when --force is provided', () async {
when(cache.isUpToDate()).thenReturn(true); when(cache.isUpToDate()).thenReturn(true);
// Release lock between test cases. // Release lock between test cases.
...@@ -73,10 +146,12 @@ void main() { ...@@ -73,10 +146,12 @@ void main() {
applyMocksToCommand(command); applyMocksToCommand(command);
await createTestCommandRunner(command).run(const <String>['precache', '--force']); await createTestCommandRunner(command).run(const <String>['precache', '--force']);
expect(artifacts, unorderedEquals(<DevelopmentArtifact>{ expect(artifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal, DevelopmentArtifact.universal,
DevelopmentArtifact.iOS, DevelopmentArtifact.iOS,
DevelopmentArtifact.android, DevelopmentArtifact.androidGenSnapshot,
})); DevelopmentArtifact.androidMaven,
DevelopmentArtifact.androidInternalBuild,
}));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Cache: () => cache, Cache: () => cache,
FlutterVersion: () => flutterVersion, FlutterVersion: () => flutterVersion,
......
...@@ -138,7 +138,7 @@ void main() { ...@@ -138,7 +138,7 @@ void main() {
expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{ expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal, DevelopmentArtifact.universal,
DevelopmentArtifact.android, DevelopmentArtifact.androidGenSnapshot,
})); }));
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) { when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
...@@ -162,7 +162,7 @@ void main() { ...@@ -162,7 +162,7 @@ void main() {
expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{ expect(await RunCommand().requiredArtifacts, unorderedEquals(<DevelopmentArtifact>{
DevelopmentArtifact.universal, DevelopmentArtifact.universal,
DevelopmentArtifact.iOS, DevelopmentArtifact.iOS,
DevelopmentArtifact.android, DevelopmentArtifact.androidGenSnapshot,
})); }));
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) { when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
......
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