001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube 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 * SonarQube 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.scan.filesystem;
021
022import com.google.common.base.Joiner;
023import com.google.common.base.Preconditions;
024import com.google.common.collect.Lists;
025import org.sonar.api.BatchComponent;
026import org.sonar.api.utils.PathUtils;
027
028import javax.annotation.CheckForNull;
029
030import java.io.File;
031import java.util.Collection;
032import java.util.List;
033
034/**
035 * @since 3.5
036 */
037public class PathResolver implements BatchComponent {
038
039  public File relativeFile(File dir, String path) {
040    Preconditions.checkArgument(dir.isDirectory(), "Not a directory: " + dir.getAbsolutePath());
041    File file = new File(path);
042    if (!file.isAbsolute()) {
043      try {
044        file = new File(dir, path).getAbsoluteFile();
045      } catch (Exception e) {
046        throw new IllegalStateException("Fail to resolve path '" + path + "' relative to: " + dir.getAbsolutePath(), e);
047      }
048    }
049    return file;
050  }
051
052  public List<File> relativeFiles(File dir, List<String> paths) {
053    List<File> result = Lists.newArrayList();
054    for (String path : paths) {
055      result.add(relativeFile(dir, path));
056    }
057    return result;
058  }
059
060  @CheckForNull
061  public RelativePath relativePath(Collection<File> dirs, File file) {
062    List<String> stack = Lists.newArrayList();
063    File cursor = file;
064    while (cursor != null) {
065      File parentDir = parentDir(dirs, cursor);
066      if (parentDir != null) {
067        return new RelativePath(parentDir, Joiner.on("/").join(stack));
068      }
069      stack.add(0, cursor.getName());
070      cursor = cursor.getParentFile();
071    }
072    return null;
073  }
074
075  @CheckForNull
076  public String relativePath(File dir, File file) {
077    List<String> stack = Lists.newArrayList();
078    String dirPath = PathUtils.canonicalPath(dir);
079    File cursor = file;
080    while (cursor != null) {
081      if (dirPath.equals(PathUtils.canonicalPath(cursor))) {
082        return Joiner.on("/").join(stack);
083      }
084      stack.add(0, cursor.getName());
085      cursor = cursor.getParentFile();
086    }
087    return null;
088  }
089
090  @CheckForNull
091  private File parentDir(Collection<File> dirs, File cursor) {
092    for (File dir : dirs) {
093      if (PathUtils.canonicalPath(dir).equals(PathUtils.canonicalPath(cursor))) {
094        return dir;
095      }
096    }
097    return null;
098  }
099
100  public static final class RelativePath {
101    private File dir;
102    private String path;
103
104    public RelativePath(File dir, String path) {
105      this.dir = dir;
106      this.path = path;
107    }
108
109    public File dir() {
110      return dir;
111    }
112
113    public String path() {
114      return path;
115    }
116  }
117}