/* * 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.distributed; import com.facebook.buck.distributed.thrift.BuildJobStateBuildTarget; import com.facebook.buck.distributed.thrift.BuildJobStateTargetGraph; import com.facebook.buck.distributed.thrift.BuildJobStateTargetNode; import com.facebook.buck.event.SimplePerfEvent; import com.facebook.buck.graph.MutableDirectedGraph; import com.facebook.buck.io.ProjectFilesystem; import com.facebook.buck.model.BuildTarget; import com.facebook.buck.model.Flavor; import com.facebook.buck.model.InternalFlavor; import com.facebook.buck.model.UnflavoredBuildTarget; import com.facebook.buck.parser.ParserTargetNodeFactory; import com.facebook.buck.rules.Cell; import com.facebook.buck.rules.TargetGraph; import com.facebook.buck.rules.TargetGraphAndBuildTargets; import com.facebook.buck.rules.TargetNode; import com.facebook.buck.util.MoreCollectors; import com.facebook.buck.util.ObjectMappers; import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; /** Saves and loads the {@link TargetNode}s needed for the build. */ public class DistBuildTargetGraphCodec { private final ParserTargetNodeFactory<TargetNode<?, ?>> parserTargetNodeFactory; private final Function<? super TargetNode<?, ?>, ? extends Map<String, Object>> nodeToRawNode; private Set<String> topLevelTargets; public DistBuildTargetGraphCodec( ParserTargetNodeFactory<TargetNode<?, ?>> parserTargetNodeFactory, Function<? super TargetNode<?, ?>, ? extends Map<String, Object>> nodeToRawNode, Set<String> topLevelTargets) { this.parserTargetNodeFactory = parserTargetNodeFactory; this.nodeToRawNode = nodeToRawNode; this.topLevelTargets = topLevelTargets; } public BuildJobStateTargetGraph dump( Collection<TargetNode<?, ?>> targetNodes, DistBuildCellIndexer cellIndexer) { BuildJobStateTargetGraph result = new BuildJobStateTargetGraph(); for (TargetNode<?, ?> targetNode : targetNodes) { Map<String, Object> rawTargetNode = nodeToRawNode.apply(targetNode); ProjectFilesystem projectFilesystem = targetNode.getFilesystem(); BuildJobStateTargetNode remoteNode = new BuildJobStateTargetNode(); remoteNode.setCellIndex(cellIndexer.getCellIndex(projectFilesystem.getRootPath())); remoteNode.setBuildTarget(encodeBuildTarget(targetNode.getBuildTarget())); try { remoteNode.setRawNode(ObjectMappers.WRITER.writeValueAsString(rawTargetNode)); } catch (JsonProcessingException e) { throw new RuntimeException(e); } result.addToNodes(remoteNode); } return result; } public static BuildJobStateBuildTarget encodeBuildTarget(BuildTarget buildTarget) { BuildJobStateBuildTarget remoteTarget = new BuildJobStateBuildTarget(); remoteTarget.setShortName(buildTarget.getShortName()); remoteTarget.setBaseName(buildTarget.getBaseName()); if (buildTarget.getCell().isPresent()) { remoteTarget.setCellName(buildTarget.getCell().get()); } remoteTarget.setFlavors( buildTarget.getFlavors().stream().map(Object::toString).collect(Collectors.toSet())); return remoteTarget; } public static BuildTarget decodeBuildTarget(BuildJobStateBuildTarget remoteTarget, Cell cell) { UnflavoredBuildTarget unflavoredBuildTarget = UnflavoredBuildTarget.builder() .setShortName(remoteTarget.getShortName()) .setBaseName(remoteTarget.getBaseName()) .setCellPath(cell.getRoot()) .setCell(Optional.ofNullable(remoteTarget.getCellName())) .build(); ImmutableSet<Flavor> flavors = remoteTarget .flavors .stream() .map(InternalFlavor::of) .collect(MoreCollectors.toImmutableSet()); return BuildTarget.builder() .setUnflavoredBuildTarget(unflavoredBuildTarget) .setFlavors(flavors) .build(); } public TargetGraphAndBuildTargets createTargetGraph( BuildJobStateTargetGraph remoteTargetGraph, Function<Integer, Cell> cellLookup) throws IOException { ImmutableMap.Builder<BuildTarget, TargetNode<?, ?>> targetNodeIndexBuilder = ImmutableMap.builder(); ImmutableSet.Builder<BuildTarget> buildTargetsBuilder = ImmutableSet.builder(); for (BuildJobStateTargetNode remoteNode : remoteTargetGraph.getNodes()) { Cell cell = cellLookup.apply(remoteNode.getCellIndex()); ProjectFilesystem projectFilesystem = cell.getFilesystem(); BuildTarget target = decodeBuildTarget(remoteNode.getBuildTarget(), cell); if (topLevelTargets.contains(target.getFullyQualifiedName())) { buildTargetsBuilder.add(target); } @SuppressWarnings("unchecked") Map<String, Object> rawNode = ObjectMappers.readValue(remoteNode.getRawNode(), Map.class); Path buildFilePath = projectFilesystem.resolve(target.getBasePath()).resolve(cell.getBuildFileName()); TargetNode<?, ?> targetNode = parserTargetNodeFactory.createTargetNode( cell, buildFilePath, target, rawNode, input -> SimplePerfEvent.scope(Optional.empty(), input)); targetNodeIndexBuilder.put(targetNode.getBuildTarget(), targetNode); } ImmutableSet<BuildTarget> buildTargets = buildTargetsBuilder.build(); Preconditions.checkArgument(topLevelTargets.size() == buildTargets.size()); ImmutableMap<BuildTarget, TargetNode<?, ?>> targetNodeIndex = targetNodeIndexBuilder.build(); MutableDirectedGraph<TargetNode<?, ?>> mutableTargetGraph = new MutableDirectedGraph<>(); for (TargetNode<?, ?> targetNode : targetNodeIndex.values()) { mutableTargetGraph.addNode(targetNode); for (BuildTarget dep : targetNode.getParseDeps()) { mutableTargetGraph.addEdge( targetNode, Preconditions.checkNotNull(targetNodeIndex.get(dep))); } } TargetGraph targetGraph = new TargetGraph(mutableTargetGraph, targetNodeIndex); return TargetGraphAndBuildTargets.builder() .setTargetGraph(targetGraph) .addAllBuildTargets(buildTargets) .build(); } }