
com.nordstrom.common.file.PathUtils Maven / Gradle / Ivy
package com.nordstrom.common.file;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
/**
* This utility class provides a {@link #getNextPath(Path, String, String) getNextPath} method to acquire the next file
* path in sequence for the specified base name and extension in the indicated target folder. If the target folder
* already contains at least one file that matches the specified base name and extension, the algorithm used to select
* the next path will always return a path whose index is one more than the highest index that currently exists. (If a
* single file with no index is found, its implied index is 0.)
*
* Example usage of {@code getNextPath}
*
* ...
*
* /*
* * This example gets the next path in sequence for base name `artifact`
* * and extension `txt` in the TestNG output directory.
* *
* * For purposes of this example, the output directory already contains
* * the following files: `artifact.txt`, `artifact-3.txt`
* */
*
* Path collectionPath = Paths.get(testContext.getOutputDirectory());
* // => C:\git\my-project\test-output\Default suite
*
* Path artifactPath;
* try {
* artifactPath = PathUtils.getNextPath(collectionPath, "artifact", "txt");
* // => C:\git\my-project\test-output\Default suite\artifact-4.txt
* } catch (IOException e) {
* provider.getLogger().info("Unable to get output path; no artifact was captured", e);
* return;
* }
*
* ...
*
*/
public final class PathUtils {
private PathUtils() {
throw new AssertionError("PathUtils is a static utility class that cannot be instantiated");
}
private static final String SUREFIRE_PATH = "surefire-reports";
private static final String FAILSAFE_PATH = "failsafe-reports";
/**
* This enumeration contains methods to help build proxy subclass names and select reports directories.
*/
public enum ReportsDirectory {
SUREFIRE_1("(Test)(.*)", SUREFIRE_PATH),
SUREFIRE_2("(.*)(Test)", SUREFIRE_PATH),
SUREFIRE_3("(.*)(Tests)", SUREFIRE_PATH),
SUREFIRE_4("(.*)(TestCase)", SUREFIRE_PATH),
FAILSAFE_1("(IT)(.*)", FAILSAFE_PATH),
FAILSAFE_2("(.*)(IT)", FAILSAFE_PATH),
FAILSAFE_3("(.*)(ITCase)", FAILSAFE_PATH),
ARTIFACT(".*", "artifact-capture");
private String regex;
private String folder;
ReportsDirectory(String regex, String folder) {
this.regex = regex;
this.folder = folder;
}
/**
* Get the regular expression that matches class names for this constant.
*
* @return class-matching regular expression string
*/
public String getRegEx() {
return regex;
}
/**
* Get the name of the folder associated with this constant.
*
* @return class-related folder name
*/
public String getFolder() {
return folder;
}
/**
* Get the resolved Maven-derived path associated with this constant.
*
* @return Maven folder path
*/
public Path getPath() {
return getTargetPath().resolve(folder);
}
/**
* Get the reports directory constant for the specified test class object.
*
* @param obj test class object
* @return reports directory constant
*/
public static ReportsDirectory fromObject(Object obj) {
String name = obj.getClass().getSimpleName();
for (ReportsDirectory constant : values()) {
if (name.matches(constant.regex)) {
return constant;
}
}
throw new IllegalStateException("Someone removed the 'default' pattern from this enumeration");
}
/**
* Get reports directory path for the specified test class object.
*
* @param obj test class object
* @return reports directory path
*/
public static Path getPathForObject(Object obj) {
ReportsDirectory constant = fromObject(obj);
return getTargetPath().resolve(constant.folder);
}
/**
* Get the path for the 'target' folder of the current project.
*
* @return path for project 'target' folder
*/
private static Path getTargetPath() {
return Paths.get(getBaseDir(), "target");
}
}
/**
* Get the next available path in sequence for the specified base name and extension in the specified folder.
*
* @param targetPath path to target directory for the next available path in sequence
* @param baseName base name for the path sequence
* @param extension extension for the path sequence
* @return the next available path in sequence
* @throws IOException if an I/O error is thrown when accessing the starting file.
*/
public static Path getNextPath(Path targetPath, String baseName, String extension) throws IOException {
Objects.requireNonNull(targetPath, "[targetPath] must be non-null");
Objects.requireNonNull(baseName, "[baseName] must be non-null");
Objects.requireNonNull(extension, "[extension] must be non-null");
File targetFile = targetPath.toFile();
if ( ! (targetFile.exists() && targetFile.isDirectory())) {
throw new IllegalArgumentException("[targetPath] must specify an existing directory");
}
if (baseName.isEmpty()) {
throw new IllegalArgumentException("[baseName] must specify a non-empty string");
}
if (extension.isEmpty()) {
throw new IllegalArgumentException("[extension] must specify a non-empty string");
}
Visitor visitor = new Visitor(baseName, extension);
Files.walkFileTree(targetPath, EnumSet.noneOf(FileVisitOption.class), 1, visitor);
return targetPath.resolve(visitor.getNewName());
}
/**
* Get project base directory.
*
* @return project base directory
*/
public static String getBaseDir() {
Path currentRelativePath = Paths.get(System.getProperty("user.dir"));
return currentRelativePath.toAbsolutePath().toString();
}
private static class Visitor implements FileVisitor {
private String baseName;
private String extension;
private int base, ext;
private PathMatcher pathMatcher;
private List intList = new ArrayList<>();
Visitor(String baseName, String extension) {
this.baseName = baseName;
this.extension = extension;
this.base = baseName.length();
this.ext = extension.length() + 1;
this.pathMatcher = FileSystems.getDefault().getPathMatcher("regex:\\Q" + baseName + "\\E(-\\d+)?\\." + extension);
}
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (attrs.isRegularFile() && pathMatcher.matches(file.getFileName())) {
String name = file.getFileName().toString();
String iStr = "0" + name.substring(base, name.length() - ext);
iStr = iStr.replace("0-", "");
intList.add(Integer.valueOf(iStr) + 1);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
public String getNewName() {
String newName;
if (intList.isEmpty()) {
newName = baseName + "." + extension;
} else {
Collections.sort(intList, Collections.reverseOrder());
newName = baseName + "-" + intList.get(0) + "." + extension;
}
return newName;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy