// Copyright 2016 Pants project contributors (see CONTRIBUTORS.md). // Licensed under the Apache License, Version 2.0 (see LICENSE). package com.twitter.intellij.pants.index; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.util.indexing.DataIndexer; import com.intellij.util.indexing.FileBasedIndex; import com.intellij.util.indexing.FileContent; import com.intellij.util.indexing.ID; import com.intellij.util.indexing.ScalarIndexExtension; import com.intellij.util.io.EnumeratorStringDescriptor; import com.intellij.util.io.KeyDescriptor; import com.twitter.intellij.pants.util.PantsUtil; import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; public class PantsBuildFileIndex extends ScalarIndexExtension<String> { public static final ID<String, Void> NAME = ID.create("PantsBuildFileIndex"); public static Collection<String> getFiles(@NotNull PsiFile file) { Optional<VirtualFile> root = PantsUtil.findBuildRoot(file); // We need to make sure that the files really belong to the project. // As stated in http://www.jetbrains.org/intellij/sdk/docs/basics/indexing_and_psi_stubs/file_based_indexes.html#accessing-a-file-based-index // it "may also contain additional keys not currently found in the project." return root .map(r -> FileBasedIndex.getInstance().getAllKeys(NAME, file.getProject()).stream() .filter(key -> { String absolutePath = r.getPath() + File.separatorChar + key + File.separatorChar + "BUILD"; return r.getFileSystem().findFileByPath(absolutePath) != null; })) .orElse(Stream.empty()) .collect(Collectors.toList()); } @NotNull @Override public ID<String, Void> getName() { return NAME; } @NotNull @Override public DataIndexer<String, Void, FileContent> getIndexer() { return indexer; } @NotNull @Override public KeyDescriptor<String> getKeyDescriptor() { return new EnumeratorStringDescriptor(); } @NotNull @Override public FileBasedIndex.InputFilter getInputFilter() { return new FileBasedIndex.InputFilter() { @Override public boolean acceptInput(@NotNull VirtualFile file) { return PantsUtil.isBUILDFileName(file.getName()); } }; } @Override public boolean dependsOnFileContent() { return true; } @Override public int getVersion() { return 0; } private static DataIndexer<String, Void, FileContent> indexer = new DataIndexer<String, Void, FileContent>() { @Override @NotNull public Map<String, Void> map(@NotNull final FileContent inputData) { if (!PantsUtil.isPantsProject(inputData.getProject())) { return Collections.emptyMap(); } final VirtualFile file = inputData.getFile(); Optional<VirtualFile> buildRoot = PantsUtil.findBuildRoot(file); if (!buildRoot.isPresent()) { return Collections.emptyMap(); } String relative = FileUtil.getRelativePath(buildRoot.get().getPath(), file.getParent().getPath(), File.separatorChar); if (relative == null || relative.isEmpty()) { return Collections.emptyMap(); } else { return Collections.singletonMap(relative, null); } } }; }