diff options
Diffstat (limited to 'tools/product_config/src/com/android/build/config/OutputChecker.java')
-rw-r--r-- | tools/product_config/src/com/android/build/config/OutputChecker.java | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/tools/product_config/src/com/android/build/config/OutputChecker.java b/tools/product_config/src/com/android/build/config/OutputChecker.java new file mode 100644 index 0000000000..d982dba7ed --- /dev/null +++ b/tools/product_config/src/com/android/build/config/OutputChecker.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * 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.android.build.config; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Compares the make-based configuration as reported by dumpconfig.mk + * with what was computed from the new tool. + */ +public class OutputChecker { + // Differences that we know about, either know issues to be fixed or intentional. + private static final RegexSet IGNORED_VARIABLES = new RegexSet( + // TODO: Rewrite the enforce packages exist logic into this tool. + "PRODUCT_ENFORCE_PACKAGES_EXIST", + "PRODUCT_ENFORCE_PACKAGES_EXIST_ALLOW_LIST", + "PRODUCTS\\..*\\.PRODUCT_ENFORCE_PACKAGES_EXIST", + "PRODUCTS\\..*\\.PRODUCT_ENFORCE_PACKAGES_EXIST_ALLOW_LIST", + + // This is generated by this tool, but comes later in the make build system. + "INTERNAL_PRODUCT", + + // This can be set temporarily by product_config.mk + ".KATI_ALLOW_RULES" + ); + + private final FlatConfig mConfig; + private final TreeMap<String, Variable> mVariables; + + /** + * Represents the before and after state of a variable. + */ + public static class Variable { + public final String name; + public final VarType type; + public final Str original; + public final Value updated; + + public Variable(String name, VarType type, Str original) { + this(name, type, original, null); + } + + public Variable(String name, VarType type, Str original, Value updated) { + this.name = name; + this.type = type; + this.original = original; + this.updated = updated; + } + + /** + * Return copy of this Variable with the updated field also set. + */ + public Variable addUpdated(Value updated) { + return new Variable(name, type, original, updated); + } + + /** + * Return whether normalizedOriginal and normalizedUpdate are equal. + */ + public boolean isSame() { + final Str normalizedOriginal = Value.normalize(original); + final Str normalizedUpdated = Value.normalize(updated); + if (normalizedOriginal == null && normalizedUpdated == null) { + return true; + } else if (normalizedOriginal != null) { + return normalizedOriginal.equals(normalizedUpdated); + } else { + return false; + } + } + } + + /** + * Construct OutputChecker with the config it will check. + */ + public OutputChecker(FlatConfig config) { + mConfig = config; + mVariables = getVariables(config); + } + + /** + * Add a WARNING_DIFFERENT_FROM_KATI for each of the variables which have changed. + */ + public void reportErrors(Errors errors) { + for (Variable var: getDifferences()) { + if (IGNORED_VARIABLES.matches(var.name)) { + continue; + } + errors.WARNING_DIFFERENT_FROM_KATI.add("product_config processing differs from" + + " kati processing for " + var.type + " variable " + var.name + ".\n" + + "original: " + + Value.oneLinePerWord(var.original, "<null>") + "\n" + + "updated: " + + Value.oneLinePerWord(var.updated, "<null>")); + } + } + + /** + * Get the Variables that are different between the normalized form of the original + * and updated. If one is null and the other is not, even if one is an empty string, + * the values are considered different. + */ + public List<Variable> getDifferences() { + final ArrayList<Variable> result = new ArrayList(); + for (Variable var: mVariables.values()) { + if (!var.isSame()) { + result.add(var); + } + } + return result; + } + + /** + * Get all of the variables for this config. + * + * VisibleForTesting + */ + static TreeMap<String, Variable> getVariables(FlatConfig config) { + final TreeMap<String, Variable> result = new TreeMap(); + + // Add the original values to mAll + for (Map.Entry<String, Str> entry: getModifiedVars(config.getInitialVariables(), + config.getFinalVariables()).entrySet()) { + final String name = entry.getKey(); + result.put(name, new Variable(name, config.getVarType(name), entry.getValue())); + } + + // Add the updated values to mAll + for (Map.Entry<String, Value> entry: config.getValues().entrySet()) { + final String name = entry.getKey(); + final Value value = entry.getValue(); + Variable var = result.get(name); + if (var == null) { + result.put(name, new Variable(name, config.getVarType(name), null, value)); + } else { + result.put(name, var.addUpdated(value)); + } + } + + return result; + } + + /** + * Get the entries that are different in the two maps. + */ + public static Map<String, Str> getModifiedVars(Map<String, Str> before, + Map<String, Str> after) { + final HashMap<String, Str> result = new HashMap(); + + // Entries that were added or changed. + for (Map.Entry<String, Str> afterEntry: after.entrySet()) { + final String varName = afterEntry.getKey(); + final Str afterValue = afterEntry.getValue(); + final Str beforeValue = before.get(varName); + if (beforeValue == null || !beforeValue.equals(afterValue)) { + result.put(varName, afterValue); + } + } + + // removed Entries that were removed, we just treat them as empty string + for (Map.Entry<String, Str> beforeEntry: before.entrySet()) { + final String varName = beforeEntry.getKey(); + if (!after.containsKey(varName)) { + result.put(varName, new Str("")); + } + } + + return result; + } +} |