blob: 8a8d0f78889559eabe4e9cfeafca224bcb677482 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* https://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.apache.ivy.core.report;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ivy.core.cache.ResolutionCacheManager;
import org.apache.ivy.core.module.descriptor.Artifact;
import org.apache.ivy.core.module.descriptor.Configuration;
import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
import org.apache.ivy.core.module.descriptor.DefaultModuleDescriptor;
import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.apache.ivy.core.module.id.ModuleId;
import org.apache.ivy.core.module.id.ModuleRevisionId;
import org.apache.ivy.core.resolve.IvyNode;
import org.apache.ivy.core.resolve.ResolveOptions;
import org.apache.ivy.core.settings.IvySettings;
import org.apache.ivy.plugins.report.ReportOutputter;
import org.apache.ivy.util.filter.Filter;
/**
* Represents a whole resolution report for a module
*/
public class ResolveReport {
private ModuleDescriptor md;
private Map<String, ConfigurationResolveReport> confReports = new LinkedHashMap<>();
private List<String> problemMessages = new ArrayList<>();
/**
* the list of all dependencies resolved, ordered from the more dependent to the less dependent
*/
private List<IvyNode> dependencies = new ArrayList<>();
private List<Artifact> artifacts = new ArrayList<>();
private long resolveTime;
private long downloadTime;
private String resolveId;
private long downloadSize;
public ResolveReport(ModuleDescriptor md) {
this(md, ResolveOptions.getDefaultResolveId(md));
}
public ResolveReport(ModuleDescriptor md, String resolveId) {
this.md = md;
this.resolveId = resolveId;
}
public void addReport(String conf, ConfigurationResolveReport report) {
confReports.put(conf, report);
}
public ConfigurationResolveReport getConfigurationReport(String conf) {
return confReports.get(conf);
}
public String[] getConfigurations() {
return confReports.keySet().toArray(new String[confReports.size()]);
}
public boolean hasError() {
for (ConfigurationResolveReport report : confReports.values()) {
if (report.hasError()) {
return true;
}
}
return false;
}
public void output(ReportOutputter[] outputters, ResolutionCacheManager cacheMgr,
ResolveOptions options) throws IOException {
for (ReportOutputter outputter : outputters) {
outputter.output(this, cacheMgr, options);
}
}
public ModuleDescriptor getModuleDescriptor() {
return md;
}
public IvyNode[] getEvictedNodes() {
Collection<IvyNode> all = new LinkedHashSet<>();
for (ConfigurationResolveReport report : confReports.values()) {
all.addAll(Arrays.asList(report.getEvictedNodes()));
}
return all.toArray(new IvyNode[all.size()]);
}
public IvyNode[] getUnresolvedDependencies() {
Collection<IvyNode> all = new LinkedHashSet<>();
for (ConfigurationResolveReport report : confReports.values()) {
all.addAll(Arrays.asList(report.getUnresolvedDependencies()));
}
return all.toArray(new IvyNode[all.size()]);
}
/**
* Get every report on the download requests.
*
* @return the list of reports, never <code>null</code>
*/
public ArtifactDownloadReport[] getFailedArtifactsReports() {
return ConfigurationResolveReport.filterOutMergedArtifacts(getArtifactsReports(
DownloadStatus.FAILED, true));
}
/**
* Get every report on the download requests.
*
* @return the list of reports, never <code>null</code>
*/
public ArtifactDownloadReport[] getAllArtifactsReports() {
return getArtifactsReports(null, true);
}
/**
* Get the report on the download requests. The list of download report can be restricted to a
* specific download status, and also remove the download report for the evicted modules.
*
* @param downloadStatus
* the status of download to retrieve. Set it to <code>null</code> for no restriction
* on the download status
* @param withEvicted
* set it to <code>true</code> if the report for the evicted modules have to be
* retrieved, <code>false</code> to exclude reports from modules evicted in all
* configurations.
* @return the list of reports, never <code>null</code>
* @see ConfigurationResolveReport#getArtifactsReports(DownloadStatus, boolean)
*/
public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus downloadStatus,
boolean withEvicted) {
Collection<ArtifactDownloadReport> all = new LinkedHashSet<>();
for (ConfigurationResolveReport report : confReports.values()) {
ArtifactDownloadReport[] reports = report.getArtifactsReports(downloadStatus,
withEvicted);
all.addAll(Arrays.asList(reports));
}
return all.toArray(new ArtifactDownloadReport[all.size()]);
}
public ArtifactDownloadReport[] getArtifactsReports(ModuleRevisionId mrid) {
Collection<ArtifactDownloadReport> all = new LinkedHashSet<>();
for (ConfigurationResolveReport report : confReports.values()) {
all.addAll(Arrays.asList(report.getDownloadReports(mrid)));
}
return all.toArray(new ArtifactDownloadReport[all.size()]);
}
public void checkIfChanged() {
for (ConfigurationResolveReport report : confReports.values()) {
report.checkIfChanged();
}
}
/**
* Can only be called if checkIfChanged has been called
*
* @return boolean
*/
public boolean hasChanged() {
for (ConfigurationResolveReport report : confReports.values()) {
if (report.hasChanged()) {
return true;
}
}
return false;
}
public void setProblemMessages(List<String> problems) {
problemMessages = problems;
}
public List<String> getProblemMessages() {
return problemMessages;
}
public List<String> getAllProblemMessages() {
List<String> ret = new ArrayList<>(problemMessages);
for (ConfigurationResolveReport r : confReports.values()) {
for (IvyNode unresolved : r.getUnresolvedDependencies()) {
String errMsg = unresolved.getProblemMessage();
if (errMsg.isEmpty()) {
ret.add("unresolved dependency: " + unresolved.getId());
} else {
ret.add("unresolved dependency: " + unresolved.getId() + ": " + errMsg);
}
}
for (ArtifactDownloadReport adr : r.getFailedArtifactsReports()) {
ret.add("download failed: " + adr.getArtifact());
}
}
return ret;
}
public void setDependencies(List<IvyNode> dependencies, Filter<Artifact> artifactFilter) {
this.dependencies = dependencies;
// collect list of artifacts
artifacts = new ArrayList<>();
for (IvyNode dependency : dependencies) {
if (!dependency.isCompletelyEvicted() && !dependency.hasProblem()) {
artifacts.addAll(Arrays.asList(dependency.getSelectedArtifacts(artifactFilter)));
}
// update the configurations reports with the dependencies
// these reports will be completed later with download information, if any
for (String dconf : dependency.getRootModuleConfigurations()) {
ConfigurationResolveReport configurationReport = getConfigurationReport(dconf);
if (configurationReport != null) {
configurationReport.addDependency(dependency);
}
}
}
}
/**
* Returns the list of all dependencies concerned by this report as a List of IvyNode ordered
* from the more dependent to the least one
*
* @return The list of all dependencies.
*/
public List<IvyNode> getDependencies() {
return dependencies;
}
/**
* Returns the list of all artifacts which should be downloaded per this resolve To know if the
* artifact have actually been downloaded use information found in ConfigurationResolveReport.
*
* @return The list of all artifacts.
*/
public List<Artifact> getArtifacts() {
return artifacts;
}
/**
* gives all the modules ids concerned by this report, from the most dependent to the least one
*
* @return a list of ModuleId
*/
public List<ModuleId> getModuleIds() {
List<ModuleId> ret = new ArrayList<>();
List<IvyNode> sortedDependencies = new ArrayList<>(dependencies);
for (IvyNode dependency : sortedDependencies) {
ModuleId mid = dependency.getResolvedId().getModuleId();
if (!ret.contains(mid)) {
ret.add(mid);
}
}
return ret;
}
public void setResolveTime(long elapsedTime) {
resolveTime = elapsedTime;
}
public long getResolveTime() {
return resolveTime;
}
public void setDownloadTime(long elapsedTime) {
downloadTime = elapsedTime;
}
public long getDownloadTime() {
return downloadTime;
}
public void setDownloadSize(long size) {
this.downloadSize = size;
}
/**
* The total size of downloaded artifacts, in bytes.
* <p>
* This only includes artifacts actually downloaded to cache (DownloadStatus.SUCCESSFUL), and
* not artifacts already in cache or used at their original location.
* </p>
*
* @return The total size of downloaded artifacts, in bytes.
*/
public long getDownloadSize() {
return downloadSize;
}
public String getResolveId() {
return resolveId;
}
/**
* Get every configuration which extends the specified one. The returned list also includes the
* specified one.
*
* @param extended String
* @return Set of String
*/
@SuppressWarnings("unused")
private Set<String> getExtendingConfs(String extended) {
Set<String> extendingConfs = new HashSet<>();
extendingConfs.add(extended);
for (String conf : md.getConfigurationsNames()) {
gatherExtendingConfs(extendingConfs, conf, extended);
}
return extendingConfs;
}
private boolean gatherExtendingConfs(Set<String> extendingConfs, String conf, String extended) {
if (extendingConfs.contains(conf)) {
return true;
}
String[] exts = md.getConfiguration(conf).getExtends();
if (exts == null || exts.length == 0) {
return false;
}
for (String ext : exts) {
if (extendingConfs.contains(ext)) {
extendingConfs.add(conf);
return true;
}
if (ext.equals(extended)) {
extendingConfs.add(conf);
return true;
}
if (gatherExtendingConfs(extendingConfs, ext, extended)) {
extendingConfs.add(conf);
return true;
}
}
return false;
}
public ModuleDescriptor toFixedModuleDescriptor(IvySettings settings, List<ModuleId> midToKeep) {
DefaultModuleDescriptor fixedmd = new DefaultModuleDescriptor(md.getModuleRevisionId(),
md.getStatus(), new Date());
// copy namespaces
for (Map.Entry<String, String> ns : md.getExtraAttributesNamespaces().entrySet()) {
fixedmd.addExtraAttributeNamespace(ns.getKey(), ns.getValue());
}
// copy info
fixedmd.setDescription(md.getDescription());
fixedmd.setHomePage(md.getHomePage());
fixedmd.getExtraInfos().addAll(md.getExtraInfos());
// copy configurations
List<String> resolvedConfs = Arrays.asList(getConfigurations());
for (String conf : resolvedConfs) {
fixedmd.addConfiguration(new Configuration(conf));
}
// copy artifacts
for (String conf : resolvedConfs) {
for (Artifact a : md.getArtifacts(conf)) {
fixedmd.addArtifact(conf, a);
}
}
// add resolved dependencies
for (IvyNode dep : dependencies) {
ModuleRevisionId depMrid;
boolean force;
if (midToKeep != null && midToKeep.contains(dep.getModuleId())) {
depMrid = dep.getId();
force = false;
} else {
depMrid = dep.getResolvedId();
force = true;
}
DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(fixedmd, depMrid,
force, false, false);
boolean evicted = true;
for (String rootConf : dep.getRootModuleConfigurations()) {
if (dep.isEvicted(rootConf)) {
continue;
}
evicted = false;
for (String targetConf : dep.getConfigurations(rootConf)) {
dd.addDependencyConfiguration(rootConf, targetConf);
}
}
if (!evicted) {
fixedmd.addDependency(dd);
}
}
return fixedmd;
}
}