blob: 03686cb1935dbd62bcf85893eca0104fc563a7d5 [file] [log] [blame]
/*
* 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;
}
}