Fixed an issue where upwards resolved schematics would break schem list (#1481)

* Fixed an issue where upwards resolved schematics would break schem list

* Missed diff

* PR changes

* Further fixes

* Improve sorting logic

* Pass in comparator rather than using sort type

Co-authored-by: Octavia Togami <octavia.togami@gmail.com>
This commit is contained in:
Matthew Miller 2020-08-13 18:01:37 +10:00 committed by GitHub
parent e0718dd319
commit 0a9fa869c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 156 additions and 107 deletions

View File

@ -25,6 +25,7 @@
import org.slf4j.LoggerFactory;
import java.io.File;
import java.nio.file.Path;
/**
* YAMLConfiguration but with setting for no op permissions and plugin root data folder.
@ -68,7 +69,7 @@ private void migrate(String file, String name) {
}
@Override
public File getWorkingDirectory() {
return plugin.getDataFolder();
public Path getWorkingDirectoryPath() {
return plugin.getDataFolder().toPath();
}
}

View File

@ -21,12 +21,12 @@
import com.sk89q.worldedit.util.PropertiesConfiguration;
import java.io.File;
import java.nio.file.Path;
public class CLIConfiguration extends PropertiesConfiguration {
public CLIConfiguration(CLIWorldEdit app) {
super(app.getWorkingDir().resolve("worldedit.properties").toFile());
super(app.getWorkingDir().resolve("worldedit.properties"));
}
@Override
@ -34,7 +34,7 @@ protected void loadExtra() {
}
@Override
public File getWorkingDirectory() {
return CLIWorldEdit.inst.getWorkingDir().toFile();
public Path getWorkingDirectoryPath() {
return CLIWorldEdit.inst.getWorkingDir();
}
}
}

View File

@ -34,6 +34,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.List;
@ -169,9 +170,20 @@ protected String[] getDefaultDisallowedBlocks() {
* Get the working directory to work from.
*
* @return a working directory
* @deprecated Use {@link LocalConfiguration#getWorkingDirectoryPath()}
*/
@Deprecated
public File getWorkingDirectory() {
return new File(".");
return getWorkingDirectoryPath().toFile();
}
/**
* Get the working directory to work from.
*
* @return a working directory
*/
public Path getWorkingDirectoryPath() {
return Paths.get(".");
}
public void initializeSnapshotConfiguration(String directory, boolean experimental) {

View File

@ -426,14 +426,27 @@ public void checkMaxBrushRadius(double radius) throws MaxBrushRadiusException {
*
* @param path the subpath under the working directory
* @return a working directory
* @deprecated Use {@link WorldEdit#getWorkingDirectoryPath(String)} instead
*/
@Deprecated
public File getWorkingDirectoryFile(String path) {
File f = new File(path);
if (f.isAbsolute()) {
return f;
return getWorkingDirectoryPath(path).toFile();
}
/**
* Get a file relative to the defined working directory. If the specified
* path is absolute, then the working directory is not used.
*
* @param path the subpath under the working directory
* @return a working directory
*/
public Path getWorkingDirectoryPath(String path) {
Path p = Paths.get(path);
if (p.isAbsolute()) {
return p;
}
return new File(getConfiguration().getWorkingDirectory(), path);
return getConfiguration().getWorkingDirectoryPath().resolve(path);
}
/**

View File

@ -49,7 +49,6 @@
import org.enginehub.piston.annotation.param.ArgFlag;
import org.enginehub.piston.exception.StopExecutionException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -122,12 +121,11 @@ public void deleteChunks(Actor actor, World world, LocalSession session,
throw new StopExecutionException(TextComponent.of("Couldn't find world folder for this world."));
}
File chunkFile = worldEdit.getWorkingDirectoryFile(DELCHUNKS_FILE_NAME);
Path chunkPath = chunkFile.toPath();
Path chunkPath = worldEdit.getWorkingDirectoryPath(DELCHUNKS_FILE_NAME);
ChunkDeletionInfo currentInfo = null;
if (Files.exists(chunkPath)) {
try {
currentInfo = ChunkDeleter.readInfo(chunkFile.toPath());
currentInfo = ChunkDeleter.readInfo(chunkPath);
} catch (IOException e) {
throw new StopExecutionException(TextComponent.of("Error reading existing chunk file."));
}

View File

@ -20,8 +20,7 @@
package com.sk89q.worldedit.command;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import com.google.common.io.MoreFiles;
import com.sk89q.worldedit.LocalConfiguration;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
@ -30,7 +29,6 @@
import com.sk89q.worldedit.command.util.CommandPermissions;
import com.sk89q.worldedit.command.util.CommandPermissionsConditionGenerator;
import com.sk89q.worldedit.command.util.WorldEditAsyncCommandBuilder;
import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
@ -54,6 +52,7 @@
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.io.Closer;
import com.sk89q.worldedit.util.io.file.FilenameException;
import com.sk89q.worldedit.util.io.file.MorePaths;
import org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
@ -70,11 +69,13 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
@ -110,7 +111,7 @@ public void load(Actor actor, LocalSession session,
String formatName) throws FilenameException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile();
File f = worldEdit.getSafeOpenFile(actor, dir, filename,
BuiltInClipboardFormat.SPONGE_SCHEMATIC.getPrimaryFileExtension(),
ClipboardFormats.getFileExtensionArray());
@ -155,7 +156,7 @@ public void save(Actor actor, LocalSession session,
boolean allowOverwrite) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile();
ClipboardFormat format = ClipboardFormats.findByAlias(formatName);
if (format == null) {
@ -206,9 +207,9 @@ public void delete(Actor actor,
@Arg(desc = "File name.")
String filename) throws WorldEditException {
LocalConfiguration config = worldEdit.getConfiguration();
File dir = worldEdit.getWorkingDirectoryFile(config.saveDir);
File dir = worldEdit.getWorkingDirectoryPath(config.saveDir).toFile();
File f = worldEdit.getSafeOpenFile(actor instanceof Player ? ((Player) actor) : null,
File f = worldEdit.getSafeOpenFile(actor,
dir, filename, "schematic", ClipboardFormats.getFileExtensionArray());
if (!f.exists()) {
@ -272,12 +273,24 @@ public void list(Actor actor,
throw new StopExecutionException(TextComponent.of("Cannot sort by oldest and newest."));
}
final String saveDir = worldEdit.getConfiguration().saveDir;
Comparator<Path> pathComparator;
String flag;
if (oldFirst) {
pathComparator = MorePaths.oldestFirst();
flag = " -d";
} else if (newFirst) {
pathComparator = MorePaths.newestFirst();
flag = " -n";
} else {
pathComparator = Comparator.naturalOrder();
flag = "";
}
final int sortType = oldFirst ? -1 : newFirst ? 1 : 0;
final String pageCommand = actor.isPlayer()
? "//schem list -p %page%" + (sortType == -1 ? " -d" : sortType == 1 ? " -n" : "") : null;
? "//schem list -p %page%" + flag : null;
WorldEditAsyncCommandBuilder.createAndSendMessage(actor,
new SchematicListTask(saveDir, sortType, page, pageCommand),
new SchematicListTask(saveDir, pathComparator, page, pageCommand),
SubtleFormat.wrap("(Please wait... gathering schematic list.)"));
}
@ -353,95 +366,75 @@ public Void call() throws Exception {
}
private static class SchematicListTask implements Callable<Component> {
private final String prefix;
private final int sortType;
private final Comparator<Path> pathComparator;
private final int page;
private final File rootDir;
private final Path rootDir;
private final String pageCommand;
SchematicListTask(String prefix, int sortType, int page, String pageCommand) {
this.prefix = prefix;
this.sortType = sortType;
SchematicListTask(String prefix, Comparator<Path> pathComparator, int page, String pageCommand) {
this.pathComparator = pathComparator;
this.page = page;
this.rootDir = WorldEdit.getInstance().getWorkingDirectoryFile(prefix);
this.rootDir = WorldEdit.getInstance().getWorkingDirectoryPath(prefix);
this.pageCommand = pageCommand;
}
@Override
public Component call() throws Exception {
List<File> fileList = allFiles(rootDir);
Path resolvedRoot = rootDir.toRealPath();
List<Path> fileList = allFiles(resolvedRoot);
if (fileList == null || fileList.isEmpty()) {
if (fileList.isEmpty()) {
return ErrorFormat.wrap("No schematics found.");
}
File[] files = new File[fileList.size()];
fileList.toArray(files);
// cleanup file list
Arrays.sort(files, (f1, f2) -> {
// http://stackoverflow.com/questions/203030/best-way-to-list-files-in-java-sorted-by-date-modified
int res;
if (sortType == 0) { // use name by default
int p = f1.getParent().compareTo(f2.getParent());
if (p == 0) { // same parent, compare names
res = f1.getName().compareTo(f2.getName());
} else { // different parent, sort by that
res = p;
}
} else {
res = Long.compare(f1.lastModified(), f2.lastModified()); // use date if there is a flag
if (sortType == 1) {
res = -res; // flip date for newest first instead of oldest first
}
}
return res;
});
fileList.sort(pathComparator);
PaginationBox paginationBox = new SchematicPaginationBox(prefix, files, pageCommand);
PaginationBox paginationBox = new SchematicPaginationBox(resolvedRoot, fileList, pageCommand);
return paginationBox.create(page);
}
}
private static List<File> allFiles(File root) {
File[] files = root.listFiles();
if (files == null) {
return null;
}
List<File> fileList = new ArrayList<>();
for (File f : files) {
if (f.isDirectory()) {
List<File> subFiles = allFiles(f);
if (subFiles == null) {
continue; // empty subdir
private static List<Path> allFiles(Path root) throws IOException {
List<Path> pathList = new ArrayList<>();
try (DirectoryStream<Path> stream = Files.newDirectoryStream(root)) {
for (Path path : stream) {
if (Files.isDirectory(path)) {
pathList.addAll(allFiles(path));
} else {
pathList.add(path);
}
fileList.addAll(subFiles);
} else {
fileList.add(f);
}
}
return fileList;
return pathList;
}
private static class SchematicPaginationBox extends PaginationBox {
private final String prefix;
private final File[] files;
private final Path rootDir;
private final List<Path> files;
SchematicPaginationBox(String rootDir, File[] files, String pageCommand) {
SchematicPaginationBox(Path rootDir, List<Path> files, String pageCommand) {
super("Available schematics", pageCommand);
this.prefix = rootDir == null ? "" : rootDir;
this.rootDir = rootDir;
this.files = files;
}
@Override
public Component getComponent(int number) {
checkArgument(number < files.length && number >= 0);
File file = files[number];
Multimap<String, ClipboardFormat> exts = ClipboardFormats.getFileExtensionMap();
String format = exts.get(Files.getFileExtension(file.getName()))
.stream().findFirst().map(ClipboardFormat::getName).orElse("Unknown");
boolean inRoot = file.getParentFile().getName().equals(prefix);
checkArgument(number < files.size() && number >= 0);
Path file = files.get(number);
String path = inRoot ? file.getName() : file.getPath().split(Pattern.quote(prefix + File.separator))[1];
String format = ClipboardFormats.getFileExtensionMap()
.get(MoreFiles.getFileExtension(file))
.stream()
.findFirst()
.map(ClipboardFormat::getName)
.orElse("Unknown");
boolean inRoot = file.getParent().equals(rootDir);
String path = inRoot
? file.getFileName().toString()
: file.toString().substring(rootDir.toString().length());
return TextComponent.builder()
.content("")
@ -458,7 +451,7 @@ public Component getComponent(int number) {
@Override
public int getComponentsSize() {
return files.length;
return files.size();
}
}
}

View File

@ -103,7 +103,7 @@ public void executeLast(Player player, LocalSession session,
return;
}
File dir = worldEdit.getWorkingDirectoryFile(worldEdit.getConfiguration().scriptsDir);
File dir = worldEdit.getWorkingDirectoryPath(worldEdit.getConfiguration().scriptsDir).toFile();
File f = worldEdit.getSafeOpenFile(player, dir, lastScript, "js", "js");
worldEdit.runScript(player, f, Stream.concat(Stream.of(lastScript), args.stream())

View File

@ -248,7 +248,7 @@ public Set<BaseBlock> getBlocks(String list, boolean allBlocksAllowed) throws Wo
* @throws FilenameException if there is a problem with the name of the file
*/
public File getSafeOpenFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException {
File dir = controller.getWorkingDirectoryFile(folder);
File dir = controller.getWorkingDirectoryPath(folder).toFile();
return controller.getSafeOpenFile(player, dir, filename, defaultExt, exts);
}
@ -269,7 +269,7 @@ public File getSafeOpenFile(String folder, String filename, String defaultExt, S
* @throws FilenameException if there is a problem with the name of the file
*/
public File getSafeSaveFile(String folder, String filename, String defaultExt, String... exts) throws FilenameException {
File dir = controller.getWorkingDirectoryFile(folder);
File dir = controller.getWorkingDirectoryPath(folder).toFile();
return controller.getSafeSaveFile(player, dir, filename, defaultExt, exts);
}

View File

@ -36,6 +36,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
@ -55,14 +56,25 @@ public class PropertiesConfiguration extends LocalConfiguration {
/**
* Construct the object. The configuration isn't loaded yet.
*
* @param path the path tot he configuration
* @param path the path to the configuration
*/
public PropertiesConfiguration(File path) {
this.path = path;
public PropertiesConfiguration(Path path) {
this.path = path.toFile();
properties = new Properties();
}
/**
* Construct the object. The configuration isn't loaded yet.
*
* @param path the path to the configuration
* @deprecated Use {@link PropertiesConfiguration#PropertiesConfiguration(Path)}
*/
@Deprecated
public PropertiesConfiguration(File path) {
this(path.toPath());
}
@Override
public void load() {
try (InputStream stream = new FileInputStream(path)) {

View File

@ -33,6 +33,6 @@ public WorldEditResourceLoader(WorldEdit worldEdit) {
@Override
public Path getLocalResource(String pathName) {
return this.worldEdit.getWorkingDirectoryFile(pathName).toPath();
return this.worldEdit.getWorkingDirectoryPath(pathName);
}
}

View File

@ -22,9 +22,14 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Streams;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Deque;
import java.util.Spliterator;
import java.util.stream.IntStream;
@ -32,6 +37,20 @@
public class MorePaths {
public static Comparator<Path> oldestFirst() {
return Comparator.comparing(x -> {
try {
return Files.getLastModifiedTime(x);
} catch (IOException e) {
return FileTime.from(Instant.EPOCH);
}
});
}
public static Comparator<Path> newestFirst() {
return oldestFirst().reversed();
}
/**
* Starting with the first path element, add elements until reaching this path.
*/

View File

@ -21,7 +21,7 @@
import com.sk89q.worldedit.util.PropertiesConfiguration;
import java.io.File;
import java.nio.file.Path;
public class FabricConfiguration extends PropertiesConfiguration {
@ -29,7 +29,7 @@ public class FabricConfiguration extends PropertiesConfiguration {
public boolean cheatMode = false;
public FabricConfiguration(FabricWorldEdit mod) {
super(new File(mod.getWorkingDir(), "worldedit.properties"));
super(mod.getWorkingDir().resolve("worldedit.properties"));
}
@Override
@ -39,7 +39,7 @@ protected void loadExtra() {
}
@Override
public File getWorkingDirectory() {
public Path getWorkingDirectoryPath() {
return FabricWorldEdit.inst.getWorkingDir();
}
}
}

View File

@ -329,8 +329,8 @@ public Platform getPlatform() {
*
* @return the working directory
*/
public File getWorkingDir() {
return this.workingDir.toFile();
public Path getWorkingDir() {
return this.workingDir;
}
/**

View File

@ -22,6 +22,7 @@
import com.sk89q.worldedit.util.PropertiesConfiguration;
import java.io.File;
import java.nio.file.Path;
public class ForgeConfiguration extends PropertiesConfiguration {
@ -29,7 +30,7 @@ public class ForgeConfiguration extends PropertiesConfiguration {
public boolean cheatMode = false;
public ForgeConfiguration(ForgeWorldEdit mod) {
super(new File(mod.getWorkingDir() + File.separator + "worldedit.properties"));
super(mod.getWorkingDir().resolve("worldedit.properties"));
}
@Override
@ -39,7 +40,7 @@ protected void loadExtra() {
}
@Override
public File getWorkingDirectory() {
public Path getWorkingDirectoryPath() {
return ForgeWorldEdit.inst.getWorkingDir();
}
}
}

View File

@ -337,8 +337,8 @@ public Platform getPlatform() {
*
* @return the working directory
*/
public File getWorkingDir() {
return this.workingDir.toFile();
public Path getWorkingDir() {
return this.workingDir;
}
/**

View File

@ -362,8 +362,8 @@ public Platform getPlatform() {
*
* @return the working directory
*/
public File getWorkingDir() {
return this.workingDir;
public Path getWorkingDir() {
return this.workingDir.toPath();
}
/**

View File

@ -26,8 +26,8 @@
import org.slf4j.Logger;
import org.spongepowered.api.config.DefaultConfig;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
public class SpongeConfiguration extends ConfigurateConfiguration {
@ -54,7 +54,7 @@ public void load() {
}
@Override
public File getWorkingDirectory() {
public Path getWorkingDirectoryPath() {
return SpongeWorldEdit.inst().getWorkingDir();
}
}