| /* |
| * Copyright (C) 2015 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.gradle.internal.pipeline; |
| |
| import com.android.annotations.NonNull; |
| import com.android.annotations.Nullable; |
| import com.android.annotations.concurrency.Immutable; |
| import com.android.build.api.transform.DirectoryInput; |
| import com.android.build.api.transform.JarInput; |
| import com.android.build.api.transform.QualifiedContent; |
| import com.android.build.api.transform.QualifiedContent.ContentType; |
| import com.android.build.api.transform.QualifiedContent.Scope; |
| import com.android.build.api.transform.TransformInput; |
| import com.android.build.api.transform.TransformOutputProvider; |
| import com.google.common.collect.Iterables; |
| import java.util.Set; |
| import org.gradle.api.Project; |
| import org.gradle.api.file.FileCollection; |
| import org.gradle.api.file.FileTree; |
| import org.gradle.api.tasks.util.PatternSet; |
| |
| /** |
| * Representation of a stream for internal usage of the {@link TransformManager} to wire up |
| * the different Transforms. |
| * |
| * Transforms read from and write into TransformStreams, via a custom view of them: |
| * {@link TransformInput}, and {@link TransformOutputProvider}. |
| * |
| * This contains information about the content via {@link QualifiedContent}, dependencies, and the |
| * actual file information. |
| * |
| * The dependencies is what triggers the creation of the files and any Transform (task) consuming |
| * the files must be made to depend on these objects. |
| */ |
| @Immutable |
| public abstract class TransformStream { |
| |
| // FIXME These objects are no immutable.... |
| private static final PatternSet INCLUDE_CLASSES = |
| new PatternSet() |
| .include("**/*.class") |
| .include("**/*.jar") |
| .include("META-INF/*.kotlin_module"); |
| private static final PatternSet EXCLUDE_CLASSES = new PatternSet().exclude("**/*.class"); |
| private static final PatternSet INCLUDE_SO = |
| new PatternSet().include("**/*.so").include("**/*.jar"); |
| private static final PatternSet INCLUDE_DEX = |
| new PatternSet().include("**/*.dex").include("**/*.jar"); |
| private static final PatternSet INCLUDE_DATABINDING_BIN = new PatternSet(); |
| |
| @NonNull private final String name; |
| @NonNull private final Set<ContentType> contentTypes; |
| @NonNull private final Set<? super Scope> scopes; |
| @NonNull private final FileCollection fileCollection; |
| |
| /** |
| * Creates the stream |
| * |
| * @param name the name of the string. This is used only for debugging purpose in order to more |
| * easily identify streams when debugging transforms. There is no restrictions on what the |
| * name can be. |
| * @param contentTypes the content type(s) of the stream |
| * @param scopes the scope(s) of the stream |
| * @param fileCollection the file collection that makes up the content of the stream |
| */ |
| protected TransformStream( |
| @NonNull String name, |
| @NonNull Set<ContentType> contentTypes, |
| @NonNull Set<? super Scope> scopes, |
| @NonNull FileCollection fileCollection) { |
| this.name = name; |
| this.contentTypes = contentTypes; |
| this.scopes = scopes; |
| this.fileCollection = fileCollection; |
| } |
| |
| @NonNull |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * Returns the type of content that the stream represents. |
| * |
| * <p> |
| * It's never null nor empty, but can contain several types. |
| */ |
| @NonNull |
| public Set<ContentType> getContentTypes() { |
| return contentTypes; |
| } |
| |
| /** |
| * Returns the scope of the stream. |
| * |
| * <p> |
| * It's never null nor empty, but can contain several scopes. |
| */ |
| @NonNull |
| public Set<? super Scope> getScopes() { |
| return scopes; |
| } |
| |
| /** Returns the stream content as a FileCollection. */ |
| @NonNull |
| public FileCollection getFileCollection() { |
| return fileCollection; |
| } |
| |
| /** |
| * Returns the content of the stream as a file tree. |
| * |
| * <p>This is filtered based on {@link #getContentTypes()} so that this can be used as task |
| * inputs. |
| * |
| * @return the file tree. |
| */ |
| @NonNull |
| public FileTree getAsFileTree() { |
| final FileTree fileTree = fileCollection.getAsFileTree(); |
| |
| PatternSet pattern = getPatternSet(); |
| if (pattern != null) { |
| return fileTree.matching(pattern); |
| } |
| |
| return fileTree; |
| } |
| |
| @Nullable |
| private PatternSet getPatternSet() { |
| if (contentTypes.size() == 1) { |
| return getSingleTypePatternSet(Iterables.getOnlyElement(contentTypes)); |
| } |
| |
| // else, create a new PatternSet and try to set some valid include/exclude. |
| // It's hard because some items cannot be easily match with just includes. |
| if (contentTypes.size() == 2 |
| && contentTypes.contains(ExtendedContentType.NATIVE_LIBS) |
| && contentTypes.contains(QualifiedContent.DefaultContentType.RESOURCES)) { |
| // only res and native so, use an exclude on classes. |
| return EXCLUDE_CLASSES; |
| } |
| |
| // TODO more cases? |
| |
| return null; |
| } |
| |
| @NonNull |
| private static PatternSet getSingleTypePatternSet(@NonNull ContentType type) { |
| if (type instanceof QualifiedContent.DefaultContentType) { |
| switch ((QualifiedContent.DefaultContentType) type) { |
| case CLASSES: |
| return INCLUDE_CLASSES; |
| case RESOURCES: |
| // Can't make an include but since we really care about excluding class |
| // files, use an exclude pattern |
| return EXCLUDE_CLASSES; |
| default: |
| throw new RuntimeException("Unsupported DefaultContentType value: " + type); |
| } |
| |
| } else if (type instanceof ExtendedContentType) { |
| switch ((ExtendedContentType) type) { |
| case DEX: |
| case DEX_ARCHIVE: |
| return INCLUDE_DEX; |
| case NATIVE_LIBS: |
| return INCLUDE_SO; |
| case CLASSES_ENHANCED: |
| return INCLUDE_CLASSES; |
| case DATA_BINDING: |
| return INCLUDE_DATABINDING_BIN; |
| default: |
| throw new RuntimeException("Unsupported ExtendedContentType value: " + type); |
| } |
| } |
| |
| throw new RuntimeException( |
| "Unsupported ContentType implementation: " + type.getClass().getCanonicalName()); |
| } |
| |
| /** |
| * Returns the transform input for this stream. |
| * |
| * <p>All the {@link JarInput} and {@link DirectoryInput} will be in non-incremental mode. |
| * |
| * @return the transform input. |
| */ |
| @NonNull |
| abstract TransformInput asNonIncrementalInput(); |
| |
| /** |
| * Returns a list of QualifiedContent for the jars and one for the folders. |
| * |
| */ |
| @NonNull |
| abstract IncrementalTransformInput asIncrementalInput(); |
| |
| @NonNull |
| abstract TransformStream makeRestrictedCopy( |
| @NonNull Set<ContentType> types, |
| @NonNull Set<? super Scope> scopes); |
| |
| /** |
| * Returns a FileCollection that contains the outputs. |
| * |
| * The type/scope of the output is filtered by a StreamFilter. |
| * |
| * @param project a Projet object to create new FileCollection |
| * @param streamFilter the stream filter. |
| * |
| * @return the FileCollection |
| */ |
| @NonNull |
| FileCollection getOutputFileCollection( |
| @NonNull Project project, |
| @NonNull StreamFilter streamFilter) { |
| return fileCollection; |
| } |
| } |