1/* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.tools.build.jetifier.core.config 18 19import com.android.tools.build.jetifier.core.PackageMap 20import com.android.tools.build.jetifier.core.pom.DependencyVersionsMap 21import com.android.tools.build.jetifier.core.pom.PomRewriteRule 22import com.android.tools.build.jetifier.core.proguard.ProGuardType 23import com.android.tools.build.jetifier.core.proguard.ProGuardTypesMap 24import com.android.tools.build.jetifier.core.rule.RewriteRule 25import com.android.tools.build.jetifier.core.rule.RewriteRulesMap 26import com.android.tools.build.jetifier.core.type.JavaType 27import com.android.tools.build.jetifier.core.type.PackageName 28import com.android.tools.build.jetifier.core.type.TypesMap 29import com.google.gson.annotations.SerializedName 30import java.util.regex.Pattern 31 32/** 33 * The main and only one configuration that is used by the tool and all its transformers. 34 * 35 * @param restrictToPackagePrefixes Package prefixes that limit the scope of the rewriting. In most 36 * cases the rules have priority over this. We use this mainly to determine if we are actually 37 * missing a rule in case we fail to rewrite. 38 * @param reversedRestrictToPackagePrefixes Same as [restrictToPackagePrefixes] but used when 39 * running in reversed mode. 40 * @param rulesMap Rules to scan support libraries to generate [TypesMap] 41 * @param slRule List of rules used when rewriting the support library itself in the reversed mode 42 * to ignore packages that don't need rewriting anymore. 43 * @param pomRewriteRules Rules to rewrite POM files 44 * @param typesMap Map of all java types and fields to be used to rewrite libraries. 45 * @param proGuardMap Proguard types map to be used for ProGuard files rewriting. 46 * @param versionsMap Pre-defined maps of versions to be substituted in pom dependency rules. 47 * @param packageMap Package map to be used to rewrite packages, used only during the support 48 * library rewrite. 49 */ 50data class Config( 51 val restrictToPackagePrefixes: Set<String>, 52 val reversedRestrictToPackagePrefixes: Set<String>, 53 val rulesMap: RewriteRulesMap, 54 val slRules: List<RewriteRule>, 55 val pomRewriteRules: Set<PomRewriteRule>, 56 val typesMap: TypesMap, 57 val proGuardMap: ProGuardTypesMap, 58 val versionsMap: DependencyVersionsMap, 59 val packageMap: PackageMap = PackageMap(PackageMap.DEFAULT_RULES) 60) { 61 62 init { 63 // Verify pom rules 64 val testSet = mutableSetOf<String>() 65 pomRewriteRules.forEach { 66 val raw = "${it.from.groupId}:${it.from.artifactId}" 67 if (!testSet.add(raw)) { 68 throw IllegalArgumentException("Artifact '$raw' is defined twice in pom rules!") 69 } 70 } 71 } 72 73 // Merges all packages prefixes into one regEx pattern 74 private val packagePrefixPattern = Pattern.compile( 75 "^(" + restrictToPackagePrefixes.map { "($it)" }.joinToString("|") + ").*$") 76 77 val restrictToPackagePrefixesWithDots: List<String> = restrictToPackagePrefixes 78 .map { it.replace("/", ".") } 79 80 companion object { 81 /** Path to the default config file located within the jar file. */ 82 const val DEFAULT_CONFIG_RES_PATH = "/default.generated.config" 83 84 val EMPTY = fromOptional() 85 86 fun fromOptional( 87 restrictToPackagePrefixes: Set<String> = emptySet(), 88 reversedRestrictToPackagesPrefixes: Set<String> = emptySet(), 89 rulesMap: RewriteRulesMap = RewriteRulesMap.EMPTY, 90 slRules: List<RewriteRule> = emptyList(), 91 pomRewriteRules: Set<PomRewriteRule> = emptySet(), 92 typesMap: TypesMap = TypesMap.EMPTY, 93 proGuardMap: ProGuardTypesMap = ProGuardTypesMap.EMPTY, 94 versionsMap: DependencyVersionsMap = DependencyVersionsMap.EMPTY, 95 packageMap: PackageMap = PackageMap.EMPTY 96 ): Config { 97 return Config( 98 restrictToPackagePrefixes = restrictToPackagePrefixes, 99 reversedRestrictToPackagePrefixes = reversedRestrictToPackagesPrefixes, 100 rulesMap = rulesMap, 101 slRules = slRules, 102 pomRewriteRules = pomRewriteRules, 103 typesMap = typesMap, 104 proGuardMap = proGuardMap, 105 versionsMap = versionsMap, 106 packageMap = packageMap 107 ) 108 } 109 } 110 111 fun setNewMap(mappings: TypesMap): Config { 112 return Config( 113 restrictToPackagePrefixes = restrictToPackagePrefixes, 114 reversedRestrictToPackagePrefixes = reversedRestrictToPackagePrefixes, 115 rulesMap = rulesMap, 116 slRules = slRules, 117 pomRewriteRules = pomRewriteRules, 118 typesMap = mappings, 119 proGuardMap = proGuardMap, 120 versionsMap = versionsMap, 121 packageMap = packageMap 122 ) 123 } 124 125 /** 126 * Returns whether the given type is eligible for rewrite. 127 * 128 * If not, the transformers should ignore it. 129 */ 130 fun isEligibleForRewrite(type: JavaType): Boolean { 131 if (!isEligibleForRewriteInternal(type.fullName)) { 132 return false 133 } 134 135 val isIgnored = rulesMap.runtimeIgnoreRules 136 .any { it.apply(type) == RewriteRule.TypeRewriteResult.IGNORED } 137 return !isIgnored 138 } 139 140 /** 141 * Returns whether the given ProGuard type reference is eligible for rewrite. 142 * 143 * Keep in mind that his has limited capabilities - mainly when * is used as a prefix. Rules 144 * like *.v7 are not matched by prefix support.v7. So don't rely on it and use 145 * the [ProGuardTypesMap] as first. 146 */ 147 fun isEligibleForRewrite(type: ProGuardType): Boolean { 148 if (!isEligibleForRewriteInternal(type.value)) { 149 return false 150 } 151 152 val isIgnored = rulesMap.runtimeIgnoreRules.any { it.doesThisIgnoreProGuard(type) } 153 return !isIgnored 154 } 155 156 fun isEligibleForRewrite(type: PackageName): Boolean { 157 if (!isEligibleForRewriteInternal(type.fullName + "/")) { 158 return false 159 } 160 161 val javaType = JavaType(type.fullName + "/") 162 val isIgnored = rulesMap.runtimeIgnoreRules 163 .any { it.apply(javaType) == RewriteRule.TypeRewriteResult.IGNORED } 164 return !isIgnored 165 } 166 167 private fun isEligibleForRewriteInternal(type: String): Boolean { 168 if (restrictToPackagePrefixes.isEmpty()) { 169 return false 170 } 171 return packagePrefixPattern.matcher(type).matches() 172 } 173 174 /** Returns JSON data model of this class */ 175 fun toJson(): JsonData { 176 return JsonData( 177 restrictToPackagePrefixes.toList(), 178 reversedRestrictToPackagePrefixes.toList(), 179 rulesMap.toJson().rules.toList(), 180 slRules.map { it.toJson() }.toList(), 181 pomRewriteRules.map { it.toJson() }.toList(), 182 versionsMap.data, 183 typesMap.toJson(), 184 proGuardMap.toJson() 185 ) 186 } 187 188 /** 189 * JSON data model for [Config]. 190 */ 191 data class JsonData( 192 @SerializedName("restrictToPackagePrefixes") 193 val restrictToPackages: List<String?>, 194 195 @SerializedName("reversedRestrictToPackagePrefixes") 196 val reversedRestrictToPackages: List<String?>, 197 198 @SerializedName("rules") 199 val rules: List<RewriteRule.JsonData?>?, 200 201 @SerializedName("slRules") 202 val slRules: List<RewriteRule.JsonData?>?, 203 204 @SerializedName("pomRules") 205 val pomRules: List<PomRewriteRule.JsonData?>, 206 207 @SerializedName("versions") 208 val versions: Map<String, Map<String, String>>? = null, 209 210 @SerializedName("map") 211 val mappings: TypesMap.JsonData? = null, 212 213 @SerializedName("proGuardMap") 214 val proGuardMap: ProGuardTypesMap.JsonData? = null 215 ) { 216 /** Creates instance of [Config] */ 217 fun toConfig(): Config { 218 return Config( 219 restrictToPackagePrefixes = restrictToPackages.filterNotNull().toSet(), 220 reversedRestrictToPackagePrefixes = reversedRestrictToPackages 221 .filterNotNull().toSet(), 222 rulesMap = rules 223 ?.let { RewriteRulesMap(it.filterNotNull().map { it.toRule() }.toList()) } 224 ?: RewriteRulesMap.EMPTY, 225 slRules = slRules 226 ?.let { it.filterNotNull().map { it.toRule() }.toList() } 227 ?: emptyList(), 228 pomRewriteRules = pomRules.filterNotNull().map { it.toRule() }.toSet(), 229 versionsMap = versions 230 ?.let { DependencyVersionsMap(versions) } 231 ?: DependencyVersionsMap.EMPTY, 232 typesMap = mappings?.toMappings() ?: TypesMap.EMPTY, 233 proGuardMap = proGuardMap?.toMappings() ?: ProGuardTypesMap.EMPTY 234 ) 235 } 236 } 237} 238