com.facebook.buck.ide.intellij.BaseIjModuleRule.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.ide.intellij.BaseIjModuleRule.java

Source

/*
 * Copyright 2015-present Facebook, Inc.
 *
 * 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.facebook.buck.ide.intellij;

import com.facebook.buck.ide.intellij.aggregation.AggregationContext;
import com.facebook.buck.ide.intellij.model.DependencyType;
import com.facebook.buck.ide.intellij.model.IjModule;
import com.facebook.buck.ide.intellij.model.IjModuleFactoryResolver;
import com.facebook.buck.ide.intellij.model.IjModuleRule;
import com.facebook.buck.ide.intellij.model.IjProjectConfig;
import com.facebook.buck.ide.intellij.model.folders.IJFolderFactory;
import com.facebook.buck.ide.intellij.model.folders.SourceFolder;
import com.facebook.buck.ide.intellij.model.folders.TestFolder;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.jvm.java.JvmLibraryArg;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargets;
import com.facebook.buck.rules.CommonDescriptionArg;
import com.facebook.buck.rules.TargetNode;
import com.facebook.buck.util.MoreCollectors;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public abstract class BaseIjModuleRule<T extends CommonDescriptionArg> implements IjModuleRule<T> {

    protected final ProjectFilesystem projectFilesystem;
    protected final IjModuleFactoryResolver moduleFactoryResolver;
    protected final IjProjectConfig projectConfig;

    protected BaseIjModuleRule(ProjectFilesystem projectFilesystem, IjModuleFactoryResolver moduleFactoryResolver,
            IjProjectConfig projectConfig) {
        this.projectFilesystem = projectFilesystem;
        this.moduleFactoryResolver = moduleFactoryResolver;
        this.projectConfig = projectConfig;
    }

    /**
     * Calculate the set of directories containing inputs to the target.
     *
     * @param paths inputs to a given target.
     * @return index of path to set of inputs in that path
     */
    protected static ImmutableMultimap<Path, Path> getSourceFoldersToInputsIndex(ImmutableSet<Path> paths) {
        Path defaultParent = Paths.get("");
        return paths.stream().collect(MoreCollectors.toImmutableMultimap(path -> {
            Path parent = path.getParent();
            return parent == null ? defaultParent : parent;
        }, path -> path));
    }

    /**
     * Add the set of input paths to the {@link IjModule.Builder} as source folders.
     *
     * @param foldersToInputsIndex mapping of source folders to their inputs.
     * @param wantsPackagePrefix whether folders should be annotated with a package prefix. This only
     *     makes sense when the source folder is Java source code.
     * @param context the module to add the folders to.
     */
    protected void addSourceFolders(IJFolderFactory factory, ImmutableMultimap<Path, Path> foldersToInputsIndex,
            boolean wantsPackagePrefix, ModuleBuildContext context) {
        for (Map.Entry<Path, Collection<Path>> entry : foldersToInputsIndex.asMap().entrySet()) {
            context.addSourceFolder(factory.create(entry.getKey(), wantsPackagePrefix,
                    ImmutableSortedSet.copyOf(Ordering.natural(), entry.getValue())));
        }
    }

    private void addDepsAndFolder(IJFolderFactory folderFactory, DependencyType dependencyType,
            TargetNode<T, ?> targetNode, boolean wantsPackagePrefix, ModuleBuildContext context) {
        ImmutableMultimap<Path, Path> foldersToInputsIndex = getSourceFoldersToInputsIndex(targetNode.getInputs());
        addSourceFolders(folderFactory, foldersToInputsIndex, wantsPackagePrefix, context);
        addDeps(foldersToInputsIndex, targetNode, dependencyType, context);

        addGeneratedOutputIfNeeded(folderFactory, targetNode, context);

        if (targetNode.getConstructorArg() instanceof JvmLibraryArg) {
            addAnnotationOutputIfNeeded(folderFactory, targetNode, context);
        }
    }

    protected void addDepsAndSources(TargetNode<T, ?> targetNode, boolean wantsPackagePrefix,
            ModuleBuildContext context) {
        addDepsAndFolder(SourceFolder.FACTORY, DependencyType.PROD, targetNode, wantsPackagePrefix, context);
    }

    protected void addDepsAndTestSources(TargetNode<T, ?> targetNode, boolean wantsPackagePrefix,
            ModuleBuildContext context) {
        addDepsAndFolder(TestFolder.FACTORY, DependencyType.TEST, targetNode, wantsPackagePrefix, context);
    }

    private void addDeps(ImmutableMultimap<Path, Path> foldersToInputsIndex, TargetNode<T, ?> targetNode,
            DependencyType dependencyType, ModuleBuildContext context) {
        context.addDeps(foldersToInputsIndex.keySet(), targetNode.getBuildDeps(), dependencyType);
    }

    @SuppressWarnings("unchecked")
    private void addAnnotationOutputIfNeeded(IJFolderFactory folderFactory, TargetNode<T, ?> targetNode,
            ModuleBuildContext context) {
        TargetNode<? extends JvmLibraryArg, ?> jvmLibraryTargetNode = (TargetNode<? extends JvmLibraryArg, ?>) targetNode;

        Optional<Path> annotationOutput = moduleFactoryResolver.getAnnotationOutputPath(jvmLibraryTargetNode);
        if (!annotationOutput.isPresent()) {
            return;
        }

        Path annotationOutputPath = annotationOutput.get();
        context.addGeneratedSourceCodeFolder(
                folderFactory.create(annotationOutputPath, false, ImmutableSortedSet.of(annotationOutputPath)));
    }

    private void addGeneratedOutputIfNeeded(IJFolderFactory folderFactory, TargetNode<T, ?> targetNode,
            ModuleBuildContext context) {

        ImmutableSet<Path> generatedSourcePaths = findConfiguredGeneratedSourcePaths(targetNode);

        for (Path generatedSourcePath : generatedSourcePaths) {
            context.addGeneratedSourceCodeFolder(
                    folderFactory.create(generatedSourcePath, false, ImmutableSortedSet.of(generatedSourcePath)));
        }
    }

    private ImmutableSet<Path> findConfiguredGeneratedSourcePaths(TargetNode<T, ?> targetNode) {
        ImmutableSet.Builder<Path> generatedSourcePaths = ImmutableSet.builder();

        generatedSourcePaths.addAll(findConfiguredGeneratedSourcePathsUsingDeps(targetNode));
        generatedSourcePaths.addAll(findConfiguredGeneratedSourcePathsUsingLabels(targetNode));

        return generatedSourcePaths.build();
    }

    private Set<Path> findConfiguredGeneratedSourcePathsUsingDeps(TargetNode<T, ?> targetNode) {
        ImmutableMap<String, String> depToGeneratedSourcesMap = projectConfig.getDepToGeneratedSourcesMap();
        BuildTarget buildTarget = targetNode.getBuildTarget();

        Set<Path> generatedSourcePaths = new HashSet<>();

        for (BuildTarget dependencyTarget : targetNode.getBuildDeps()) {
            String buildTargetName = dependencyTarget.toString();
            String generatedSourceWithPattern = depToGeneratedSourcesMap.get(buildTargetName);
            if (generatedSourceWithPattern != null) {
                String generatedSource = generatedSourceWithPattern.replaceAll("%name%",
                        buildTarget.getShortNameAndFlavorPostfix());
                Path generatedSourcePath = BuildTargets.getGenPath(projectFilesystem, buildTarget, generatedSource);

                generatedSourcePaths.add(generatedSourcePath);
            }
        }

        return generatedSourcePaths;
    }

    private ImmutableSet<Path> findConfiguredGeneratedSourcePathsUsingLabels(TargetNode<T, ?> targetNode) {
        BuildTarget buildTarget = targetNode.getBuildTarget();
        ImmutableMap<String, String> labelToGeneratedSourcesMap = projectConfig.getLabelToGeneratedSourcesMap();

        return targetNode.getConstructorArg().getLabels().stream().map(labelToGeneratedSourcesMap::get)
                .filter(Objects::nonNull)
                .map(pattern -> pattern.replaceAll("%name%", buildTarget.getShortNameAndFlavorPostfix()))
                .map(path -> BuildTargets.getGenPath(projectFilesystem, buildTarget, path))
                .collect(MoreCollectors.toImmutableSet());
    }

    @Override
    public void applyDuringAggregation(AggregationContext context, TargetNode<T, ?> targetNode) {
        context.setModuleType(detectModuleType(targetNode));
    }
}