All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dockerjava.core.GoLangFileMatch Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
/**
 * Copyright (C) 2014 SignalFuse, Inc.
 */
package com.github.dockerjava.core;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import org.apache.commons.lang3.StringUtils;

import com.github.dockerjava.core.exception.GoLangFileMatchException;

/**
 * Implementation of golang's file.Match
 *
 * Match returns true if name matches the shell file name pattern. The pattern syntax is:
 *
 * 
 *  pattern:
 *          { term }
 *   term:
 *       '*'         matches any sequence of non-Separator characters
 *      '?'         matches any single non-Separator character
 *       '[' [ '^' ] { character-range } ']'
 *                  character class (must be non-empty)
 *       c           matches character c (c != '*', '?', '\\', '[')
 *       '\\' c      matches character c
 *
 *   character-range:
 *       c           matches character c (c != '\\', '-', ']')
 *       '\\' c      matches character c
 *       lo '-' hi   matches character c for lo <= c <= hi
 *
 *  Match requires pattern to match all of name, not just a substring.
 *  The only possible returned error is ErrBadPattern, when pattern
 *  is malformed.
 *
 * On Windows, escaping is disabled. Instead, '\\' is treated as
 AuthConfigTest *  path separator.
 * 
* * @author tedo * */ public class GoLangFileMatch { private GoLangFileMatch() { } public static final boolean IS_WINDOWS = File.separatorChar == '\\'; private static final String PATTERN_CHARS_TO_ESCAPE = "\\.[]{}()*+-?^$|"; private static final LoadingCache PATTERN_CACHE = CacheBuilder.newBuilder() .expireAfterAccess(1, TimeUnit.HOURS) .maximumSize(10_000) .build(CacheLoader.from(GoLangFileMatch::buildPattern)); public static boolean match(List patterns, File file) { return !match(patterns, file.getPath()).isEmpty(); } public static boolean match(String pattern, File file) { return match(pattern, file.getPath()); } /** * Returns the matching patterns for the given string */ public static List match(List patterns, String name) { List matches = new ArrayList<>(); for (String pattern : patterns) { if (match(pattern, name)) { matches.add(pattern); } } return matches; } public static boolean match(String pattern, String name) { try { return PATTERN_CACHE.get(pattern).matcher(name).matches(); } catch (ExecutionException | UncheckedExecutionException e) { throw new GoLangFileMatchException(e.getCause().getMessage()); } } private static Pattern buildPattern(String pattern) { StringBuilder patternStringBuilder = new StringBuilder("^"); while (!pattern.isEmpty()) { pattern = appendChunkPattern(patternStringBuilder, pattern); if (!pattern.isEmpty()) { patternStringBuilder.append(quote(File.separatorChar)); } } patternStringBuilder.append("(").append(quote(File.separatorChar)).append(".*").append(")?"); return Pattern.compile(patternStringBuilder.toString()); } private static String quote(char separatorChar) { if (StringUtils.contains(PATTERN_CHARS_TO_ESCAPE, separatorChar)) { return "\\" + separatorChar; } else { return String.valueOf(separatorChar); } } private static String appendChunkPattern(StringBuilder patternStringBuilder, String pattern) { if (pattern.equals("**") || pattern.startsWith("**" + File.separator)) { patternStringBuilder.append("(") .append("[^").append(quote(File.separatorChar)).append("]*") .append("(") .append(quote(File.separatorChar)).append("[^").append(quote(File.separatorChar)).append("]*") .append(")*").append(")?"); return pattern.substring(pattern.length() == 2 ? 2 : 3); } boolean inRange = false; int rangeFrom = 0; RangeParseState rangeParseState = RangeParseState.CHAR_EXPECTED; boolean isEsc = false; int i; for (i = 0; i < pattern.length(); i++) { char c = pattern.charAt(i); switch (c) { case '/': if (!inRange) { if (!IS_WINDOWS && !isEsc) { // end of chunk return pattern.substring(i + 1); } else { patternStringBuilder.append(quote(c)); } } else { rangeParseState = nextStateAfterChar(rangeParseState); } isEsc = false; break; case '\\': if (!inRange) { if (!IS_WINDOWS) { if (isEsc) { patternStringBuilder.append(quote(c)); isEsc = false; } else { isEsc = true; } } else { // end of chunk return pattern.substring(i + 1); } } else { if (IS_WINDOWS || isEsc) { rangeParseState = nextStateAfterChar(rangeParseState); isEsc = false; } else { isEsc = true; } } break; case '[': if (!isEsc) { if (inRange) { throw new GoLangFileMatchException("[ not expected, closing bracket ] not yet reached"); } rangeFrom = i; rangeParseState = RangeParseState.CHAR_EXPECTED; inRange = true; } else { if (!inRange) { patternStringBuilder.append(c); } else { rangeParseState = nextStateAfterChar(rangeParseState); } } isEsc = false; break; case ']': if (!isEsc) { if (!inRange) { throw new GoLangFileMatchException("] is not expected, [ was not met"); } if (rangeParseState == RangeParseState.CHAR_EXPECTED_AFTER_DASH) { throw new GoLangFileMatchException("Character range not finished"); } patternStringBuilder.append(pattern.substring(rangeFrom, i + 1)); inRange = false; } else { if (!inRange) { patternStringBuilder.append(c); } else { rangeParseState = nextStateAfterChar(rangeParseState); } } isEsc = false; break; case '*': if (!inRange) { if (!isEsc) { patternStringBuilder.append("[^").append(quote(File.separatorChar)).append("]*"); } else { patternStringBuilder.append(quote(c)); } } else { rangeParseState = nextStateAfterChar(rangeParseState); } isEsc = false; break; case '?': if (!inRange) { if (!isEsc) { patternStringBuilder.append("[^").append(quote(File.separatorChar)).append("]"); } else { patternStringBuilder.append(quote(c)); } } else { rangeParseState = nextStateAfterChar(rangeParseState); } isEsc = false; break; case '-': if (!inRange) { patternStringBuilder.append(quote(c)); } else { if (!isEsc) { if (rangeParseState != RangeParseState.CHAR_OR_DASH_EXPECTED) { throw new GoLangFileMatchException("- character not expected"); } rangeParseState = RangeParseState.CHAR_EXPECTED_AFTER_DASH; } else { rangeParseState = nextStateAfterChar(rangeParseState); } } isEsc = false; break; default: if (!inRange) { patternStringBuilder.append(quote(c)); } else { rangeParseState = nextStateAfterChar(rangeParseState); } isEsc = false; } } if (isEsc) { throw new GoLangFileMatchException("Escaped character missing"); } if (inRange) { throw new GoLangFileMatchException("Character range not finished"); } return ""; } private static RangeParseState nextStateAfterChar(RangeParseState currentState) { if (currentState == RangeParseState.CHAR_EXPECTED_AFTER_DASH) { return RangeParseState.CHAR_EXPECTED; } else { return RangeParseState.CHAR_OR_DASH_EXPECTED; } } private enum RangeParseState { CHAR_EXPECTED, CHAR_OR_DASH_EXPECTED, CHAR_EXPECTED_AFTER_DASH } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy