/* * RHQ Management Platform * Copyright (C) 2005-2009 Red Hat, Inc. * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2, as * published by the Free Software Foundation, and/or the GNU Lesser * General Public License, version 2.1, also as published by the Free * Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License and the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.rhq.augeas.util; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A helper class for easy work with glob patterns. * * @author Lukas Krejci */ public class Glob { private static final Log log = LogFactory.getLog(Glob.class); public static final Comparator<File> ALPHABETICAL_COMPARATOR = new Comparator<File>() { public int compare(File o1, File o2) { String path1 = o1.getAbsolutePath(); String path2 = o2.getAbsolutePath(); return path1.compareTo(path2); } }; private Glob() { } /** * Checks whether the provided string is a wildcard glob pattern. * * @param globPattern * @return */ public static boolean isWildcard(String globPattern) { for(char specialChar : GlobFilter.WILDCARD_CHARS) { if (globPattern.indexOf(specialChar) >= 0) return true; } return false; } /** * Checks if the file matches the glob pattern with given path as a root of the filesystem. * * If the glob pattern denotes an absolute path, it is understood to be under the supplied * fs root. * * @param rootPath * @param globPattern * @param file * @return */ public static boolean matches(File rootPath, String globPattern, File file) { String rootPortion = rootPortion(globPattern); globPattern = globPattern.substring(rootPortion.length()); globPattern = new File(rootPath, globPattern).getAbsolutePath(); return new GlobFilter(globPattern).accept(file); } /** * This is an overloaded version of the {@link #match(File, String, Comparator)} method * that passes <code>null</code> as the comparator to use. * * @see #match(File, String, Comparator) */ public static List<File> match(File parentPath, String globPattern) { return match(parentPath, globPattern, null); } /** * Returns a fixed size list of matches. * * The parent path specifies the "root" from which the glob pattern applies. * The glob pattern can span several directories with wildcards present only * on the lowest level. * The glob pattern is always relative to the specified parent path, even if it denotes * an absolute path. In that case, the leading root path is chopped off and the rest is * appended to the parent path. * * @param parentPath the parent path to start the pattern search * @param globPattern the glob pattern to match against * @param resultComparator the comparator using which to sort the results or null if no sorting is necessary * @return the list of matches */ public static List<File> match(File parentPath, String globPattern, Comparator<? super File> resultComparator) { if (!parentPath.exists()) { throw new IllegalArgumentException("Path '" + parentPath + "' does not exist."); } if (!parentPath.isDirectory()) { throw new IllegalArgumentException("Path '" + parentPath + "' is not a directory."); } String rootPortion = rootPortion(globPattern); globPattern = globPattern.substring(rootPortion.length()); //now search for the first special character in the patterns int specialCharIdx = globPattern.length(); for(char specialChar : GlobFilter.WILDCARD_CHARS) { int idx = globPattern.indexOf(specialChar); if (idx >= 0 && specialCharIdx > idx) { specialCharIdx = idx; } } if (specialCharIdx > 0) { //now search for the first path separator preceding the special char int globParentIdx = globPattern.lastIndexOf(File.separatorChar, specialCharIdx); if (globParentIdx > 0) { //move the parent path down to the nearest parent of the wildcard part of the //glob pattern parentPath = new File(parentPath, globPattern.substring(0, globParentIdx)); globPattern = createGlobPattern(parentPath.getAbsolutePath(), globPattern.substring(globParentIdx)); } else { globPattern = createGlobPattern(parentPath.getAbsolutePath(),globPattern); } } else { globPattern = createGlobPattern(parentPath.getAbsolutePath(),globPattern); } globPattern = new File(globPattern).getAbsolutePath(); File[] files = parentPath.listFiles(new GlobFilter(globPattern)); if (files == null) { log.debug("Could list files in " + parentPath); return Collections.emptyList(); } if (resultComparator != null) { Arrays.sort(files, resultComparator); } return Arrays.asList(files); } private static String createGlobPattern(String parent,String pattern){ if (!parent.endsWith(File.separator)) parent = parent + File.separatorChar; return parent+pattern; } /** * This is an overloaded version of the {@link #matchAll(File, List, Comparator)} method * that passes <code>null</code> as the comparator to use. * * @see #matchAll(File, List, Comparator) */ public static List<File> matchAll(File parentPath, List<String> globPatterns) { return matchAll(parentPath, globPatterns, null); } public static List<File> matchAll(File parentPath, List<String> globPatterns, Comparator<? super File> resultComparator) { ArrayList<File> matches = new ArrayList<File>(); for(String p : globPatterns) { matches.addAll(match(parentPath, p, null)); } if (resultComparator != null) { Collections.sort(matches, resultComparator); } return matches; } public static void exclude(List<File> matches, String globPattern) { GlobFilter filter = new GlobFilter(globPattern); Iterator<File> it = matches.iterator(); while (it.hasNext()) { if (filter.accept(it.next())) { it.remove(); } } } public static void excludeAll(List<File> matches, String... globPattern) { excludeAll(matches, Arrays.asList(globPattern)); } public static void excludeAll(List<File> matches, List<String> globPatterns) { for(String p : globPatterns) { exclude(matches, p); } } public static String rootPortion(String path) { // On Windows, make sure we have the correct drive letter format and slash direction for comparison. if (File.separator.equals("\\")) { try { File f = new File(path); path = f.isAbsolute() ? f.getCanonicalPath() : f.getPath(); } catch (Exception e) { // should not happen but just leave path as-is } } File[] roots = File.listRoots(); if (roots != null) { for (File root : roots) { if (path.startsWith(root.getPath())) { return root.getPath(); } } } else { log.warn("Could not determine file system roots. This is strange."); } return ""; } }