// Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).
package com.twitter.intellij.pants.service.project.model;
import com.intellij.openapi.util.Condition;
import com.intellij.util.containers.ContainerUtil;
import com.twitter.intellij.pants.model.PantsSourceType;
import com.twitter.intellij.pants.model.TargetAddressInfo;
import com.twitter.intellij.pants.util.PantsScalaUtil;
import com.twitter.intellij.pants.util.PantsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
public class TargetInfo {
protected Set<TargetAddressInfo> addressInfos = Collections.emptySet();
/**
* List of libraries. Just names.
*/
protected Set<String> libraries = Collections.emptySet();
/**
* List of libraries. Just names.
*/
protected Set<String> excludes = Collections.emptySet();
/**
* List of dependencies.
*/
protected Set<String> targets = Collections.emptySet();
/**
* List of source roots.
*/
protected Set<ContentRoot> roots = Collections.emptySet();
public TargetInfo(TargetAddressInfo... addressInfos) {
setAddressInfos(ContainerUtil.newHashSet(addressInfos));
}
public TargetInfo(
Set<TargetAddressInfo> addressInfos,
Set<String> targets,
Set<String> libraries,
Set<String> excludes,
Set<ContentRoot> roots
) {
setAddressInfos(addressInfos);
setLibraries(libraries);
setExcludes(excludes);
setTargets(targets);
setRoots(roots);
}
public Set<TargetAddressInfo> getAddressInfos() {
return addressInfos;
}
public void setAddressInfos(Set<TargetAddressInfo> addressInfos) {
this.addressInfos = addressInfos;
}
@NotNull
public Set<String> getLibraries() {
return libraries;
}
public void setLibraries(Set<String> libraries) {
this.libraries = new TreeSet<>(libraries);
}
@NotNull
public Set<String> getExcludes() {
return excludes;
}
public void setExcludes(Set<String> excludes) {
this.excludes = new TreeSet<String>(excludes);
}
@NotNull
public Set<String> getTargets() {
return targets;
}
public void setTargets(Set<String> targets) {
this.targets = new TreeSet<String>(targets);
}
@NotNull
public Set<ContentRoot> getRoots() {
return roots;
}
public void setRoots(Set<ContentRoot> roots) {
this.roots = new TreeSet<ContentRoot>(roots);
}
public boolean isEmpty() {
return libraries.isEmpty() && targets.isEmpty() && roots.isEmpty() && addressInfos.isEmpty();
}
@Nullable
public String findScalaLibId() {
return ContainerUtil.find(
libraries,
new Condition<String>() {
@Override
public boolean value(String libraryId) {
return PantsScalaUtil.isScalaLibraryLib(libraryId);
}
}
);
}
public boolean isTest() {
return ContainerUtil.exists(
getAddressInfos(),
new Condition<TargetAddressInfo>() {
@Override
public boolean value(TargetAddressInfo info) {
return PantsUtil.getSourceTypeForTargetType(info.getTargetType()).toExternalSystemSourceType().isTest();
}
}
);
}
@NotNull
public PantsSourceType getSourcesType() {
// In the case where multiple targets get combined into one module,
// the type of common module should be in the order of
// source -> test source -> resource -> test resources. (like Ranked Value in Pants options)
// e.g. if source and resources get combined, the common module should be source type.
Set<PantsSourceType> allTypes = getAddressInfos().stream()
.map(s -> PantsUtil.getSourceTypeForTargetType(s.getTargetType()))
.collect(Collectors.toSet());
Optional<PantsSourceType> topRankedType = Arrays.stream(PantsSourceType.values())
.filter(allTypes::contains)
.findFirst();
if (topRankedType.isPresent()) {
return topRankedType.get();
}
return PantsSourceType.SOURCE;
}
public boolean isJarLibrary() {
return getAddressInfos().stream().allMatch(TargetAddressInfo::isJarLibrary);
}
public boolean isScalaTarget() {
return getAddressInfos().stream().anyMatch(TargetAddressInfo::isScala);
}
public boolean isPythonTarget() {
return getAddressInfos().stream().anyMatch(TargetAddressInfo::isPython);
}
public boolean dependOn(@NotNull String targetName) {
return targets.contains(targetName);
}
public void addDependency(@NotNull String targetName) {
if (targets.isEmpty()) {
targets = new HashSet<>(Collections.singletonList(targetName));
}
else {
targets.add(targetName);
}
}
public boolean removeDependency(@NotNull String targetName) {
return getTargets().remove(targetName);
}
public void replaceDependency(@NotNull String targetName, @NotNull String newTargetName) {
if (removeDependency(targetName)) {
addDependency(newTargetName);
}
}
public TargetInfo union(@NotNull TargetInfo other) {
return new TargetInfo(
ContainerUtil.union(getAddressInfos(), other.getAddressInfos()),
ContainerUtil.union(getTargets(), other.getTargets()),
ContainerUtil.union(getLibraries(), other.getLibraries()),
ContainerUtil.union(getExcludes(), other.getExcludes()),
ContainerUtil.union(getRoots(), other.getRoots())
);
}
@Override
public String toString() {
return "TargetInfo{" +
"libraries=" + libraries +
", excludes=" + excludes +
", targets=" + targets +
", roots=" + roots +
", addressInfos='" + addressInfos + '\'' +
'}';
}
}