package com.feisystems.tools.maven; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.commons.cli.ParseException; import org.apache.commons.lang.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MavenArtifactCleaner { private final static Logger logger = LoggerFactory .getLogger(MavenArtifactCleaner.class); /** * Maven Artifact Cleaner tool with CLI. * * @param args * see -h or -help for usage details * @throws IOException * @throws ParseException */ public static void main(String[] args) throws IOException, ParseException { // Load configuration Config config = null; try { config = CLI.getConfig(args); logger.info(config.toString()); if (config.getArtifacts().size() == 0) { logger.info("Please see help (-h or -help) for the usage of this tool..."); } } catch (Exception e) { logger.error("Error occured:"); logger.error(e.getMessage(), e); logger.error("Cannot load the configuration, stopping the tool..."); System.exit(1); } // For each artifact passed in the arguments for (Artifact artifact : config.getArtifacts()) { // Find groupId folder StringBuilder pathBuilder = new StringBuilder(); pathBuilder.append(config.getMavenRepositoryPath()); String groupId = artifact.getGroupId(); appendFolderToPath(pathBuilder, groupId.replace(".", "\\")); String groupdIdAbsolutePath = buildEscapedPath(pathBuilder); File groupFolder = new File(groupdIdAbsolutePath); Map<String, HashMap<String, ArrayList<Version>>> versionFoldersToClean = new HashMap<String, HashMap<String, ArrayList<Version>>>(); // Find/Filter requested artifact folders for (File artifactFolder : groupFolder.listFiles(FileFilterFactory .createFileFilterForArtifact(artifact))) { // Version folders in an artifact folder File[] versionFolders = artifactFolder .listFiles(FileFilterFactory.DIRECTORY_FILTER); HashMap<String, ArrayList<Version>> versions = mapToVersionsByQualifier( versionFolders, config.isUseQualifierAsBranch()); // Collect version folders to be cleaned versionFoldersToClean.put(artifactFolder.getAbsolutePath(), versions); } // Log version folders to be cleaned logVersionFoldersToClean(versionFoldersToClean); for (String artifactFolderAbsolutePath : versionFoldersToClean .keySet()) { HashMap<String, ArrayList<Version>> qualifierToVersionsMap = versionFoldersToClean .get(artifactFolderAbsolutePath); // if config.isUseQualifierAsBranch()==false, there will be only // 1 qualifier ("*") for (String qualifier : qualifierToVersionsMap.keySet()) { ArrayList<Version> versions = qualifierToVersionsMap .get(qualifier); // Recursively delete the files/folders starting from the // beginning of version list. if (versions.size() > config.getNumberOfVersionsToKeep()) { int deleteBeforeIndex = versions.size() - config.getNumberOfVersionsToKeep(); for (int i = 0; i < deleteBeforeIndex; i++) { // Recursive method to delete folders with all files // in it. delete(versions.get(i).getFile()); } } } } } } public static String buildEscapedPath(StringBuilder pathBuilder) { return StringEscapeUtils.escapeJava(pathBuilder.toString()); } public static void appendFolderToPath(StringBuilder pathBuilder, String folder) { pathBuilder.append("\\"); pathBuilder.append(folder); } /** * Recursive delete method that deletes a folder its all contents. * * @param file * If this is just a file, it deletes the file. If this is a * folder, it recursively deletes the folder with everything in * it. * @throws IOException */ private static void delete(File file) throws IOException { if (file.isDirectory()) { // directory is empty, then delete it if (file.list().length == 0) { file.delete(); logger.info("Directory is deleted : " + file.getAbsolutePath()); } else { // list all the directory contents String files[] = file.list(); for (String temp : files) { // construct the file structure File fileDelete = new File(file, temp); // recursive delete delete(fileDelete); } // check the directory again, if empty then delete it if (file.list().length == 0) { file.delete(); logger.info("Directory is deleted : " + file.getAbsolutePath()); } } } else { // if file, then delete it file.delete(); logger.info("File is deleted : " + file.getAbsolutePath()); } } /** * Logs the discovered and filtered version folders. * * @param map * versionFoldersToClean */ private static void logVersionFoldersToClean( Map<String, HashMap<String, ArrayList<Version>>> map) { for (String key : map.keySet()) { for (String key2 : map.get(key).keySet()) { logger.info(key + "\t" + map.get(key).get(key2)); } } } /** * If useQualifierAsBranch==true, this method returns a map from qualifiers * (key) to version folders (value). If useQualifierAsBranch==false, this * method returns a map with only one key ("*") with all version folders as * the value. * * @param versionFolders * @param useQualifierAsBranch * @return */ private static HashMap<String, ArrayList<Version>> mapToVersionsByQualifier( File[] versionFolders, boolean useQualifierAsBranch) { HashMap<String, ArrayList<Version>> map = new HashMap<String, ArrayList<Version>>(); for (File file : versionFolders) { if (!file.getName().contains("$")) { Version version = Version.newVersion(file); ArrayList<Version> list = new ArrayList<Version>(); // If useQualifierAsBranch=true, collect the version folders by // qualifier; Else collect all version folders in the same list // with map key="*". String qualifier = useQualifierAsBranch ? version .getQualifier() : "*"; if (map.containsKey(qualifier)) { list = map.get(qualifier); } else { map.put(qualifier, list); } list.add(version); } } // For each version list (there will be only 1 list if // useQualifierAsBranch==false), sort them accordingly from lower // version to higher version (so we can start deleting folders from // beginning of the list). for (String version : map.keySet()) { Collections.sort( map.get(version), useQualifierAsBranch ? VersionComparatorFactory .createHandleQualifiersSeparatelyComparator() : VersionComparatorFactory .createDefaultComparator()); } return map; } }