com.facebook.buck.parser.ConvertingPipeline.java Source code

Java tutorial

Introduction

Here is the source code for com.facebook.buck.parser.ConvertingPipeline.java

Source

/*
 * Copyright 2016-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.parser;

import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.BuildTargetException;
import com.facebook.buck.parser.PipelineNodeCache.Cache;
import com.facebook.buck.rules.Cell;
import com.facebook.buck.util.HumanReadableException;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;

import java.nio.file.Path;
import java.util.List;

/**
 * Base class for a parse pipeline that converts data one item at a time.
 * @param <F> Type to convert from (raw nodes, for example)
 * @param <T> Type to convert to (TargetNode, for example)
 */
public abstract class ConvertingPipeline<F, T> extends ParsePipeline<T> {
    private final PipelineNodeCache<BuildTarget, T> cache;
    protected final ListeningExecutorService executorService;

    public ConvertingPipeline(ListeningExecutorService executorService, Cache<BuildTarget, T> cache) {
        this.cache = new PipelineNodeCache<>(cache);
        this.executorService = executorService;
    }

    @Override
    public ListenableFuture<ImmutableSet<T>> getAllNodesJob(final Cell cell, final Path buildFile)
            throws BuildTargetException {
        // TODO(csarbora): this hits the chained pipeline before hitting the cache
        ListenableFuture<List<T>> allNodesListJob = Futures.transformAsync(getItemsToConvert(cell, buildFile),
                allToConvert -> {
                    if (shuttingDown()) {
                        return Futures.immediateCancelledFuture();
                    }

                    ImmutableList.Builder<ListenableFuture<T>> allNodeJobs = ImmutableList.builder();

                    for (final F from : allToConvert) {
                        if (isValid(from)) {
                            final BuildTarget target = getBuildTarget(cell.getRoot(), buildFile, from);
                            allNodeJobs.add(cache.getJobWithCacheLookup(cell, target, () -> {
                                if (shuttingDown()) {
                                    return Futures.immediateCancelledFuture();
                                }
                                return dispatchComputeNode(cell, target, from);
                            }));
                        }
                    }

                    return Futures.allAsList(allNodeJobs.build());
                }, executorService);
        return Futures.transform(allNodesListJob, (Function<List<T>, ImmutableSet<T>>) ImmutableSet::copyOf,
                executorService);
    }

    @Override
    public ListenableFuture<T> getNodeJob(final Cell cell, final BuildTarget buildTarget)
            throws BuildTargetException {
        return cache.getJobWithCacheLookup(cell, buildTarget,
                () -> Futures.transformAsync(getItemToConvert(cell, buildTarget),
                        from -> dispatchComputeNode(cell, buildTarget, from)));
    }

    protected boolean isValid(F from) {
        return from != null;
    }

    protected abstract BuildTarget getBuildTarget(Path root, Path buildFile, F from);

    protected abstract T computeNode(Cell cell, BuildTarget buildTarget, F rawNode) throws BuildTargetException;

    protected abstract ListenableFuture<ImmutableSet<F>> getItemsToConvert(Cell cell, Path buildFile)
            throws BuildTargetException;

    protected abstract ListenableFuture<F> getItemToConvert(Cell cell, BuildTarget buildTarget)
            throws BuildTargetException;

    private ListenableFuture<T> dispatchComputeNode(Cell cell, BuildTarget buildTarget, F from)
            throws BuildTargetException {
        // TODO(csarbora): would be nice to have the first half of this function pulled up into base
        if (shuttingDown()) {
            return Futures.immediateCancelledFuture();
        }

        if (!isValid(from)) {
            throw new NoSuchBuildTargetException(buildTarget);
        }

        Path pathToCheck = buildTarget.getBasePath();
        if (cell.getFilesystem().isIgnored(pathToCheck)) {
            throw new HumanReadableException(
                    "Content of '%s' cannot be built because" + " it is defined in an ignored directory.",
                    pathToCheck);
        }

        return Futures.immediateFuture(computeNode(cell, buildTarget, from));
    }

}