Skip to content

Commit

Permalink
Ensure that the sentry debug properties are added to final APK
Browse files Browse the repository at this point in the history
To ensure that the asset file is added it needs to be available before
the proguard task runs. So instead of relying on the CLI to generate the
UUID there is now a separate task that creates it and --uuid is used in
the CLI to match the mappings to the build.

This fixes getsentry#37
  • Loading branch information
ansman committed Feb 12, 2021
1 parent daa52e8 commit 6509b12
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 82 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ repositories {
}

compileGroovy {
sourceCompatibility = '1.6'
targetCompatibility = '1.6'
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.sentry.android.gradle;

import org.gradle.api.DefaultTask;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFile;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.UUID;

abstract class GenerateSentryProguardUuidTask extends DefaultTask {
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();

@Internal
public Provider<UUID> getOutputUuid() {
return getOutputUuidInternal();
}

@Internal
protected abstract Property<UUID> getOutputUuidInternal();

@Internal
private final Provider<RegularFile> outputFile = getOutputDirectory().map(dir -> dir.file("sentry-debug-meta.properties"));

public GenerateSentryProguardUuidTask() {
getOutputs().upToDateWhen(spec -> false);
setDescription("Generates a unique build ID");
}

@Internal
public Provider<RegularFile> getOutputFile() {
return outputFile;
}

@TaskAction
protected void generateProperties() throws IOException {
UUID uuid = UUID.randomUUID();
getOutputUuidInternal().set(uuid);

try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile.get().getAsFile())))) {
writer.write("io.sentry.ProguardUuids=");
writer.write(uuid.toString());
}
}
}
117 changes: 37 additions & 80 deletions src/main/groovy/io/sentry/android/gradle/SentryPlugin.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.android.gradle

import com.android.Version
import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin
import com.android.build.gradle.api.ApplicationVariant
Expand All @@ -9,6 +10,7 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.Exec
import org.gradle.util.VersionNumber

class SentryPlugin implements Plugin<Project> {
static final String GROUP_NAME = 'Sentry'
Expand Down Expand Up @@ -184,39 +186,6 @@ class SentryPlugin implements Plugin<Project> {
return project.tasks.findByName("bundle${variant.name.capitalize()}")
}

/**
* Returns the path to the debug meta properties file for the given variant.
*
* @param project
* @param variant
* @return
*/
static String getDebugMetaPropPath(Project project, ApplicationVariant variant) {
try {
return variant.mergeAssetsProvider.get().outputDir.get().file("sentry-debug-meta.properties").getAsFile().path
} catch (Exception ignored) {
project.logger.error("getDebugMetaPropPath 1: ${ignored.getMessage()}")
}

try {
return variant.mergeAssets.outputDir.get().file("sentry-debug-meta.properties").getAsFile().path
} catch (Exception ignored) {
project.logger.error("getDebugMetaPropPath 2: ${ignored.getMessage()}")
}

try {
return "${variant.mergeAssets.outputDir.get().asFile.path}/sentry-debug-meta.properties"
} catch (Exception ignored) {
project.logger.error("getDebugMetaPropPath 3: ${ignored.getMessage()}")
}

try {
return "${variant.mergeAssets.outputDir}/sentry-debug-meta.properties"
} catch (Exception ignored) {
project.logger.error("getDebugMetaPropPath 4: ${ignored.getMessage()}")
}
}

void apply(Project project) {
SentryPluginExtension extension = project.extensions.create("sentry", SentryPluginExtension)

Expand Down Expand Up @@ -274,60 +243,48 @@ class SentryPlugin implements Plugin<Project> {

def cli = getSentryCli(project)

def persistIdsTaskName = "persistSentryProguardUuidsFor${variant.name.capitalize()}${variantOutput.name.capitalize()}"
// create a task that persists our proguard uuid as android asset
def persistIdsTask = project.tasks.create(
name: persistIdsTaskName,
type: Exec) {
description "Write references to proguard UUIDs to the android assets."
workingDir project.rootDir

def propsFile = getPropsString(project, variant)
def generateUuidTask = project.tasks.create(
name: "generateSentryProguardUuid${variant.name.capitalize()}${variantOutput.name.capitalize()}",
type: GenerateSentryProguardUuidTask) {
outputDirectory.set(project.file("build/generated/assets/sentry/${variant.name}"))

if (propsFile != null) {
environment("SENTRY_PROPERTIES", propsFile)
} else {
project.logger.info("propsFile is null")
doFirst {
project.logger.info("debugMetaPropPath: ${getOutputFile().get()}")
}
}

def debugMetaPropPath = getDebugMetaPropPath(project, variant)
project.logger.info("debugMetaPropPath: ${debugMetaPropPath}")

def args = [
cli,
"upload-proguard",
"--write-properties",
debugMetaPropPath,
mappingFile
]

if (!extension.autoUpload) {
args << "--no-upload"
if (VersionNumber.parse(Version.ANDROID_GRADLE_PLUGIN_VERSION) >= new VersionNumber(3, 3, 0, null)) {
variant.mergeAssetsProvider.configure {
dependsOn(generateUuidTask)
}
} else {
//noinspection GrDeprecatedAPIUsage
variant.mergeAssets.dependsOn(generateUuidTask)
}

// create a task that persists our proguard uuid as android asset
def uploadSentryProguardMappingsTask = project.tasks.create(
name: "uploadSentryProguardMappings${variant.name.capitalize()}${variantOutput.name.capitalize()}",
type: SentryUploadProguardMappingsTask) {
dependsOn(generateUuidTask)
workingDir project.rootDir
getCliExecutable().set(cli)
getSentryProperties().set(project.file(getPropsString(project, variant)))
mappingsUuid.set(generateUuidTask.outputUuid)
getMappingsFile().set(mappingFile)
getAutoUpload().set(extension.autoUpload)
def buildTypeProperties = variant.buildType.ext
if (buildTypeProperties.has(SENTRY_ORG_PARAMETER)) {
args.add("--org")
args.add(buildTypeProperties.get(SENTRY_ORG_PARAMETER).toString())
getSentryOrganization().set(buildTypeProperties.get(SENTRY_ORG_PARAMETER).toString())
}
if (buildTypeProperties.has(SENTRY_PROJECT_PARAMETER)) {
args.add("--project")
args.add(buildTypeProperties.get(SENTRY_PROJECT_PARAMETER).toString())
}

project.logger.info("cli args: ${args.toString()}")

if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine("cmd", "/c", *args)
} else {
commandLine(*args)
getSentryProject().set(buildTypeProperties.get(SENTRY_PROJECT_PARAMETER).toString())
}

project.logger.info("args executed.")

enabled true
}

variant.register(uploadSentryProguardMappingsTask)
project.android.sourceSets[variant.name].assets.srcDir(generateUuidTask.outputDirectory)

// create and hooks the uploading of native symbols task after the assembling task
def variantOutputName = "${variant.name.capitalize()}${variantOutput.name.capitalize()}"
def uploadNativeSymbolsTaskName = "uploadNativeSymbolsFor${variantOutputName}"
Expand Down Expand Up @@ -389,16 +346,16 @@ class SentryPlugin implements Plugin<Project> {
// we set ourselves as dependency, otherwise we just hack outselves into
// the proguard task's doLast.
if (dexTask != null) {
dexTask.dependsOn persistIdsTask
dexTask.dependsOn uploadSentryProguardMappingsTask
}

if (transformerTask != null) {
transformerTask.finalizedBy persistIdsTask
transformerTask.finalizedBy uploadSentryProguardMappingsTask
}

// To include proguard uuid file into aab, run before bundle task.
if (preBundleTask != null) {
preBundleTask.dependsOn persistIdsTask
preBundleTask.dependsOn uploadSentryProguardMappingsTask
}

// find the package task
Expand All @@ -409,9 +366,9 @@ class SentryPlugin implements Plugin<Project> {
project.logger.info("packageTask is null")
}

// the package task will only be executed if the persistIdsTask has already been executed.
// the package task will only be executed if the uploadSentryProguardMappingsTask has already been executed.
if (packageTask != null) {
packageTask.dependsOn persistIdsTask
packageTask.dependsOn uploadSentryProguardMappingsTask
}

// find the assemble task
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package io.sentry.android.gradle;

import org.apache.tools.ant.taskdefs.condition.Os;
import org.gradle.api.file.RegularFile;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Exec;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Optional;

import java.util.ArrayList;
import java.util.UUID;

abstract class SentryUploadProguardMappingsTask extends Exec {
@Input
public abstract Property<String> getCliExecutable();

@Input
public abstract Property<UUID> getMappingsUuid();

@InputFile
public abstract RegularFileProperty getMappingsFile();

@Optional
@InputFile
public abstract RegularFileProperty getSentryProperties();

@Optional
@Input
public abstract Property<String> getSentryOrganization();

@Optional
@Input
public abstract Property<String> getSentryProject();

@Input
public abstract Property<Boolean> getAutoUpload();

public SentryUploadProguardMappingsTask() {
setDescription("Uploads the proguard mappings file");
}

@Override
protected void exec() {
RegularFile sentryProperties = getSentryProperties().getOrNull();
if (sentryProperties != null) {
environment("SENTRY_PROPERTIES", sentryProperties);
} else {
getLogger().info("propsFile is null");
}

ArrayList<Object> args = new ArrayList<>();

args.add(getCliExecutable().get());
args.add("upload-proguard");
args.add("--uuid");
args.add(getMappingsUuid().get());
args.add(getMappingsFile().get());

if (!getAutoUpload().get()) {
args.add("--no-upload");
}

String org = getSentryOrganization().getOrNull();
if (org != null) {
args.add("--org");
args.add(org);
}

String project = getSentryProject().getOrNull();
if (project != null) {
args.add("--project");
args.add(project);
}

if (Os.isFamily(Os.FAMILY_WINDOWS)) {
args.add(0, "cmd");
args.add(1, "/c");
}
commandLine(args);

getLogger().info("cli args: " + getArgs());

super.exec();
}
}

0 comments on commit 6509b12

Please sign in to comment.