# This patch file was generated by NetBeans IDE # It uses platform neutral UTF-8 encoding and \n newlines. --- src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java +++ src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java @@ -23,8 +23,13 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.ParseException; +import java.util.Collection; import java.util.Date; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; import org.apache.ivy.Ivy; @@ -525,6 +530,46 @@ } /** + * Parses the unique prefix key generated by {@link #getPrefixKey(Artifact) getPrefixKey}. + * One known limitation is that this method will NOT support artifacts that contain the '#' + * character in any field (name, type, ext) due to {@code getPrefixKey} not doing any escaping + * of the character(s) used as delimiters. + * + * @param key cached data file property key + * + * @return struct containing the individual fields of the prefix key, or {@code null} if unable + */ + private PropertyKeyStruct decodePrefixKey(String key) { + java.util.regex.Matcher matcher = PREFIX_DECODE_VALIDATION_PATTERN.matcher(key); + if (matcher.find()) { + PropertyKeyStruct struct = new PropertyKeyStruct(); + struct.name = matcher.group(1); + struct.type = matcher.group(2); + struct.ext = matcher.group(3); + struct.hash = Integer.parseInt(matcher.group(4)); + return struct; + } + return null; + } + + /** + * Requires EXACTLY THREE(3) text values (name, type, ext) and ONE(1) numeric value (hash code) + * delimited by '#' characters; the text values themselves MUST NOT contain the '#' delimiter. + * @see #getPrefixKey + * @see #decodePrefixKey + */ + private static final Pattern PREFIX_DECODE_VALIDATION_PATTERN = Pattern.compile( + "^artifact:([^#]+)#([^#]+)#([^#]+)#(-?\\d+)"); + + /** @see #decodePrefixKey */ + private static class PropertyKeyStruct { + String name; + String type; + String ext; + int hash; + } + + /** * Returns the key used to identify the location of the artifact. * * @param artifact @@ -1211,12 +1256,13 @@ deleteOldArtifacts = true; } if (deleteOldArtifacts) { - String[] confs = md.getConfigurationsNames(); - for (int i = 0; i < confs.length; i++) { - Artifact[] arts = md.getArtifacts(confs[i]); - for (int j = 0; j < arts.length; j++) { + Collection/**/ allArtifacts = discoverCachedArtifacts( + moduleArtifact, false /* don't include metadata files */); + Iterator/**/ iter = allArtifacts.iterator(); + while (iter.hasNext()) { + Artifact art = (Artifact) iter.next(); Artifact transformedArtifact = NameSpaceHelper.transform( - arts[j], options.getNamespace().getToSystemTransformer()); + art, options.getNamespace().getToSystemTransformer()); ArtifactOrigin origin = getSavedArtifactOrigin( transformedArtifact); File artFile = getArchiveFileInCache( @@ -1234,7 +1280,6 @@ } removeSavedArtifactOrigin(transformedArtifact); } - } } else if (isChanging(dd, mrid, options)) { Message.verbose(mrid + " is changing, but has not changed: will trust cached artifacts if any"); @@ -1267,6 +1312,49 @@ } + /** + * Helper method to find ALL potential artifacts that should CURRENTLY be in the cache, + * whether or not those artifacts are currently requested or even described by the metadata. + * Commonly, these files would include those that were downlaoded by {@literal } + * child tags within a {@literal } of the resolving-project's ivy.xml file. It + * also includes related artifacts for other types (such as maven classifiers) and optionally + * the artifact metadata files themselves. + * + * @param moduleArtifact current artifact being resolved + * @param includeMetadata {@code true} to include ivy, pom, and original pom metadata files + * + * @return zero or more {@link Artifact} instances that supposedly exist in the cache for + * the specified module artifact + */ + private Collection/**/ discoverCachedArtifacts( + Artifact moduleArtifact, boolean includeMetadata) { + Set/**/ discovered = new LinkedHashSet(); + PropertiesFile cdf = getCachedDataFile(moduleArtifact.getModuleRevisionId()); + Enumeration/**/ keys = cdf.propertyNames(); + while (keys.hasMoreElements()) { + String key = (String) keys.nextElement(); + PropertyKeyStruct keyStruct = decodePrefixKey(key); + if (keyStruct != null && (includeMetadata || !isMetadataPropertyKey(keyStruct))) { + Artifact art = DefaultArtifact.cloneWithAnotherTypeAndExt( + DefaultArtifact.cloneWithAnotherName(moduleArtifact, keyStruct.name), + keyStruct.type, keyStruct.ext); + discovered.add(art); + } + } + return discovered; + } + + /** + * Identifies property data relating to repository metadata. + * @see #discoverCachedArtifacts + * @param keyStruct property information + * @return {@code true} if {@code keyStruct} seems to describe repository metadata artifacts + */ + private boolean isMetadataPropertyKey(PropertyKeyStruct keyStruct) { + return ("ivy".equals(keyStruct.name) && "ivy".equals(keyStruct.type)) + || ("pom".equals(keyStruct.type) || "pom.original".equals(keyStruct.type)); + } + // lock used to lock all metadata related information access private boolean lockMetadataArtifact(ModuleRevisionId mrid) { Artifact artifact = getDefaultMetadataArtifact(mrid);