/*
* 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 me.tatarka.androidunittest.idea;
import com.android.tools.idea.gradle.customizer.ModuleCustomizer;
import com.google.common.collect.Lists;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.java.JavaSourceRootProperties;
import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import java.io.File;
import java.util.Collection;
import java.util.List;
/**
* This is a modified version from Android Studio that doesn't remove the current source roots.
* @param <T>
*/
public abstract class AbstractContentRootModuleCustomizer<T> implements ModuleCustomizer<T> {
private static final Logger LOG = Logger.getInstance(AbstractContentRootModuleCustomizer.class);
@Override
public void customizeModule(@NotNull Module module, @NotNull Project project, @Nullable T model) {
if (model == null) {
return;
}
ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
ModifiableRootModel rootModel = moduleRootManager.getModifiableModel();
try {
Collection<ContentEntry> contentEntries = findOrCreateContentEntries(rootModel, model);
List<RootSourceFolder> orphans = Lists.newArrayList();
setUpContentEntries(contentEntries, model, orphans);
for (RootSourceFolder orphan : orphans) {
File path = orphan.getPath();
ContentEntry contentEntry = rootModel.addContentEntry(FilePaths.pathToIdeaUrl(path));
addSourceFolder(contentEntry, path, orphan.getType(), orphan.isGenerated());
}
}
finally {
rootModel.commit();
}
}
@NotNull
protected abstract Collection<ContentEntry> findOrCreateContentEntries(@NotNull ModifiableRootModel rootModel, @NotNull T model);
protected abstract void setUpContentEntries(@NotNull Collection<ContentEntry> contentEntries,
@NotNull T model,
@NotNull List<RootSourceFolder> orphans);
protected void addSourceFolder(@NotNull Collection<ContentEntry> contentEntries,
@NotNull File folderPath,
@NotNull JpsModuleSourceRootType type,
boolean generated,
@NotNull List<RootSourceFolder> orphans) {
ContentEntry parent = findParentContentEntry(contentEntries, folderPath);
if (parent == null) {
orphans.add(new RootSourceFolder(folderPath, type, generated));
return;
}
addSourceFolder(parent, folderPath, type, generated);
}
private static void addSourceFolder(@NotNull ContentEntry contentEntry,
@NotNull File folderPath,
@NotNull JpsModuleSourceRootType type,
boolean generated) {
String url = FilePaths.pathToIdeaUrl(folderPath);
SourceFolder sourceFolder = contentEntry.addSourceFolder(url, type);
if (generated) {
JpsModuleSourceRoot sourceRoot = sourceFolder.getJpsElement();
JpsElement properties = sourceRoot.getProperties();
if (properties instanceof JavaSourceRootProperties) {
((JavaSourceRootProperties)properties).setForGeneratedSources(true);
}
}
}
protected boolean addExcludedFolder(@NotNull ContentEntry contentEntry, @NotNull File dirPath) {
if (!FilePaths.isPathInContentEntry(dirPath, contentEntry)) {
return false;
}
contentEntry.addExcludeFolder(FilePaths.pathToIdeaUrl(dirPath));
return true;
}
protected void setCompilerOutputPath(@NotNull ModifiableRootModel model, @NotNull File folderPath, boolean test) {
CompilerModuleExtension extension = model.getModuleExtension(CompilerModuleExtension.class);
extension.inheritCompilerOutputPath(false);
String url = FilePaths.pathToIdeaUrl(folderPath);
if (test) {
extension.setCompilerOutputPathForTests(url);
}
else {
extension.setCompilerOutputPath(url);
}
}
@Nullable
protected ContentEntry findParentContentEntry(@NotNull Collection<ContentEntry> contentEntries, @NotNull File dirPath) {
for (ContentEntry contentEntry : contentEntries) {
if (FilePaths.isPathInContentEntry(dirPath, contentEntry)) {
return contentEntry;
}
}
LOG.info(String.format("Failed to find content entry for file '%1$s'", dirPath.getPath()));
return null;
}
protected static class RootSourceFolder {
@NotNull private final File myPath;
@NotNull private final JpsModuleSourceRootType myType;
private final boolean myGenerated;
protected RootSourceFolder(@NotNull File path, @NotNull JpsModuleSourceRootType type, boolean generated) {
myPath = path;
myType = type;
myGenerated = generated;
}
@NotNull
protected File getPath() {
return myPath;
}
@NotNull
protected JpsModuleSourceRootType getType() {
return myType;
}
protected boolean isGenerated() {
return myGenerated;
}
}
}