/*
* Copyright 2013-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.python;
import com.facebook.buck.cxx.CxxPlatform;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.model.Flavor;
import com.facebook.buck.model.FlavorConvertible;
import com.facebook.buck.model.FlavorDomain;
import com.facebook.buck.model.InternalFlavor;
import com.facebook.buck.parser.NoSuchBuildTargetException;
import com.facebook.buck.rules.BuildRuleParams;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.CellPathResolver;
import com.facebook.buck.rules.CommonDescriptionArg;
import com.facebook.buck.rules.Description;
import com.facebook.buck.rules.HasDeclaredDeps;
import com.facebook.buck.rules.HasTests;
import com.facebook.buck.rules.MetadataProvidingDescription;
import com.facebook.buck.rules.SourcePathResolver;
import com.facebook.buck.rules.SourcePathRuleFinder;
import com.facebook.buck.rules.TargetGraph;
import com.facebook.buck.rules.coercer.PatternMatchedCollection;
import com.facebook.buck.rules.coercer.SourceList;
import com.facebook.buck.rules.coercer.VersionMatchedCollection;
import com.facebook.buck.util.immutables.BuckStyleImmutable;
import com.facebook.buck.versions.Version;
import com.facebook.buck.versions.VersionPropagator;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import org.immutables.value.Value;
public class PythonLibraryDescription
implements Description<PythonLibraryDescriptionArg>,
VersionPropagator<PythonLibraryDescriptionArg>,
MetadataProvidingDescription<PythonLibraryDescriptionArg> {
private final FlavorDomain<PythonPlatform> pythonPlatforms;
private final FlavorDomain<CxxPlatform> cxxPlatforms;
private static final FlavorDomain<MetadataType> METADATA_TYPE =
FlavorDomain.from("Python Metadata Type", MetadataType.class);
public PythonLibraryDescription(
FlavorDomain<PythonPlatform> pythonPlatforms, FlavorDomain<CxxPlatform> cxxPlatforms) {
this.pythonPlatforms = pythonPlatforms;
this.cxxPlatforms = cxxPlatforms;
}
@Override
public Class<PythonLibraryDescriptionArg> getConstructorArgType() {
return PythonLibraryDescriptionArg.class;
}
@Override
public PythonLibrary createBuildRule(
TargetGraph targetGraph,
BuildRuleParams params,
BuildRuleResolver resolver,
CellPathResolver cellRoots,
PythonLibraryDescriptionArg args) {
return new PythonLibrary(params, resolver);
}
@Override
public <U> Optional<U> createMetadata(
BuildTarget buildTarget,
BuildRuleResolver resolver,
PythonLibraryDescriptionArg args,
Optional<ImmutableMap<BuildTarget, Version>> selectedVersions,
Class<U> metadataClass)
throws NoSuchBuildTargetException {
Optional<Map.Entry<Flavor, MetadataType>> optionalType =
METADATA_TYPE.getFlavorAndValue(buildTarget);
if (!optionalType.isPresent()) {
return Optional.empty();
}
Map.Entry<Flavor, MetadataType> type = optionalType.get();
BuildTarget baseTarget = buildTarget.withoutFlavors(type.getKey());
switch (type.getValue()) {
case PACKAGE_COMPONENTS:
{
Map.Entry<Flavor, PythonPlatform> pythonPlatform =
pythonPlatforms
.getFlavorAndValue(baseTarget)
.orElseThrow(IllegalArgumentException::new);
Map.Entry<Flavor, CxxPlatform> cxxPlatform =
cxxPlatforms.getFlavorAndValue(baseTarget).orElseThrow(IllegalArgumentException::new);
baseTarget = buildTarget.withoutFlavors(pythonPlatform.getKey(), cxxPlatform.getKey());
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);
SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder);
Path baseModule = PythonUtil.getBasePath(baseTarget, args.getBaseModule());
PythonPackageComponents components =
PythonPackageComponents.of(
PythonUtil.getModules(
baseTarget,
resolver,
ruleFinder,
pathResolver,
pythonPlatform.getValue(),
cxxPlatform.getValue(),
"srcs",
baseModule,
args.getSrcs(),
args.getPlatformSrcs(),
args.getVersionedSrcs(),
selectedVersions),
PythonUtil.getModules(
baseTarget,
resolver,
ruleFinder,
pathResolver,
pythonPlatform.getValue(),
cxxPlatform.getValue(),
"resources",
baseModule,
args.getResources(),
args.getPlatformResources(),
args.getVersionedResources(),
selectedVersions),
ImmutableMap.of(),
ImmutableSet.of(),
args.getZipSafe());
return Optional.of(components).map(metadataClass::cast);
}
case PACKAGE_DEPS:
{
Map.Entry<Flavor, PythonPlatform> pythonPlatform =
pythonPlatforms
.getFlavorAndValue(baseTarget)
.orElseThrow(IllegalArgumentException::new);
Map.Entry<Flavor, CxxPlatform> cxxPlatform =
cxxPlatforms.getFlavorAndValue(baseTarget).orElseThrow(IllegalArgumentException::new);
baseTarget = buildTarget.withoutFlavors(pythonPlatform.getKey(), cxxPlatform.getKey());
ImmutableList<BuildTarget> depTargets =
PythonUtil.getDeps(
pythonPlatform.getValue(),
cxxPlatform.getValue(),
args.getDeps(),
args.getPlatformDeps());
return Optional.of(resolver.getAllRules(depTargets)).map(metadataClass::cast);
}
}
throw new IllegalStateException();
}
enum MetadataType implements FlavorConvertible {
PACKAGE_COMPONENTS(InternalFlavor.of("package-components")),
PACKAGE_DEPS(InternalFlavor.of("package-deps")),
;
private final Flavor flavor;
MetadataType(Flavor flavor) {
this.flavor = flavor;
}
@Override
public Flavor getFlavor() {
return flavor;
}
}
interface CoreArg extends CommonDescriptionArg, HasDeclaredDeps, HasTests {
@Value.Default
default SourceList getSrcs() {
return SourceList.EMPTY;
}
Optional<VersionMatchedCollection<SourceList>> getVersionedSrcs();
@Value.Default
default PatternMatchedCollection<SourceList> getPlatformSrcs() {
return PatternMatchedCollection.of();
}
@Value.Default
default SourceList getResources() {
return SourceList.EMPTY;
}
Optional<VersionMatchedCollection<SourceList>> getVersionedResources();
@Value.Default
default PatternMatchedCollection<SourceList> getPlatformResources() {
return PatternMatchedCollection.of();
}
@Value.Default
default PatternMatchedCollection<ImmutableSortedSet<BuildTarget>> getPlatformDeps() {
return PatternMatchedCollection.of();
}
Optional<String> getBaseModule();
Optional<Boolean> getZipSafe();
}
@BuckStyleImmutable
@Value.Immutable
interface AbstractPythonLibraryDescriptionArg extends CoreArg {}
}