Java tutorial
/* * Copyright 2014-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.features.python; import com.facebook.buck.core.exceptions.HumanReadableException; import com.facebook.buck.core.model.BuildTarget; import com.facebook.buck.core.rulekey.AddToRuleKey; import com.facebook.buck.core.rulekey.AddsToRuleKey; import com.facebook.buck.core.rules.BuildRule; import com.facebook.buck.core.rules.SourcePathRuleFinder; import com.facebook.buck.core.sourcepath.SourcePath; import com.facebook.buck.core.util.immutables.BuckStyleImmutable; import com.facebook.buck.cxx.toolchain.CxxPlatform; import com.facebook.buck.util.MoreMaps; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.ImmutableSortedMap; import com.google.common.collect.Multimap; import com.google.common.collect.SetMultimap; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import org.immutables.value.Value; @Value.Immutable(builder = false, singleton = true) @BuckStyleImmutable abstract class AbstractPythonPackageComponents implements AddsToRuleKey { // Python modules as map of their module name to location of the source. @Value.Parameter @Value.NaturalOrder public abstract ImmutableSortedMap<Path, SourcePath> getModules(); @AddToRuleKey public final ImmutableSortedMap<String, SourcePath> getModulesRuleKey() { return MoreMaps.transformKeysAndSort(getModules(), Path::toString); } // Resources to include in the package. @Value.Parameter @Value.NaturalOrder public abstract ImmutableSortedMap<Path, SourcePath> getResources(); @AddToRuleKey public final ImmutableSortedMap<String, SourcePath> getResourcesRuleKey() { return MoreMaps.transformKeysAndSort(getResources(), Path::toString); } // Native libraries to include in the package. @Value.Parameter @Value.NaturalOrder public abstract ImmutableSortedMap<Path, SourcePath> getNativeLibraries(); @AddToRuleKey public final ImmutableSortedMap<String, SourcePath> getNativeLibrariesRuleKey() { return MoreMaps.transformKeysAndSort(getNativeLibraries(), Path::toString); } // Directories that pre-built python libraries are extracted to. Note that these // can refer to the same libraries that are in getPrebuiltLibraries, but these are // directories instead of archives. The key of this map is where to link the contents // of the directory within the archive relative to its root @Value.Parameter public abstract ImmutableMultimap<Path, SourcePath> getModuleDirs(); @Value.Parameter public abstract Optional<Boolean> isZipSafe(); /** @return whether there are any native libraries included in these components. */ public boolean hasNativeCode(CxxPlatform cxxPlatform) { for (Path module : getModules().keySet()) { if (module.toString().endsWith(cxxPlatform.getSharedLibraryExtension())) { return true; } } return false; } public ImmutableCollection<BuildRule> getDeps(SourcePathRuleFinder ruleFinder) { ImmutableList.Builder<BuildRule> deps = ImmutableList.builder(); deps.addAll(ruleFinder.filterBuildRuleInputs(getModules().values())); deps.addAll(ruleFinder.filterBuildRuleInputs(getResources().values())); deps.addAll(ruleFinder.filterBuildRuleInputs(getNativeLibraries().values())); deps.addAll(ruleFinder.filterBuildRuleInputs(getModuleDirs().values())); return deps.build(); } /** * A helper class to construct a PythonPackageComponents instance which throws human readable * error messages on duplicates. */ public static class Builder { // A description of the entity that is building this PythonPackageComponents instance. private final BuildTarget owner; // The actual maps holding the components. private final Map<Path, SourcePath> modules = new HashMap<>(); private final Map<Path, SourcePath> resources = new HashMap<>(); private final Map<Path, SourcePath> nativeLibraries = new HashMap<>(); private final SetMultimap<Path, SourcePath> moduleDirs = HashMultimap.create(); private Optional<Boolean> zipSafe = Optional.empty(); // Bookkeeping used to for error handling in the presence of duplicate // entries. These data structures map the components named above to the // entities that provided them. private final Map<Path, BuildTarget> moduleSources = new HashMap<>(); private final Map<Path, BuildTarget> resourceSources = new HashMap<>(); private final Map<Path, BuildTarget> nativeLibrarySources = new HashMap<>(); public Builder(BuildTarget owner) { this.owner = owner; } private HumanReadableException createDuplicateError(String type, Path destination, BuildTarget sourceA, BuildTarget sourceB) { return new HumanReadableException( "%s: found duplicate entries for %s %s when creating python package (%s and %s)", owner, type, destination, sourceA, sourceB); } private Builder add(String type, Map<Path, SourcePath> builder, Map<Path, BuildTarget> sourceDescs, Path destination, SourcePath source, BuildTarget sourceDesc) { SourcePath existing = builder.put(destination, source); if (existing != null && !existing.equals(source)) { throw createDuplicateError(type, destination, sourceDesc, Objects.requireNonNull(sourceDescs.get(destination))); } sourceDescs.put(destination, sourceDesc); return this; } private Builder add(String type, Map<Path, SourcePath> builder, Map<Path, BuildTarget> sourceDescs, Map<Path, SourcePath> toAdd, BuildTarget sourceDesc) { for (Map.Entry<Path, SourcePath> ent : toAdd.entrySet()) { add(type, builder, sourceDescs, ent.getKey(), ent.getValue(), sourceDesc); } return this; } public Builder addModule(Path destination, SourcePath source, BuildTarget from) { return add("module", modules, moduleSources, destination, source, from); } public Builder addModules(Map<Path, SourcePath> sources, BuildTarget from) { return add("module", modules, moduleSources, sources, from); } public Builder addResources(Map<Path, SourcePath> sources, BuildTarget from) { return add("resource", resources, resourceSources, sources, from); } public Builder addNativeLibraries(Path destination, SourcePath source, BuildTarget from) { return add("native library", nativeLibraries, nativeLibrarySources, destination, source, from); } public Builder addNativeLibraries(Map<Path, SourcePath> sources, BuildTarget from) { return add("native library", nativeLibraries, nativeLibrarySources, sources, from); } public Builder addModuleDirs(Multimap<Path, SourcePath> moduleDirs) { this.moduleDirs.putAll(moduleDirs); return this; } public Builder addComponent(PythonPackageComponents other, BuildTarget from) { addModules(other.getModules(), from); addResources(other.getResources(), from); addNativeLibraries(other.getNativeLibraries(), from); addModuleDirs(other.getModuleDirs()); addZipSafe(other.isZipSafe()); return this; } public Builder addZipSafe(Optional<Boolean> zipSafe) { if (!this.zipSafe.isPresent() && !zipSafe.isPresent()) { return this; } this.zipSafe = Optional.of(this.zipSafe.orElse(true) && zipSafe.orElse(true)); return this; } public PythonPackageComponents build() { return PythonPackageComponents.of(ImmutableSortedMap.copyOf(modules), ImmutableSortedMap.copyOf(resources), ImmutableSortedMap.copyOf(nativeLibraries), ImmutableSetMultimap.copyOf(moduleDirs), zipSafe); } } }