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

com.android.manifmerger.MergingReport 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.VisibleForTesting;
import com.android.annotations.concurrency.Immutable;
import com.android.ide.common.blame.SourceFile;
import com.android.ide.common.blame.SourceFilePosition;
import com.android.ide.common.blame.SourcePosition;
import com.android.utils.ILogger;
import com.google.common.base.CaseFormat;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;

/**
 * Contains the result of 2 files merging.
 *
 * TODO: more work necessary, this is pretty raw as it stands.
 */
@Immutable
public class MergingReport {

    private final Optional mMergedDocument;
    private final Result mResult;
    // list of logging events, ordered by their recording time.
    private final ImmutableList mRecords;
    private final ImmutableList mIntermediaryStages;
    private final Actions mActions;

    private MergingReport(Optional mergedDocument,
            @NonNull Result result,
            @NonNull ImmutableList records,
            @NonNull ImmutableList intermediaryStages,
            @NonNull Actions actions) {
        mMergedDocument = mergedDocument;
        mResult = result;
        mRecords = records;
        mIntermediaryStages = intermediaryStages;
        mActions = actions;
    }

    /**
     * dumps all logging records to a logger.
     */
    public void log(ILogger logger) {
        for (Record record : mRecords) {
            switch(record.mSeverity) {
                case WARNING:
                    logger.warning(record.toString());
                    break;
                case ERROR:
                    logger.error(null /* throwable */, record.toString());
                    break;
                case INFO:
                    logger.verbose(record.toString());
                    break;
                default:
                    logger.error(null /* throwable */, "Unhandled record type " + record.mSeverity);
            }
        }
        mActions.log(logger);
    }

    /**
     * Return the resulting merged document.
     */
    public Optional getMergedDocument() {
        return mMergedDocument;
    }

    /**
     * Returns all the merging intermediary stages if
     * {@link com.android.manifmerger.ManifestMerger2.Invoker.Feature#KEEP_INTERMEDIARY_STAGES}
     * is set.
     */
    public ImmutableList getIntermediaryStages() {
        return mIntermediaryStages;
    }

    /**
     * Overall result of the merging process.
     */
    public enum Result {
        SUCCESS,

        WARNING,

        ERROR;

        public boolean isSuccess() {
            return this == SUCCESS || this == WARNING;
        }

        public boolean isWarning() {
            return this == WARNING;
        }

        public boolean isError() {
            return this == ERROR;
        }
    }

    @NonNull
    public Result getResult() {
        return mResult;
    }

    @NonNull
    public ImmutableList getLoggingRecords() {
        return mRecords;
    }

    @NonNull
    public Actions getActions() {
        return mActions;
    }

    @NonNull
    public String getReportString() {
        switch (mResult) {
            case SUCCESS:
                return "Manifest merger executed successfully";
            case WARNING:
                return mRecords.size() > 1
                        ? "Manifest merger exited with warnings, see logs"
                        : "Manifest merger warning : " + mRecords.get(0).mLog;
            case ERROR:
                return mRecords.size() > 1
                        ? "Manifest merger failed with multiple errors, see logs"
                        : "Manifest merger failed : " + mRecords.get(0).mLog;
            default:
                return "Manifest merger returned an invalid result " + mResult;
        }
    }

    /**
     * Log record. This is used to give users some information about what is happening and
     * what might have gone wrong.
     */
    public static class Record {


        public enum Severity {WARNING, ERROR, INFO }

        private final Severity mSeverity;
        private final String mLog;
        private final SourceFilePosition mSourceLocation;

        private Record(
                @NonNull SourceFilePosition sourceLocation,
                @NonNull Severity severity,
                @NonNull String mLog) {
            this.mSourceLocation = sourceLocation;
            this.mSeverity = severity;
            this.mLog = mLog;
        }

        public Severity getSeverity() {
            return mSeverity;
        }

        public String getMessage() {
            return mLog;
        }

        @Override
        public String toString() {
            return mSourceLocation.toString() // needs short string.
                    + " "
                    + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, mSeverity.toString())
                    + ":\n\t"
                    + mLog;
        }
    }

    /**
     * This builder is used to accumulate logging, action recording and intermediary results as
     * well as final result of the merging activity.
     *
     * Once the merging is finished, the {@link #build()} is called to return an immutable version
     * of itself with all the logging, action recordings and xml files obtainable.
     *
     */
    static class Builder {

        private Optional mMergedDocument = Optional.absent();
        private ImmutableList.Builder mRecordBuilder = new ImmutableList.Builder();
        private ImmutableList.Builder mIntermediaryStages = new ImmutableList.Builder();
        private boolean mHasWarnings = false;
        private boolean mHasErrors = false;
        private ActionRecorder mActionRecorder = new ActionRecorder();
        private final ILogger mLogger;

        Builder(ILogger logger) {
            mLogger = logger;
        }


        Builder setMergedDocument(@NonNull XmlDocument mergedDocument) {
            mMergedDocument = Optional.of(mergedDocument);
            return this;
        }

        @VisibleForTesting
        Builder addMessage(@NonNull SourceFile sourceFile,
                int line,
                int column,
                @NonNull Record.Severity severity,
                @NonNull String message) {
            // The line and column used are 1-based, but SourcePosition uses zero-based.
            return addMessage(
                    new SourceFilePosition(sourceFile, new SourcePosition(line - 1, column -1, -1)),
                    severity,
                    message);
        }

        Builder addMessage(@NonNull SourceFile sourceFile,
                @NonNull Record.Severity severity,
                @NonNull String message) {
            return addMessage(
                    new SourceFilePosition(sourceFile, SourcePosition.UNKNOWN),
                    severity,
                    message);
        }

        Builder addMessage(@NonNull SourceFilePosition sourceFilePosition,
                    @NonNull Record.Severity severity,
                    @NonNull String message) {
            switch (severity) {
                case ERROR:
                    mHasErrors = true;
                    break;
                case WARNING:
                    mHasWarnings = true;
                    break;
            }
            mRecordBuilder.add(new Record(sourceFilePosition,  severity, message));
            return this;
        }

        Builder addMergingStage(String xml) {
            mIntermediaryStages.add(xml);
            return this;
        }

        /**
         * Returns true if some fatal errors were reported.
         */
        boolean hasErrors() {
            return mHasErrors;
        }

        ActionRecorder getActionRecorder() {
            return mActionRecorder;
        }

        MergingReport build() {
            Result result = mHasErrors
                    ? Result.ERROR
                    : mHasWarnings
                            ? Result.WARNING
                            : Result.SUCCESS;

            return new MergingReport(
                    mMergedDocument,
                    result,
                    mRecordBuilder.build(),
                    mIntermediaryStages.build(),
                    mActionRecorder.build());
        }

        public ILogger getLogger() {
            return mLogger;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy