aboutsummaryrefslogtreecommitdiff
path: root/tools/product_config/src/com/android/build/config/OutputChecker.java
blob: d982dba7edb27a1a3d2b236ca386d04269792492 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
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;
    }
}