/*
* Copyright 2016 the original author or authors.
*
* 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 org.gradle.api.internal.resolve;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import org.gradle.api.artifacts.component.LibraryComponentSelector;
import org.gradle.platform.base.Binary;
import org.gradle.platform.base.VariantComponent;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Intermediate data structure used to store the result of a resolution and help at building an understandable error message in case resolution fails.
*/
public class LibraryResolutionResult {
public static final Function<String, String> QUOTE_TRANSFORMER = new Function<String, String>() {
@Override
public String apply(String input) {
return "'" + input + "'";
}
};
private final Map<String, VariantComponent> libsMatchingRequirements;
private final Map<String, VariantComponent> libsNotMatchingRequirements;
private final Class<? extends Binary> binaryType;
private boolean projectNotFound;
private VariantComponent selectedLibrary;
private VariantComponent nonMatchingLibrary;
private LibraryResolutionResult(Class<? extends Binary> binaryType) {
this.binaryType = binaryType;
this.libsMatchingRequirements = Maps.newHashMap();
this.libsNotMatchingRequirements = Maps.newHashMap();
}
private VariantComponent getSingleMatchingLibrary() {
if (libsMatchingRequirements.size() == 1) {
return libsMatchingRequirements.values().iterator().next();
}
return null;
}
private void resolve(String libraryName) {
if (libraryName == null) {
VariantComponent singleMatchingLibrary = getSingleMatchingLibrary();
if (singleMatchingLibrary == null) {
return;
}
libraryName = singleMatchingLibrary.getName();
}
selectedLibrary = libsMatchingRequirements.get(libraryName);
nonMatchingLibrary = libsNotMatchingRequirements.get(libraryName);
}
public boolean isProjectNotFound() {
return projectNotFound;
}
public boolean hasLibraries() {
return !libsMatchingRequirements.isEmpty() || !libsNotMatchingRequirements.isEmpty();
}
public VariantComponent getSelectedLibrary() {
return selectedLibrary;
}
public VariantComponent getNonMatchingLibrary() {
return nonMatchingLibrary;
}
public List<String> getCandidateLibraries() {
return Lists.newArrayList(libsMatchingRequirements.keySet());
}
public String toResolutionErrorMessage(
LibraryComponentSelector selector) {
List<String> candidateLibraries = formatLibraryNames(getCandidateLibraries());
String projectPath = selector.getProjectPath();
String libraryName = selector.getLibraryName();
StringBuilder sb = new StringBuilder("Project '").append(projectPath).append("'");
if (libraryName == null || !hasLibraries()) {
if (isProjectNotFound()) {
sb.append(" not found.");
} else if (!hasLibraries()) {
sb.append(" doesn't define any library.");
} else {
sb.append(" contains more than one library. Please select one of ");
Joiner.on(", ").appendTo(sb, candidateLibraries);
}
} else {
VariantComponent notMatchingRequirements = getNonMatchingLibrary();
if (notMatchingRequirements != null) {
sb.append(" contains a library named '").append(libraryName)
.append("' but it doesn't have any binary of type ")
.append(binaryType.getSimpleName());
} else {
sb.append(" does not contain library '").append(libraryName).append("'. Did you want to use ");
if (candidateLibraries.size() == 1) {
sb.append(candidateLibraries.get(0));
} else {
sb.append("one of ");
Joiner.on(", ").appendTo(sb, candidateLibraries);
}
sb.append("?");
}
}
return sb.toString();
}
public static LibraryResolutionResult of(Class<? extends Binary> binaryType, Collection<? extends VariantComponent> libraries, String libraryName, Predicate<? super VariantComponent> libraryFilter) {
LibraryResolutionResult result = new LibraryResolutionResult(binaryType);
for (VariantComponent librarySpec : libraries) {
if (libraryFilter.apply(librarySpec)) {
result.libsMatchingRequirements.put(librarySpec.getName(), librarySpec);
} else {
result.libsNotMatchingRequirements.put(librarySpec.getName(), librarySpec);
}
}
result.resolve(libraryName);
return result;
}
public static LibraryResolutionResult projectNotFound(Class<? extends Binary> binaryType) {
LibraryResolutionResult projectNotFoundResult = new LibraryResolutionResult(binaryType);
projectNotFoundResult.projectNotFound = true;
return projectNotFoundResult;
}
public static LibraryResolutionResult emptyResolutionResult(Class<? extends Binary> binaryType) {
return new LibraryResolutionResult(binaryType);
}
private static List<String> formatLibraryNames(List<String> libs) {
List<String> list = Lists.transform(libs, QUOTE_TRANSFORMER);
return Ordering.natural().sortedCopy(list);
}
}