001/*
002 * SonarQube
003 * Copyright (C) 2009-2017 SonarSource SA
004 * mailto:info AT sonarsource DOT com
005 *
006 * This program is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.batch.fs.internal;
021
022import java.nio.file.Path;
023import javax.annotation.concurrent.ThreadSafe;
024import org.apache.commons.io.FilenameUtils;
025import org.apache.commons.lang.StringUtils;
026import org.sonar.api.utils.PathUtils;
027import org.sonar.api.utils.WildcardPattern;
028import org.sonar.api.utils.log.Logger;
029import org.sonar.api.utils.log.Loggers;
030
031@ThreadSafe
032public abstract class PathPattern {
033
034  private static final Logger LOG = Loggers.get(PathPattern.class);
035
036  /**
037   * @deprecated since 6.6
038   */
039  @Deprecated
040  private static final String ABSOLUTE_PATH_PATTERN_PREFIX = "file:";
041  final WildcardPattern pattern;
042
043  PathPattern(String pattern) {
044    this.pattern = WildcardPattern.create(pattern);
045  }
046
047  public abstract boolean match(Path absolutePath, Path relativePath);
048
049  public abstract boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension);
050
051  public static PathPattern create(String s) {
052    String trimmed = StringUtils.trim(s);
053    if (StringUtils.startsWithIgnoreCase(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX)) {
054      LOG.warn("Using absolute path pattern is deprecated. Please use relative path instead of '" + trimmed + "'");
055      return new AbsolutePathPattern(StringUtils.substring(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX.length()));
056    }
057    return new RelativePathPattern(trimmed);
058  }
059
060  public static PathPattern[] create(String[] s) {
061    PathPattern[] result = new PathPattern[s.length];
062    for (int i = 0; i < s.length; i++) {
063      result[i] = create(s[i]);
064    }
065    return result;
066  }
067
068  /**
069   * @deprecated since 6.6
070   */
071  @Deprecated
072  private static class AbsolutePathPattern extends PathPattern {
073    private AbsolutePathPattern(String pattern) {
074      super(pattern);
075    }
076
077    @Override
078    public boolean match(Path absolutePath, Path relativePath) {
079      return match(absolutePath, relativePath, true);
080    }
081
082    @Override
083    public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) {
084      String path = PathUtils.sanitize(absolutePath.toString());
085      if (!caseSensitiveFileExtension) {
086        String extension = sanitizeExtension(FilenameUtils.getExtension(path));
087        if (StringUtils.isNotBlank(extension)) {
088          path = StringUtils.removeEndIgnoreCase(path, extension);
089          path = path + extension;
090        }
091      }
092      return pattern.match(path);
093    }
094
095    @Override
096    public String toString() {
097      return ABSOLUTE_PATH_PATTERN_PREFIX + pattern.toString();
098    }
099  }
100
101  /**
102   * Path relative to module basedir
103   */
104  private static class RelativePathPattern extends PathPattern {
105    private RelativePathPattern(String pattern) {
106      super(pattern);
107    }
108
109    @Override
110    public boolean match(Path absolutePath, Path relativePath) {
111      return match(absolutePath, relativePath, true);
112    }
113
114    @Override
115    public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) {
116      String path = PathUtils.sanitize(relativePath.toString());
117      if (!caseSensitiveFileExtension) {
118        String extension = sanitizeExtension(FilenameUtils.getExtension(path));
119        if (StringUtils.isNotBlank(extension)) {
120          path = StringUtils.removeEndIgnoreCase(path, extension);
121          path = path + extension;
122        }
123      }
124      return path != null && pattern.match(path);
125    }
126
127    @Override
128    public String toString() {
129      return pattern.toString();
130    }
131  }
132
133  static String sanitizeExtension(String suffix) {
134    return StringUtils.lowerCase(StringUtils.removeStart(suffix, "."));
135  }
136}