| /* |
| * 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; |
| } |
| } |