All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.android.manifmerger.PlaceholderHandler Maven / Gradle / Ivy

There is a newer version: 25.3.0
Show newest version
/*
 * Copyright (C) 2014 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.manifmerger;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Replaces all placeholders of the form ${name} with a tool invocation provided value
 */
public class PlaceholderHandler {

    // interesting placeholders names that are documented to be automatically provided.
    public static final String INSTRUMENTATION_RUNNER = "instrumentationRunner";
    public static final String PACKAGE_NAME = "packageName";
    public static final String APPLICATION_ID = "applicationId";

    // regular expression to recognize placeholders like ${name}, potentially surrounded by a
    // prefix and suffix string. this will split in 3 groups, the prefix, the placeholder name, and
    // the suffix.
    private static final Pattern PATTERN = Pattern.compile("([^\\$]*)\\$\\{([^\\}]*)\\}(.*)");

    /**
     * Interface to provide a value for a placeholder key.
     * @param  the key type
     */
    public interface KeyBasedValueResolver {

        /**
         * Returns a placeholder value for the placeholder key or null if none exists.
         */
        @Nullable
        String getValue(@NonNull T key);
    }

    /**
     * Returns true if the passed string is a placeholder value, false otherwise.
     */
    public static boolean isPlaceHolder(@NonNull String string) {
        return PATTERN.matcher(string).matches();
    }

    /**
     * Visits a document's entire tree and check each attribute for a placeholder existence.
     * If one is found, delegate to the provided {@link KeyBasedValueResolver} to provide a value
     * for the placeholder.
     * 

* If no value is provided, an error will be generated. * * @param xmlDocument the xml document to visit * @param valueProvider the placeholder value provider. * @param mergingReportBuilder to report errors and log actions. */ public void visit( @NonNull ManifestMerger2.MergeType mergeType, @NonNull XmlDocument xmlDocument, @NonNull KeyBasedValueResolver valueProvider, @NonNull MergingReport.Builder mergingReportBuilder) { visit(mergeType, xmlDocument.getRootNode(), valueProvider, mergingReportBuilder); } private void visit( @NonNull ManifestMerger2.MergeType mergeType, @NonNull XmlElement xmlElement, @NonNull KeyBasedValueResolver valueProvider, @NonNull MergingReport.Builder mergingReportBuilder) { for (XmlAttribute xmlAttribute : xmlElement.getAttributes()) { Matcher matcher = PATTERN.matcher(xmlAttribute.getValue()); if (matcher.matches()) { String placeholderValue = valueProvider.getValue(matcher.group(2)); if (placeholderValue == null) { // if this is a library, ignore the failure MergingReport.Record.Severity severity = mergeType == ManifestMerger2.MergeType.LIBRARY ? MergingReport.Record.Severity.INFO : MergingReport.Record.Severity.ERROR; xmlAttribute.addMessage(mergingReportBuilder, severity, String.format( "Attribute %1$s at %2$s requires a placeholder substitution" + " but no value for <%3$s> is provided.", xmlAttribute.getId(), xmlAttribute.printPosition(), matcher.group(2) )); } else { // record the attribute set mergingReportBuilder.getActionRecorder().recordAttributeAction( xmlAttribute, PositionImpl.UNKNOWN, Actions.ActionType.INJECTED, null /* attributeOperationType */); String attrValue = matcher.group(1) + placeholderValue + matcher.group(3); xmlAttribute.getXml().setValue(attrValue); } } } for (XmlElement childElement : xmlElement.getMergeableElements()) { visit(mergeType, childElement, valueProvider, mergingReportBuilder); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy