From 9fb2ac0f2bb1e512ff6d8a547486d90f5531f720 Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Mon, 20 Jun 2016 08:30:42 +0200 Subject: [PATCH] SONAR-7788 Improve PathResolver::relativePath(File, File) when arguments are not normalized --- .../api/scan/filesystem/PathResolver.java | 65 +++++++++++-------- .../api/scan/filesystem/PathResolverTest.java | 48 ++++++++++++-- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java index 555333fee7e..266abad42cb 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/scan/filesystem/PathResolver.java @@ -20,16 +20,15 @@ package org.sonar.api.scan.filesystem; import com.google.common.base.Joiner; -import com.google.common.base.Preconditions; -import org.sonar.api.batch.BatchSide; -import org.sonar.api.utils.PathUtils; - -import javax.annotation.CheckForNull; - import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.annotation.CheckForNull; +import org.apache.commons.io.FilenameUtils; +import org.sonar.api.batch.BatchSide; +import org.sonar.api.utils.PathUtils; /** * @since 3.5 @@ -38,16 +37,7 @@ import java.util.List; public class PathResolver { public File relativeFile(File dir, String path) { - Preconditions.checkArgument(dir.isDirectory(), "Not a directory: " + dir.getAbsolutePath()); - File file = new File(path); - if (!file.isAbsolute()) { - try { - file = new File(dir, path).getAbsoluteFile(); - } catch (Exception e) { - throw new IllegalStateException("Fail to resolve path '" + path + "' relative to: " + dir.getAbsolutePath(), e); - } - } - return file; + return dir.toPath().resolve(path).normalize().toFile(); } public List relativeFiles(File dir, List paths) { @@ -58,6 +48,10 @@ public class PathResolver { return result; } + /** + * @deprecated since 6.0 was used when component keys were relative to source dirs + */ + @Deprecated @CheckForNull public RelativePath relativePath(Collection dirs, File file) { List stack = new ArrayList<>(); @@ -73,19 +67,32 @@ public class PathResolver { return null; } + /** + * Similar to {@link Path#relativize(Path)} except that: + *
    + *
  • null is returned if file is not a child of dir + *
  • the resulting path is converted to use Unix separators + *
+ * @since 6.0 + */ @CheckForNull - public String relativePath(File dir, File file) { - List stack = new ArrayList<>(); - String dirPath = PathUtils.canonicalPath(dir); - File cursor = file; - while (cursor != null) { - if (dirPath.equals(PathUtils.canonicalPath(cursor))) { - return Joiner.on("/").join(stack); - } - stack.add(0, cursor.getName()); - cursor = cursor.getParentFile(); + public String relativePath(Path dir, Path file) { + Path baseDir = dir.normalize(); + Path path = file.normalize(); + if (!path.startsWith(baseDir)) { + return null; } - return null; + try { + Path relativized = baseDir.relativize(path); + return FilenameUtils.separatorsToUnix(relativized.toString()); + } catch (IllegalArgumentException e) { + return null; + } + } + + @CheckForNull + public String relativePath(File dir, File file) { + return relativePath(dir.toPath(), file.toPath()); } @CheckForNull @@ -98,6 +105,10 @@ public class PathResolver { return null; } + /** + * @deprecated since 6.0 was used when component keys were relative to source dirs + */ + @Deprecated public static final class RelativePath { private File dir; private String path; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/PathResolverTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/PathResolverTest.java index 1a29d917bb3..1693918ed82 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/PathResolverTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/scan/filesystem/PathResolverTest.java @@ -19,17 +19,18 @@ */ package org.sonar.api.scan.filesystem; -import org.apache.commons.io.FilenameUtils; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.List; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.SystemUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; public class PathResolverTest { @Rule @@ -90,6 +91,35 @@ public class PathResolverTest { assertThat(resolver.relativePath(rootDir, world)).isEqualTo("org/hello/World.java"); } + @Test + public void relative_path_for_not_normalized_dir() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + File file = new File(rootDir, "level1/../dir/file.c"); + + assertThat(resolver.relativePath(rootDir, file)).isEqualTo("dir/file.c"); + } + + @Test + public void relative_path_for_not_normalized_dir_sub_level() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + File file = new File(rootDir, "level1/level2/../dir/file.c"); + + assertThat(resolver.relativePath(rootDir, file)).isEqualTo("level1/dir/file.c"); + } + + @Test + public void relative_path_for_case_insensitive_fs() throws IOException { + assumeTrue(SystemUtils.IS_OS_WINDOWS); + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + File baseDir = new File(rootDir, "level1"); + File file = new File(baseDir, "../Level1/dir/file.c"); + + assertThat(resolver.relativePath(baseDir, file)).isEqualTo("dir/file.c"); + } + @Test public void relative_path_from_multiple_dirs() throws IOException { PathResolver resolver = new PathResolver(); @@ -142,6 +172,14 @@ public class PathResolverTest { assertThat(resolver.relativePath(rootDir, new File("Elsewhere.java"))).isNull(); } + @Test + public void null_relative_path_when_file_is_not_in_dir2() throws IOException { + PathResolver resolver = new PathResolver(); + File rootDir = temp.newFolder(); + + assertThat(resolver.relativePath(rootDir, new File(rootDir, "../Elsewhere.java"))).isNull(); + } + @Test public void supportSymlink() { PathResolver resolver = new PathResolver(); -- 2.39.5