package org.moxie; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Scanner; import java.util.Set; import java.util.TreeSet; import org.moxie.utils.DeepCopier; import org.moxie.utils.FileUtils; import org.moxie.utils.StringUtils; public abstract class IMavenCache { protected Logger logger; public abstract File getRootFolder(); public abstract Collection<File> getFiles(String extension); public abstract File getArtifact(Dependency dep, String ext); public abstract File writeArtifact(Dependency dep, String ext, String content); public abstract File writeArtifact(Dependency dep, String ext, byte[] content); public abstract File getMetadata(Dependency dep, String ext); public abstract File writeMetadata(Dependency dep, String ext, String content); public abstract File writeMetadata(Dependency dep, String ext, byte[] content); public void setLogger(Logger logger) { this.logger = logger; } protected Dependency resolveRevision(Dependency dependency) { if ((dependency.isSnapshot() && StringUtils.isEmpty(dependency.revision)) || dependency.version.equalsIgnoreCase(Constants.RELEASE) || dependency.version.equalsIgnoreCase(Constants.LATEST) || dependency.isRangedVersion()) { // Support VERSION RANGE, SNAPSHOT, RELEASE and LATEST versions File metadataFile = getMetadata(dependency, Constants.XML); // read SNAPSHOT, LATEST, or RELEASE from metadata if (metadataFile != null && metadataFile.exists()) { Metadata metadata = MetadataReader.readMetadata(metadataFile); String version; String revision; if (Constants.RELEASE.equalsIgnoreCase(dependency.version)) { // RELEASE version = metadata.release; revision = version; } else if (Constants.LATEST.equalsIgnoreCase(dependency.version)) { // LATEST version = metadata.latest; revision = version; } else if (dependency.isSnapshot()) { // SNAPSHOT version = dependency.version; revision = metadata.getSnapshotRevision(); } else { // VERSION RANGE version = metadata.resolveRangedVersion(dependency.version); revision = version; } dependency.version = version; dependency.revision = revision; } } // standard release return dependency; } public void purgeSnapshots(Dependency dep, PurgePolicy policy) { if (!dep.isSnapshot()) { return; } File metadataFile = getMetadata(dep, Constants.XML); if (metadataFile == null || !metadataFile.exists()) { return; } Metadata metadata = MetadataReader.readMetadata(metadataFile); List<String> purgedRevisions = metadata.purgeSnapshots(policy); if (purgedRevisions.size() > 0) { if (logger != null) { logger.debug("purging old snapshots of " + dep.getCoordinates()); } for (String revision : purgedRevisions) { Dependency old = DeepCopier.copy(dep); old.revision = revision; purgeArtifacts(old, false); } // write purged metadata FileUtils.writeContent(metadataFile, metadata.toXML()); // if this dependency has a parent, purge that too File pomFile = getArtifact(dep, Constants.POM); Pom pom = PomReader.readPom(this, pomFile); if (pom.hasParentDependency()) { Dependency parent = pom.getParentDependency(); parent.setOrigin(dep.getOrigin()); purgeSnapshots(parent, policy); } } } public void purgeArtifacts(Dependency dep, boolean includeDependencies) { String identifier = dep.version; if (dep.isSnapshot()) { identifier = dep.revision; } File artifact = getArtifact(dep, dep.extension); File folder = artifact.getParentFile(); if (folder == null || !folder.exists()) { if (logger != null) { logger.debug(1, "! skipping non existent folder " + folder); } return; } File [] files = folder.listFiles(); if (files == null) { return; } for (File file : files) { if (file.isFile() && file.getName().contains(identifier)) { if (logger != null) { logger.debug(1, "- " + file.getName()); } file.delete(); } } } /** * Generates a POM index or list using the specified template. * * @param pomTemplate * @param separator separates pom entries * @return the index/list */ public String generatePomIndex(String pomTemplate, String separator) { List<Pom> poms = readAllPoms(); Collections.sort(poms); StringBuilder sb = new StringBuilder(); for (Pom pom : poms) { String artifact = pomTemplate; artifact = artifact.replace("${artifact.name}", pom.getName() == null ? pom.getArtifactId() : pom.getName()); artifact = artifact.replace("${artifact.description}", pom.getDescription() == null ? "" : pom.getDescription()); artifact = artifact.replace("${artifact.groupId}", pom.getGroupId()); artifact = artifact.replace("${artifact.artifactId}", pom.getArtifactId()); artifact = artifact.replace("${artifact.version}", pom.getVersion()); Dependency dep = new Dependency(pom.getCoordinates()); dep.extension = pom.getExtension(); resolveRevision(dep); artifact = artifact.replace("${artifact.date}", getLastModified(dep)); artifact = artifact.replace("${artifact.pom}", getMavenPath(dep.getPomArtifact())); artifact = artifact.replace("${artifact.package}", getMavenPath(dep)); artifact = artifact.replace("${artifact.sources}", getMavenPath(dep.getSourcesArtifact())); artifact = artifact.replace("${artifact.javadoc}", getMavenPath(dep.getJavadocArtifact())); artifact = artifact.replace("${artifact.packageSize}", getArtifactSize(dep)); artifact = artifact.replace("${artifact.sourcesSize}", getArtifactSize(dep.getSourcesArtifact())); artifact = artifact.replace("${artifact.javadocSize}", getArtifactSize(dep.getJavadocArtifact())); sb.append(artifact); sb.append(separator); } // trim trailing separator sb.setLength(sb.length() - separator.length()); return sb.toString(); } /** * Reads the prefixes index. * * @return a prefixes index. */ public Set<String> getPrefixes() { return readPrefixesIndex(new File(getRootFolder(), Constants.PREFIXES)); } /** * Reads the specified prefix index. * * @param file * @return the prefixes */ protected Set<String> readPrefixesIndex(File file) { Set<String> prefixes = new TreeSet<String>(); if (file.exists()) { Scanner scanner = null; try { scanner = new Scanner(file); while (scanner.hasNext()) { prefixes.add(scanner.next()); } } catch (Exception e) { } finally { if (scanner != null) { scanner.close(); } } } return prefixes; } /** * Creates/updates a prefixes index used by smart maven clients to do * automatic dependency routing. * * @return the index file */ public File updatePrefixesIndex() { return updatePrefixesIndex(getRootFolder()); } /** * Creates/updates a prefixes index used by smart Maven clients to do * automatic dependency routing. * * https://issues.sonatype.org/browse/NEXUS-5472 * https://github.com/restlet/restlet-framework-java/issues/449 * * @param dir directory to index * @return the index file */ protected File updatePrefixesIndex(File dir) { File file = new File(dir, Constants.PREFIXES); Set<String> prefixes = readPrefixesIndex(file); // generate index first from discovered poms List<Pom> poms = readAllPoms(dir); Collections.sort(poms); for (Pom pom : poms) { String prefix = pom.getPrefix(); prefixes.add(prefix); } // always add the .meta directory prefixes.add("/.meta"); return writePrefixes(file, prefixes); } /** * Writes the prefixes index. * * @return a prefixes index file */ public File writePrefixes(Set<String> prefixes) { File file = new File(getRootFolder(), Constants.PREFIXES); return writePrefixes(file, prefixes); } /** * Writes the prefixes index. * * @param file the target file * @param prefixes the set of prefixes * */ protected File writePrefixes(File file, Set<String> prefixes) { // create flat index content StringBuilder sb = new StringBuilder(); for (String prefix : prefixes) { sb.append(prefix).append('\n'); } // write the index file FileUtils.writeContent(file, sb.toString()); return file; } private String getMavenPath(Dependency dep) { String path = Dependency.getArtifactPath(dep, dep.extension, Constants.MAVEN2_ARTIFACT_PATTERN); if (new File(getRootFolder(), path).exists()) { return path; } return ""; } private String getLastModified(Dependency dep) { File file = getArtifact(dep, dep.extension); if (file != null && file.exists()) { return new SimpleDateFormat("yyyy-MM-dd").format(new Date(file.lastModified())); } return ""; } private String getArtifactSize(Dependency dep) { File file = getArtifact(dep, dep.extension); if (file != null && file.exists()) { return FileUtils.formatSize(file.length()); } return ""; } public List<Pom> readAllPoms() { List<Pom> poms = new ArrayList<Pom>(); poms.addAll(readAllPoms(getRootFolder())); return poms; } private List<Pom> readAllPoms(File dir) { List<Pom> poms = new ArrayList<Pom>(); File [] files = dir.listFiles(); if (files == null) { return poms; } for (File file : files) { if (file.isDirectory()) { // recurse into this directory poms.addAll(readAllPoms(file)); } else if (file.getName().endsWith(Constants.POM)) { // read this pom try { Pom pom = PomReader.readPom(this, file); poms.add(pom); } catch (Throwable t) { if (logger != null) { logger.error(t, "Failed to read POM " + file); } } } } return poms; } }