Skip to content

Implement AAR size measurement. #805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


package com.google.firebase.gradle.plugins.measurement.aarsize

/** A helper class that generates the AAR size measurement JSON report. */
class AarSizeJsonBuilder {

private static final String PULL_REQUEST_TABLE = "AndroidPullRequests"
private static final String PULL_REQUEST_COLUMN = "pull_request_id"
private static final String AAR_SIZE_TABLE = "AndroidAarSizes"
private static final String SDK_COLUMN = "sdk_id"
private static final String AAR_SIZE_COLUMN = "aar_size"

// This comes in as a String and goes out as a String, so we might as well keep it a String
private final String pullRequestNumber
private final List<Tuple2<Integer, Integer>> sdkAarSizes

AarSizeJsonBuilder(pullRequestNumber) {
this.pullRequestNumber = pullRequestNumber
this.sdkAarSizes = []
}

def addAarSize(sdkId, size) {
sdkAarSizes.add(new Tuple2(sdkId, size))
}

def toJsonString() {
if (sdkAarSizes.isEmpty()) {
throw new IllegalStateException("Empty - No sizes were added")
}

def sizes = sdkAarSizes.collect {
"[$pullRequestNumber, $it.first, $it.second]"
}.join(", ")

def json = """
{
tables: [
{
table_name: "$PULL_REQUEST_TABLE",
column_names: ["$PULL_REQUEST_COLUMN"],
replace_measurements: [[$pullRequestNumber]],
},
{
table_name: "$AAR_SIZE_TABLE",
column_names: ["$PULL_REQUEST_COLUMN", "$SDK_COLUMN", "$AAR_SIZE_COLUMN"],
replace_measurements: [$sizes],
},
],
}
"""

return json
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


package com.google.firebase.gradle.plugins.measurement.aarsize

/** A helper class that generates the human-readable, AAR size measurement table. */
class AarSizeTableBuilder {

private final List<Tuple> sdkAarSizes = []

def addAarSize(projectName, size) {
sdkAarSizes.add(new Tuple(projectName, size))
}

def toTableString() {
if (sdkAarSizes.isEmpty()) {
throw new IllegalStateException("Rempty - No sizes added")
}

def table = "|---------------- AAR Sizes --------------|\n"
table += "|--------- project ---------|-- size in bytes --|\n"

table += sdkAarSizes.collect {
sprintf("|%-33s|%,21d|", it.get(0), it.get(1))
}.join("\n")

return table
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


package com.google.firebase.gradle.plugins.measurement.aarsize

import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction

/**
* Generates size measurements after building the release aar's.
*
* <p>This task can run in two modes. The first mode, enabled when running the task with the
* {@code pull_request} flag set, is a dependency of {@link UploadMeasurementsTask} and generates
* a JSON file with measurement information. The second mode, enabled when running the task without
* flags, outputs a table to standard out with more human-readable information. See the README for
* more details.
*
* <p>This task has two properties, a required ignore SDK map file, as input, and the optional
* report file, as output. The map is used to ignore SDKs that shouldn't be included in the report.
* The report path is where the output should be stored. These properties are not used when the task
* is run in the second, human-friendly mode. However, they are still required to be specified.
*/
public class GenerateMeasurementsTask extends DefaultTask {

/**
* The file for storing the report.
*
* <p>This may be any type recognized by Gradle as a file. The contents, if any, will be
* overwritten by the new report.
*/
@OutputFile
@Optional
File reportFile

@Override
Task configure(Closure closure) {
outputs.upToDateWhen { false }
dependsOn "assemble"
return super.configure(closure)
}

@TaskAction
def generate() {
def subprojects = [:]
project.rootProject.subprojects.collect { Project it ->
def aars = it.fileTree('build') {
include '**/*release.aar'
}
if (aars.size() > 1) {
def msg = "${it.name} produced more than one AAR"
throw new IllegalStateException(msg)
}
def name = it.name
if (it.parent != project.rootProject) {
name = "${it.parent.name}:${it.name}"
}
aars.each { File f ->
subprojects[name] = f.length()
}
}
if (project.hasProperty("pull_request")) {
def pullRequestNumber = project.properties["pull_request"]
generateJson(pullRequestNumber, subprojects)
} else {
generateTable(subprojects)
}
}

private def generateJson(pullRequestNumber, subprojects) {
def builder = new AarSizeJsonBuilder(pullRequestNumber)
subprojects.each { name, aarSize ->
builder.addAarSize(name, aarSize)
}

reportFile.withWriter {
it.write(builder.toJsonString())
}
}

private def generateTable(subprojects) {
def builder = new AarSizeTableBuilder()
subprojects.each { name, aarSize ->
builder.addAarSize(name, aarSize)
}

project.logger.quiet(builder.toTableString())
}
}
8 changes: 8 additions & 0 deletions tools/measurement/apksize/apksize.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

import com.google.firebase.gradle.plugins.measurement.apksize.GenerateMeasurementsTask
import com.google.firebase.gradle.plugins.measurement.aarsize.GenerateMeasurementsTask as GenerateAarMeasurementTask
import com.google.firebase.gradle.plugins.measurement.UploadMeasurementsTask

apply plugin: "com.android.application"
Expand Down Expand Up @@ -42,6 +43,13 @@ task generateApkSizeMeasurements(type: GenerateMeasurementsTask) {
reportFile = file("$buildDir/size-report.json")
}

task generateAarSizeMeasurements(type: GenerateAarMeasurementTask) {
description 'Builds release aar artifacts and calculates AAR sizes.'
group 'Measurements'

dependsOn (":publishAllToBuildDir")
}

/**
* This task uploads the report produced by the generate measurements task to a SQL database.
*
Expand Down
2 changes: 1 addition & 1 deletion tools/measurement/apksize/default.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ android {
defaultConfig {
applicationId 'com.google.apksize'
minSdkVersion project.targetSdkVersion
multiDexEnabled true
multiDexEnabled true
targetSdkVersion project.targetSdkVersion
versionCode 1
versionName '1.0'
Expand Down