blob: 0e0b199af9292ac89a1bb113466956f4376ef045 [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.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
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.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.ResolveEngine;
import org.apache.ivy.core.resolve.ResolveOptions;
import org.apache.ivy.core.sort.SortOptions;
import org.apache.ivy.plugins.report.XmlReportParser;
import org.apache.ivy.util.Message;
/**
* Represents a whole resolution report for a module but for a specific configuration
*/
public class ConfigurationResolveReport {
private final ModuleDescriptor md;
private final String conf;
private final Date date;
private final ResolveOptions options;
private Map<IvyNode, List<ArtifactDownloadReport>> dependencyReports = new LinkedHashMap<>();
private Map<ModuleRevisionId, IvyNode> dependencies = new LinkedHashMap<>();
private final ResolveEngine resolveEngine;
private Map<ModuleId, Collection<IvyNode>> modulesIdsMap = new LinkedHashMap<>();
private List<ModuleId> modulesIds;
private Boolean hasChanged = null;
public ConfigurationResolveReport(ResolveEngine resolveEngine, ModuleDescriptor md,
String conf, Date date, ResolveOptions options) {
this.resolveEngine = resolveEngine;
this.md = md;
this.conf = conf;
this.date = date;
this.options = options;
}
/**
* Check if the set of dependencies has changed since the previous execution of a resolution.
* <p>
* This function use the report file found in the cache. So the function must be called before
* the new report is serialized there.
* </p>
* <p>
* This function also use the internal dependencies that must already be filled. This function
* might be 'heavy' because it may have to parse the previous report.
* </p>
*/
public void checkIfChanged() {
ResolutionCacheManager cache = resolveEngine.getSettings().getResolutionCacheManager();
String resolveId = options.getResolveId();
File previousReportFile = cache.getConfigurationResolveReportInCache(resolveId, conf);
if (previousReportFile.exists()) {
try {
XmlReportParser parser = new XmlReportParser();
parser.parse(previousReportFile);
Set<ModuleRevisionId> previousDepSet = new HashSet<>(
Arrays.asList(parser.getDependencyRevisionIds()));
hasChanged = !previousDepSet.equals(getModuleRevisionIds());
} catch (Exception e) {
Message.warn("Error while parsing configuration resolve report "
+ previousReportFile.getAbsolutePath(), e);
hasChanged = Boolean.TRUE;
}
} else {
hasChanged = Boolean.TRUE;
}
}
/**
* @pre checkIfChanged has been called.
* @return boolean
*/
public boolean hasChanged() {
return hasChanged;
}
/**
* Returns all non evicted and non error dependency mrids The returned set is ordered so that a
* dependency will always be found before their own dependencies
*
* @return all non evicted and non error dependency mrids
*/
public Set<ModuleRevisionId> getModuleRevisionIds() {
Set<ModuleRevisionId> mrids = new LinkedHashSet<>();
for (IvyNode node : getDependencies()) {
if (!node.isEvicted(getConfiguration()) && !node.hasProblem()) {
mrids.add(node.getResolvedId());
}
}
return mrids;
}
public void addDependency(IvyNode node) {
dependencies.put(node.getId(), node);
dependencies.put(node.getResolvedId(), node);
dependencyReports.put(node, Collections.<ArtifactDownloadReport> emptyList());
}
public void updateDependency(ModuleRevisionId mrid, IvyNode node) {
dependencies.put(mrid, node);
}
public void addDependency(IvyNode node, DownloadReport report) {
dependencies.put(node.getId(), node);
dependencies.put(node.getResolvedId(), node);
List<ArtifactDownloadReport> adrs = new ArrayList<>();
for (Artifact artifact : node.getArtifacts(conf)) {
ArtifactDownloadReport artifactReport = report.getArtifactReport(artifact);
if (artifactReport != null) {
adrs.add(artifactReport);
} else {
Message.debug("no report found for " + artifact);
}
}
dependencyReports.put(node, adrs);
}
public String getConfiguration() {
return conf;
}
public Date getDate() {
return date;
}
public ModuleDescriptor getModuleDescriptor() {
return md;
}
public ResolveOptions getResolveOptions() {
return options;
}
public IvyNode[] getUnresolvedDependencies() {
List<IvyNode> unresolved = new ArrayList<>();
for (IvyNode node : getDependencies()) {
if (node.hasProblem()) {
unresolved.add(node);
}
}
return unresolved.toArray(new IvyNode[unresolved.size()]);
}
private Collection<IvyNode> getDependencies() {
return new LinkedHashSet<>(dependencies.values());
}
public IvyNode[] getEvictedNodes() {
List<IvyNode> evicted = new ArrayList<>();
for (IvyNode node : getDependencies()) {
if (node.isEvicted(conf)) {
evicted.add(node);
}
}
return evicted.toArray(new IvyNode[evicted.size()]);
}
private Set<ModuleRevisionId> getEvictedMrids() {
Set<ModuleRevisionId> evicted = new LinkedHashSet<>();
for (IvyNode node : getEvictedNodes()) {
evicted.add(node.getId());
}
return evicted;
}
public IvyNode[] getDownloadedNodes() {
List<IvyNode> downloaded = new ArrayList<>();
for (IvyNode node : getDependencies()) {
if (node.isDownloaded() && node.getRealNode() == node) {
downloaded.add(node);
}
}
return downloaded.toArray(new IvyNode[downloaded.size()]);
}
public IvyNode[] getSearchedNodes() {
List<IvyNode> downloaded = new ArrayList<>();
for (IvyNode node : getDependencies()) {
if (node.isSearched() && node.getRealNode() == node) {
downloaded.add(node);
}
}
return downloaded.toArray(new IvyNode[downloaded.size()]);
}
public ArtifactDownloadReport[] getDownloadReports(ModuleRevisionId mrid) {
Collection<ArtifactDownloadReport> col = dependencyReports.get(getDependency(mrid));
if (col == null) {
return new ArtifactDownloadReport[0];
}
return col.toArray(new ArtifactDownloadReport[col.size()]);
}
public IvyNode getDependency(ModuleRevisionId mrid) {
return dependencies.get(mrid);
}
/**
* 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() {
if (modulesIds == null) {
List<IvyNode> sortedDependencies = resolveEngine.getSortEngine().sortNodes(
getDependencies(), SortOptions.SILENT);
Collections.reverse(sortedDependencies);
for (IvyNode dependency : sortedDependencies) {
ModuleId mid = dependency.getResolvedId().getModuleId();
Collection<IvyNode> deps = modulesIdsMap.get(mid);
if (deps == null) {
deps = new LinkedHashSet<>();
modulesIdsMap.put(mid, deps);
}
deps.add(dependency);
}
modulesIds = new ArrayList<>(modulesIdsMap.keySet());
}
return Collections.unmodifiableList(modulesIds);
}
public Collection<IvyNode> getNodes(ModuleId mid) {
if (modulesIds == null) {
getModuleIds();
}
return modulesIdsMap.get(mid);
}
public ResolveEngine getResolveEngine() {
return resolveEngine;
}
public int getArtifactsNumber() {
int total = 0;
for (Collection<ArtifactDownloadReport> reports : dependencyReports.values()) {
total += reports == null ? 0 : reports.size();
}
return total;
}
/**
* 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.
* @return the list of reports, never <code>null</code>
* @see ArtifactDownloadReport
*/
public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus downloadStatus,
boolean withEvicted) {
Collection<ArtifactDownloadReport> all = new LinkedHashSet<>();
Collection<ModuleRevisionId> evictedMrids = null;
if (!withEvicted) {
evictedMrids = getEvictedMrids();
}
for (Collection<ArtifactDownloadReport> reports : dependencyReports.values()) {
for (ArtifactDownloadReport report : reports) {
if (downloadStatus != null && report.getDownloadStatus() != downloadStatus) {
continue;
}
if (withEvicted
|| !evictedMrids.contains(report.getArtifact().getModuleRevisionId())) {
all.add(report);
}
}
}
return all.toArray(new ArtifactDownloadReport[all.size()]);
}
/**
* Get the report on the successful download requests with the evicted modules
*
* @return the list of reports, never <code>null</code>
*/
public ArtifactDownloadReport[] getDownloadedArtifactsReports() {
return getArtifactsReports(DownloadStatus.SUCCESSFUL, true);
}
/**
* Get the report on the failed download requests with the evicted modules
*
* @return the list of reports, never <code>null</code>
*/
public ArtifactDownloadReport[] getFailedArtifactsReports() {
ArtifactDownloadReport[] allFailedReports = getArtifactsReports(DownloadStatus.FAILED, true);
return filterOutMergedArtifacts(allFailedReports);
}
public boolean hasError() {
return getUnresolvedDependencies().length > 0 || getFailedArtifactsReports().length > 0;
}
public int getNodesNumber() {
return getDependencies().size();
}
public static ArtifactDownloadReport[] filterOutMergedArtifacts(
ArtifactDownloadReport[] allFailedReports) {
Collection<ArtifactDownloadReport> adrs = new ArrayList<>(
Arrays.asList(allFailedReports));
Iterator<ArtifactDownloadReport> iterator = adrs.iterator();
while (iterator.hasNext()) {
ArtifactDownloadReport adr = iterator.next();
if (adr.getArtifact().getExtraAttribute("ivy:merged") != null) {
iterator.remove();
}
}
return adrs.toArray(new ArtifactDownloadReport[adrs.size()]);
}
}