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

Fix errors with map resources being not found in 2.6. #10504

Merged
merged 5 commits into from
May 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Optional<Path> findContentRoot() {
// a polygons file, the location of the polygons file is the map content root.
final Path mapYamlParentFolder = mapDescriptionYaml.getYamlFileLocation().getParent();
contentRoot =
FileUtils.findAny(mapYamlParentFolder, 3, MapData.POLYGON_FILE)
FileUtils.findClosestToRoot(mapYamlParentFolder, 3, MapData.POLYGON_FILE)
.map(Path::getParent)
.orElse(null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ private Optional<String> findFileNameForGame(final String gameName) {
/** Find 'games' folder starting from map.yml parent folder. */
private Optional<Path> findGamesFolder() {
final Path mapFolder = yamlFileLocation.getParent();
final Optional<Path> gamesFolder = FileUtils.findAny(mapFolder, 5, "games");
final Optional<Path> gamesFolder = FileUtils.findClosestToRoot(mapFolder, 5, "games");

if (gamesFolder.isEmpty()) {
log.warn("No 'games' folder found under location: {}", mapFolder.toAbsolutePath());
Expand All @@ -220,7 +220,7 @@ private Optional<Path> findGamesFolder() {

/** Search 'games' folder for a game-xml-file. */
private Optional<Path> searchForGameFile(final Path gamesFolder, final String xmlFileName) {
final Optional<Path> gameFile = FileUtils.findAny(gamesFolder, 3, xmlFileName);
final Optional<Path> gameFile = FileUtils.findClosestToRoot(gamesFolder, 3, xmlFileName);
if (gameFile.isEmpty()) {
log.warn(
"Failed to find game file: {}, within directory tree rooted at: {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ private static Optional<Path> findMapYmlFile(final Path mapFolder) {
* 'map.yml' file at depth 2, eg: 'map_folder-master/map_folder/map/map.yml'.
*/
final int maxMapYmlSearchDepth = 2;
return FileUtils.findAny(
return FileUtils.findClosestToRoot(
mapFolder, maxMapYmlSearchDepth, MapDescriptionYaml.MAP_YAML_FILE_NAME);
}

Expand Down
31 changes: 23 additions & 8 deletions lib/java-extras/src/main/java/org/triplea/io/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.nio.file.Path;
import java.time.Instant;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
Expand Down Expand Up @@ -74,26 +75,41 @@ public static URL toUrl(final Path file) {

/**
* Searches a file system starting from a given directory looking for a file or directory with a
* matching name.
* matching name. If multiple matching paths are found, returns the one closest to the root (via
* minimum length of the absolute path).
*
* @param searchRoot The directory whose contents we will search (and sub-directories)
* @param searchRoot The directory whose contents we will search (and subdirectories).
* @param maxDepth The maximum number of subdirectories to search. Zero means only search the
* 'searchRoot' directory.
* @param fileName The name of the file to be search for.
* @return A file matching the given name or empty if not found.
*/
public Optional<Path> findAny(final Path searchRoot, final int maxDepth, final String fileName) {
public Optional<Path> findClosestToRoot(
final Path searchRoot, final int maxDepth, final String fileName) {
return find(searchRoot, maxDepth, fileName).stream().findAny();
}

public Collection<Path> find(final Path searchRoot, final int maxDepth, final String fileName) {
/**
* Searches a file system starting from a given directory looking for files or directories with
* matching names. The resulting list will be in ascending order by absolute path length.
*
* @param searchRoot The directory whose contents we will search (and subdirectories).
* @param maxDepth The maximum number of subdirectories to search. Zero means only search the
* 'searchRoot' directory.
* @param fileName The name of the file to be search for.
* @return A list of files matching the given name or an empty list if not.
*/
public List<Path> find(final Path searchRoot, final int maxDepth, final String fileName) {
Preconditions.checkArgument(Files.isDirectory(searchRoot), searchRoot.toAbsolutePath());
Preconditions.checkArgument(Files.exists(searchRoot), searchRoot.toAbsolutePath());
Preconditions.checkArgument(maxDepth > -1);
Preconditions.checkArgument(!fileName.isBlank());
try (Stream<Path> files = Files.walk(searchRoot, maxDepth)) {
return files
.filter(f -> f.getFileName().toString().equals(fileName))
// Sort by path length (shortest to longest), so that the ordering is deterministic and
// paths closer to the root are earlier in the list.
.sorted(Comparator.comparingInt(f -> f.toAbsolutePath().toString().length()))
.collect(Collectors.toList());
} catch (final IOException e) {
log.error(
Expand Down Expand Up @@ -243,7 +259,7 @@ public static void deleteDirectory(final Path path) throws IOException {
}

/**
* Does an overwrite of one folder onto another and rolls back if there any errors. The rollback
* Does an overwrite of one folder onto another and rolls back if there were errors. The rollback
* is done by first moving the destination folder to a backup location. If there are any errors
* then we delete whatever we copied and move the backup location back to the destination
* location.
Expand Down Expand Up @@ -287,8 +303,7 @@ static boolean replaceFolder(
return true;
}

// otherwise create a backup of the destination folder before we replace it

// otherwise, create a backup of the destination folder before we replace it
final Path backupFolder;
try {
backupFolder = Files.createTempDirectory("temp-dir").resolve(dest.getFileName());
Expand All @@ -298,7 +313,7 @@ static boolean replaceFolder(
}

try {
// make a complete backup by moving the dest folder to backup
// make a complete backup by moving the dest folder to back up
fileMoveOperation.move(dest, backupFolder);

// do the folder move
Expand Down
59 changes: 51 additions & 8 deletions lib/java-extras/src/test/java/org/triplea/io/FileUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresent;
import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAndIs;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doCallRealMethod;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
Expand Down Expand Up @@ -59,10 +60,7 @@ void shouldReturnEmptyCollectionWhenDirectoryIsEmpty() throws Exception {
@Test
@DisplayName("Verify we can read file contents with ISO-8859-1 encoded characters")
void readContents() {
final File testFile =
new File(
FileUtilsTest.class.getClassLoader().getResource("ISO-8859-1-test-file.txt").getFile());
final Path testFilePath = Path.of(testFile.toURI());
final Path testFilePath = getPathOfResource("ISO-8859-1-test-file.txt");

final Optional<String> contentRead = FileUtils.readContents(testFilePath);

Expand All @@ -87,9 +85,7 @@ void fileExists() {
// |- child1/
// |- child2/
// |- touch-file
final File testFolderFile =
new File(FileUtilsTest.class.getClassLoader().getResource("test-folder-path").getFile());
final Path testFolderPath = Path.of(testFolderFile.toURI());
final Path testFolderPath = getPathOfResource("test-folder-path");
final Path child1 = testFolderPath.resolve("child1");
final Path child2 = child1.resolve("child2");

Expand Down Expand Up @@ -118,6 +114,45 @@ void fileExists() {
}
}

@Nested
class Find {
// Folder structure:
// |- test-folder-path/
// |- test-file
// |- child1/
// |- child2/
// |- test-file
final Path testFolderPath = getPathOfResource("test-folder-path");
final Path child1 = testFolderPath.resolve("child1");
final Path child2 = child1.resolve("child2");

@Test
void findClosestToRootDepth1() {
assertThat(
FileUtils.findClosestToRoot(child2, 1, "test-file"),
isPresentAndIs(child2.resolve("test-file")));
}

@Test
void findClosestToRootDepth3() {
assertThat(
FileUtils.findClosestToRoot(testFolderPath, 3, "test-file"),
isPresentAndIs(testFolderPath.resolve("test-file")));
}

@Test
void findDepth1() {
assertThat(FileUtils.find(child2, 1, "test-file"), contains(child2.resolve("test-file")));
}

@Test
void findDepth3() {
assertThat(
FileUtils.find(testFolderPath, 3, "test-file"),
contains(testFolderPath.resolve("test-file"), child2.resolve("test-file")));
}
}

/**
* Creates a non-empty directory, run delete, verify directory is deleted. Linux systems will fail
* the delete operation if the directory is not empty, this test verifies that we do a recursive
Expand Down Expand Up @@ -251,4 +286,12 @@ void getLastModified() throws IOException {
assertThat(FileUtils.getLastModified(tempFile), isPresent());
assertThat(FileUtils.getLastModified(tempFile).get().isBefore(Instant.now()), is(true));
}

private Path getPathOfResource(String name) {
try {
return Path.of(FileUtilsTest.class.getClassLoader().getResource(name).toURI());
} catch (URISyntaxException e) {
throw new IllegalStateException(e);
}
}
}
Empty file.