blob: 1d35932eeac18ef6c85dae42769209f5b317f9b5 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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.google.idea.blaze.base.projectview;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.Lists;
import com.google.idea.blaze.base.io.FileAttributeProvider;
import com.google.idea.blaze.base.model.primitives.WorkspacePath;
import com.google.idea.blaze.base.projectview.ProjectViewSet.ProjectViewFile;
import com.google.idea.blaze.base.projectview.section.ListSection;
import com.google.idea.blaze.base.projectview.section.SectionParser;
import com.google.idea.blaze.base.projectview.section.sections.DirectoryEntry;
import com.google.idea.blaze.base.projectview.section.sections.DirectorySection;
import com.google.idea.blaze.base.projectview.section.sections.Sections;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.scope.output.IssueOutput;
import com.google.idea.blaze.base.sync.BlazeSyncPlugin;
import com.google.idea.blaze.base.sync.projectview.LanguageSupport;
import com.google.idea.blaze.base.sync.projectview.WorkspaceLanguageSettings;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import java.io.File;
import java.util.List;
import javax.annotation.Nullable;
/** Verifies project views. */
public class ProjectViewVerifier {
private static class MissingDirectoryIssueData extends IssueOutput.IssueData {
public final WorkspacePath workspacePath;
public MissingDirectoryIssueData(WorkspacePath workspacePath) {
this.workspacePath = workspacePath;
}
}
/** Verifies the project view. Any errors are output to the context as issues. */
public static boolean verifyProjectView(
@Nullable Project project,
BlazeContext context,
WorkspacePathResolver workspacePathResolver,
ProjectViewSet projectViewSet,
WorkspaceLanguageSettings workspaceLanguageSettings) {
if (!verifyIncludedPackagesAreNotExcluded(context, projectViewSet)) {
return false;
}
for (BlazeSyncPlugin syncPlugin : BlazeSyncPlugin.EP_NAME.getExtensions()) {
if (!syncPlugin.validateProjectView(
project, context, projectViewSet, workspaceLanguageSettings)) {
return false;
}
}
if (!LanguageSupport.validateLanguageSettings(context, workspaceLanguageSettings)) {
return false;
}
warnAboutDeprecatedSections(context, projectViewSet);
if (!verifyIncludedPackagesExistOnDisk(context, workspacePathResolver, projectViewSet)) {
return false;
}
return true;
}
private static void warnAboutDeprecatedSections(
BlazeContext context, ProjectViewSet projectViewSet) {
List<SectionParser> deprecatedParsers =
Sections.getParsers().stream().filter(SectionParser::isDeprecated).collect(toList());
for (SectionParser sectionParser : deprecatedParsers) {
for (ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
ProjectView projectView = projectViewFile.projectView;
if (projectView
.getSections()
.stream()
.anyMatch(section -> section.isSectionType(sectionParser.getSectionKey()))) {
String deprecationMessage = sectionParser.getDeprecationMessage();
if (deprecationMessage == null) {
deprecationMessage = String.format("%s is deprecated", sectionParser.getName());
}
IssueOutput.warn(deprecationMessage)
.inFile(projectViewFile.projectViewFile)
.submit(context);
}
}
}
}
private static boolean verifyIncludedPackagesAreNotExcluded(
BlazeContext context, ProjectViewSet projectViewSet) {
boolean ok = true;
List<WorkspacePath> includedDirectories =
projectViewSet
.listItems(DirectorySection.KEY)
.stream()
.filter(entry -> entry.included)
.map(entry -> entry.directory)
.collect(toList());
for (WorkspacePath includedDirectory : includedDirectories) {
for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
List<DirectoryEntry> directoryEntries = Lists.newArrayList();
for (ListSection<DirectoryEntry> section :
projectViewFile.projectView.getSectionsOfType(DirectorySection.KEY)) {
directoryEntries.addAll(section.items());
}
for (DirectoryEntry entry : directoryEntries) {
if (entry.included) {
continue;
}
WorkspacePath excludedDirectory = entry.directory;
if (FileUtil.isAncestor(
excludedDirectory.relativePath(), includedDirectory.relativePath(), false)) {
IssueOutput.error(
String.format(
"%s is included, but that contradicts %s which was excluded",
includedDirectory.toString(), excludedDirectory.toString()))
.inFile(projectViewFile.projectViewFile)
.submit(context);
ok = false;
}
}
}
}
return ok;
}
private static boolean verifyIncludedPackagesExistOnDisk(
BlazeContext context,
WorkspacePathResolver workspacePathResolver,
ProjectViewSet projectViewSet) {
boolean ok = true;
FileAttributeProvider fileAttributeProvider = FileAttributeProvider.getInstance();
for (ProjectViewSet.ProjectViewFile projectViewFile : projectViewSet.getProjectViewFiles()) {
List<DirectoryEntry> directoryEntries = Lists.newArrayList();
for (ListSection<DirectoryEntry> section :
projectViewFile.projectView.getSectionsOfType(DirectorySection.KEY)) {
directoryEntries.addAll(section.items());
}
for (DirectoryEntry entry : directoryEntries) {
if (!entry.included) {
continue;
}
WorkspacePath workspacePath = entry.directory;
File file = workspacePathResolver.resolveToFile(workspacePath);
if (!fileAttributeProvider.exists(file)) {
IssueOutput.error(
String.format(
"Directory '%s' specified in project view not found.", workspacePath))
.inFile(projectViewFile.projectViewFile)
.withData(new MissingDirectoryIssueData(workspacePath))
.submit(context);
ok = false;
} else if (!fileAttributeProvider.isDirectory(file)) {
IssueOutput.error(
String.format(
"Directory '%s' specified in project view is a file.", workspacePath))
.inFile(projectViewFile.projectViewFile)
.withData(new MissingDirectoryIssueData(workspacePath))
.submit(context);
ok = false;
}
}
}
return ok;
}
}