Skip to content

Instantly share code, notes, and snippets.

@tevjef
Last active October 25, 2022 20:47
Show Gist options
  • Save tevjef/ce1e5d66ff800a43011ac1fc1a72b893 to your computer and use it in GitHub Desktop.
Save tevjef/ce1e5d66ff800a43011ac1fc1a72b893 to your computer and use it in GitHub Desktop.
Strips mappings from proguard file
tasks.register("proguardMapper", ProguardMappingMapperTask::class).configure {
outputFile = project.rootProject.file("app/build/outputs/mapping/release/mapping-striped.txt")
mappingFile = project.rootProject.file("app/build/outputs/mapping/release/mapping.txt")
}
datadog {
mappingFilePath = "${project.buildDir}/outputs/mapping/release/mapping-striped.txt"
}
package com.mycompany.gradle.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import java.io.File
// issue: The proguard mapping file at: [/home/circleci/app/app/build/outputs/mapping/release/mapping.txt] size exceeded the maximum 50 MB size. This task cannot be performed.
// This task aims to remove disallowed mappings from the proguard file.
open class ProguardMappingMapperTask : DefaultTask() {
companion object {
private val allowedPackages = listOf("com.mycompany")
// '#' defines additional metadata to the parser.
// ' ' is a signal that line is the not a class mapping. Usually a class body mapping or a comment.
private val knownNonClassMappingFirstChars = listOf(' ', '#')
/*
stripDisallowedPackages reads a proguard mapping file and writes all allowed proguard mappings to an output file.
Input:
# compiler: R8
# compiler_version: 2.2.66
# min_api: 24
# pg_map_id: 94b8e40
# common_typos_disable
androidx.appcompat.app.ActionBarDrawerToggle$Delegate -> obfuscated.m0$b: # Below shows which if statement is true in forEachLine
android.content.Context getActionBarThemedContext() -> a <-- if !isNonClassMapping
com.mycompany.analytics.ApptimizeTestRunner -> obfuscated.yn7: <-- if isAllowedPackage
# {"id":"sourceFile","fileName":"ApptimizeTestRunner.kt"} <-- if isInAllowedPackageMapping && isNonClassMapping
1:1:void <init>():8:8 -> <init>
1:1:boolean getBooleanOrDefault(java.lang.String,boolean):16:16 -> a
org.socure.core.MatOfDouble -> obfuscated.kuq: <-- if !isNonClassMapping
# {"id":"sourceFile","fileName":"SourceFile"}
1:1:void <init>() -> <init>
Output:
com.mycompany.analytics.ApptimizeTestRunner -> obfuscated.yn7:
# {"id":"sourceFile","fileName":"ApptimizeTestRunner.kt"}
1:1:void <init>():8:8 -> <init>
1:1:boolean getBooleanOrDefault(java.lang.String,boolean):16:16 -> a
*/
private fun stripDisallowedPackages(outputFile: File, mappingFile: File) {
// Create or clear output file.
outputFile.writeText("")
var isInAllowedPackageMapping = false
mappingFile.forEachLine { line ->
val isAllowedPackage = allowedPackages.any { line.startsWith(it) }
val isNonClassMapping = knownNonClassMappingFirstChars.any { it == line.first() }
if (isAllowedPackage) {
isInAllowedPackageMapping = true
outputFile.appendText(line + "\n")
} else if (isInAllowedPackageMapping && isNonClassMapping) {
outputFile.appendText(line + "\n")
} else if (!isNonClassMapping) {
isInAllowedPackageMapping = false
}
}
println("${mappingFile.name}: ${mappingFile.length()} bytes")
println("${outputFile.name}: ${outputFile.length()} bytes")
}
}
@get:OutputFile
@Optional
var outputFile: File? = null
@get:InputFile
@Optional
var mappingFile: File? = null
@TaskAction
fun runTask() {
if (outputFile == null) {
throw GradleException("Output file is null")
}
if (mappingFile == null || !mappingFile!!.isFile) {
throw GradleException("Mapping file is null or missing")
}
stripDisallowedPackages(outputFile!!, mappingFile!!)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment