Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make UnionPath behave as paths from ZipFileSystem do. #26

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions src/main/java/cpw/mods/jarhandling/impl/JarContentsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private Map<Path, Integer> readMultiReleaseInfo() {
return Map.of();
}

var vers = filesystem.getRoot().resolve("META-INF/versions");
var vers = filesystem.getPath("").resolve("META-INF/versions");
try (var walk = Files.walk(vers)) {
Map<Path, Integer> pathToJavaVersion = new HashMap<>();
walk
Expand Down Expand Up @@ -161,7 +161,7 @@ public Set<String> getPackagesExcluding(String... excludedRootPackages) {

Set<String> packages = new HashSet<>();
try {
Files.walkFileTree(this.filesystem.getRoot(), new SimpleFileVisitor<>() {
Files.walkFileTree(this.filesystem.getPath(""), new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (file.getFileName().toString().endsWith(".class") && attrs.isRegularFile()) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/cpw/mods/niofs/union/UnionFileSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ public DirectoryStream<Path> newDirStream(final UnionPath path, final DirectoryS
closeables.add(ds);
final var currentPaths = StreamSupport.stream(ds.spliterator(), false)
.filter(p -> testFilter(p, bp))
.map(other -> fastPath(isSimple ? other : bp.relativize(other)));
.map(other -> fastPath(isSimple ? other : bp.toAbsolutePath().relativize(other.toAbsolutePath())));
stream = Stream.concat(stream, currentPaths);
}
final Stream<Path> realStream = stream.distinct();
Expand Down Expand Up @@ -452,7 +452,7 @@ private boolean testFilter(final Path path, final Path basePath) {

var sPath = path.toString();
if (path.getFileSystem() == basePath.getFileSystem()) // Directories, zips will be different file systems.
sPath = basePath.relativize(path).toString().replace('\\', '/');
sPath = basePath.toAbsolutePath().relativize(path.toAbsolutePath()).toString().replace('\\', '/');
if (Files.isDirectory(path))
sPath += '/';
if (sPath.length() > 1 && sPath.startsWith("/"))
Expand Down
69 changes: 39 additions & 30 deletions src/main/java/cpw/mods/niofs/union/UnionPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
import java.util.Deque;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.function.IntBinaryOperator;
import java.util.stream.IntStream;

public class UnionPath implements Path {
private final UnionFileSystem fileSystem;
private final boolean absolute;
private final boolean empty;
private final String[] pathParts;

// Store the normalized path after it has been created first
Expand All @@ -31,7 +31,8 @@ public class UnionPath implements Path {
this.fileSystem = fileSystem;
if (pathParts.length == 0) {
this.absolute = false;
this.pathParts = new String[0];
this.pathParts = new String[]{ "" };
this.empty = true;
} else {
StringBuilder joiner = new StringBuilder();
for (int i = 0; i < pathParts.length; i++) {
Expand All @@ -43,7 +44,8 @@ public class UnionPath implements Path {
}
final var longstring = joiner.toString();
this.absolute = longstring.startsWith(UnionFileSystem.SEP_STRING);
this.pathParts = getPathParts(longstring);
this.pathParts = getPathParts(this.absolute, longstring);
this.empty = !this.absolute && this.pathParts.length == 1 && this.pathParts[0].isEmpty();
}
this.normalized = null;
}
Expand All @@ -55,15 +57,22 @@ public class UnionPath implements Path {

private UnionPath(final UnionFileSystem fileSystem, boolean absolute, boolean isNormalized, final String... pathParts) {
this.fileSystem = fileSystem;
this.absolute = absolute;
this.pathParts = pathParts;
if (isNormalized)
this.normalized = this;
else
this.normalized = null;
if (!absolute && (pathParts.length == 0 || (pathParts.length == 1 && pathParts[0].isEmpty()))) {
this.absolute = false;
this.pathParts = new String[]{ "" };
this.empty = true;
} else {
this.absolute = absolute;
this.empty = false;
this.pathParts = pathParts;
if (isNormalized)
this.normalized = this;
else
this.normalized = null;
}
}

private String[] getPathParts(final String longstring) {
private String[] getPathParts(final boolean isAbsolute, final String longstring) {
var clean = longstring.replace('\\', '/');
int startIndex = 0;
List<String> parts = new ArrayList<>();
Expand All @@ -79,7 +88,11 @@ private String[] getPathParts(final String longstring) {
}
startIndex = (index + 1);
}
return parts.toArray(String[]::new);
if (parts.isEmpty() && !isAbsolute) {
return new String[]{ "" };
} else {
return parts.toArray(String[]::new);
}
}

@Override
Expand All @@ -94,28 +107,25 @@ public boolean isAbsolute() {

@Override
public Path getRoot() {
// Found nothing in the docs that say a non-absolute path can't have a root
// although this is uncommon. However, other stuff relies on it so leave it
//if (!this.absolute)
// return null;
if (!this.absolute)
return null;
return this.fileSystem.getRoot();
}

@Override
public Path getFileName() {
if (this.pathParts.length > 0) {
if (this.empty) {
return null;
} else if (this.pathParts.length > 0) {
return new UnionPath(this.getFileSystem(), false, this.pathParts[this.pathParts.length - 1]);
} else {
// normally would be null for the empty absolute path and empty string for the empty relative
// path. But again, very much stuff relies on it and there's no current directory for union
// paths, so it does not really matter.
return new UnionPath(this.fileSystem, false);
return this.absolute ? null : new UnionPath(this.fileSystem, false);
}
}

@Override
public Path getParent() {
if (this.pathParts.length > 0) {
if (this.pathParts.length > 1 || (this.absolute && this.pathParts.length == 1)) {
return new UnionPath(this.fileSystem, this.absolute, Arrays.copyOf(this.pathParts,this.pathParts.length - 1));
} else {
return null;
Expand Down Expand Up @@ -193,10 +203,10 @@ public Path normalize() {
case ".":
break;
case "..":
if (normpath.isEmpty() || normpath.getLast().equals("..")) {
// .. on an empty path is allowed, so keep it
if (!this.absolute && (normpath.isEmpty() || normpath.getLast().equals(".."))) {
// .. on an empty path is allowed as long as it is not absolute, so keep it
normpath.addLast(pathPart);
} else {
} else if (!normpath.isEmpty()) {
normpath.removeLast();
}
break;
Expand All @@ -212,9 +222,12 @@ public Path normalize() {
@Override
public Path resolve(final Path other) {
if (other instanceof UnionPath path) {
if (path.isAbsolute()) {
if (path.isAbsolute() || this.empty) {
return path;
}
if (path.empty) {
return this;
}
String[] mergedParts = new String[this.pathParts.length + path.pathParts.length];
System.arraycopy(this.pathParts, 0, mergedParts, 0, this.pathParts.length);
System.arraycopy(path.pathParts, 0, mergedParts, this.pathParts.length, path.pathParts.length);
Expand All @@ -228,11 +241,7 @@ public Path relativize(final Path other) {
if (other.getFileSystem()!=this.getFileSystem()) throw new IllegalArgumentException("Wrong filesystem");
if (other instanceof UnionPath p) {
if (this.absolute != p.absolute) {
// Should not be allowed but union fs relies on it
// also there is no such concept of a current directory for union paths
// meaning absolute and relative paths should have the same effect,
// so we just allow this.
//throw new IllegalArgumentException("Different types of path");
throw new IllegalArgumentException("Different types of path");
}
var length = Math.min(this.pathParts.length, p.pathParts.length);
int i = 0;
Expand Down
56 changes: 3 additions & 53 deletions src/test/java/cpw/mods/niofs/union/TestUnionFS.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
import static org.junit.jupiter.api.Assertions.assertTrue;

public class TestUnionFS {

private static final UnionFileSystemProvider UFSP = (UnionFileSystemProvider) FileSystemProvider.installedProviders().stream().filter(fsp->fsp.getScheme().equals("union")).findFirst().orElseThrow(()->new IllegalStateException("Couldn't find UnionFileSystemProvider"));

@Test
void testUnionFileSystem() throws IOException {
final var dir1 = Paths.get("src", "test", "resources", "dir1").toAbsolutePath().normalize();
Expand Down Expand Up @@ -72,65 +74,13 @@ void testUnionFileSystemJar() throws Throwable {
var doexist = List.of("cpw/mods/niofs/union/UnionPath.class", "net/minecraftforge/client/event/GuiOpenEvent.class", "cpw/mods/modlauncher/Launcher.class"); //jar 3
var dontexist = List.of("cpw/mods/modlauncher/api/NoIDontExist.class", "net/minecraftforge/client/nonexistent/Nope.class", "Missing.class");
assertAll(
doexist.stream().map(ufs::getPath).map(p->()->assertTrue(Files.exists(p)))
doexist.stream().map(ufs::getPath).map(p->()->assertTrue(Files.exists(p)))
);
assertAll(
dontexist.stream().map(ufs::getPath).map(p->()->assertTrue(Files.notExists(p)))
);
}

@Test
void testRelativize() {
final var dir1 = Paths.get("src", "test", "resources", "dir1").toAbsolutePath().normalize();
final var dir2 = Paths.get("src", "test", "resources", "dir2").toAbsolutePath().normalize();

var fsp = (UnionFileSystemProvider)FileSystemProvider.installedProviders().stream().filter(fs-> fs.getScheme().equals("union")).findFirst().orElseThrow();
var ufs = fsp.newFileSystem((path, base) -> true, dir1, dir2);
var p1 = ufs.getPath("path1");
var p123 = ufs.getPath("path1/path2/path3");
var p11 = ufs.getPath("path1/path1");
var p12 = ufs.getPath("path1/path2");
var p13 = ufs.getPath("path1/path3");
var p23 = ufs.getPath("path2/path3");
var p13plus = ufs.getPath("path1/path3");
assertAll(
()->assertEquals("path2/path3", p1.relativize(p123).toString()),
()->assertEquals("../..", p123.relativize(p1).toString()),
()->assertEquals("path1", p1.relativize(p11).toString()),
()->assertEquals("path2", p1.relativize(p12).toString()),
()->assertEquals("path3", p1.relativize(p13).toString()),
()->assertEquals("../../path1/path1", p23.relativize(p11).toString()),
()->assertEquals("../../path1", p123.relativize(p11).toString()),
()->assertEquals(0, p13.relativize(p13plus).getNameCount())
);
}

@Test
void testRelativizeAbsolute() {
final var dir1 = Paths.get("src", "test", "resources", "dir1").toAbsolutePath().normalize();
final var dir2 = Paths.get("src", "test", "resources", "dir2").toAbsolutePath().normalize();

var fsp = (UnionFileSystemProvider)FileSystemProvider.installedProviders().stream().filter(fs-> fs.getScheme().equals("union")).findFirst().orElseThrow();
var ufs = fsp.newFileSystem((path, base) -> true, dir1, dir2);
var p1 = ufs.getPath("/path1");
var p123 = ufs.getPath("/path1/path2/path3");
var p11 = ufs.getPath("/path1/path1");
var p12 = ufs.getPath("/path1/path2");
var p13 = ufs.getPath("/path1/path3");
var p23 = ufs.getPath("/path2/path3");
var p13plus = ufs.getPath("/path1/path3");
assertAll(
()->assertEquals("path2/path3", p1.relativize(p123).toString()),
()->assertEquals("../..", p123.relativize(p1).toString()),
()->assertEquals("path1", p1.relativize(p11).toString()),
()->assertEquals("path2", p1.relativize(p12).toString()),
()->assertEquals("path3", p1.relativize(p13).toString()),
()->assertEquals("../../path1/path1", p23.relativize(p11).toString()),
()->assertEquals("../../path1", p123.relativize(p11).toString()),
()->assertEquals(0, p13.relativize(p13plus).getNameCount())
);
}

@Test
void testPathFiltering() {
final var dir1 = Paths.get("src", "test", "resources", "dir1").toAbsolutePath().normalize();
Expand Down
Loading