com.intuit.karate.resource.ResourceUtils Maven / Gradle / Ivy
The newest version!
/*
* The MIT License
*
* Copyright 2022 Karate Labs Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.intuit.karate.resource;
import com.intuit.karate.FileUtils;
import com.intuit.karate.core.Feature;
import com.intuit.karate.core.FeatureCall;
import io.github.classgraph.ClassGraph;
import io.github.classgraph.ResourceList;
import io.github.classgraph.ScanResult;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author pthomas3
*/
public class ResourceUtils {
private static final Logger logger = LoggerFactory.getLogger(ResourceUtils.class);
private ResourceUtils() {
// only static methods
}
public static List findFeatureFiles(File workingDir, List paths, String scenarioName) {
List features = new ArrayList();
if (paths == null || paths.isEmpty()) {
return features;
}
if (paths.size() == 1) { // TODO handle multiple paths with tag or line suffixes
String path = paths.get(0);
int pos = path.indexOf(".feature:");
int line;
String callTag;
if (pos != -1) { // line number has been appended
line = Integer.valueOf(path.substring(pos + 9));
path = path.substring(0, pos + 8);
} else {
line = -1;
}
pos = path.indexOf('@');
if (pos != -1) { // call by tag
callTag = path.substring(pos);
path = path.substring(0, pos);
} else {
callTag = null;
}
if (path.endsWith(".feature")) {
Resource resource = getResource(workingDir, path);
Feature feature = Feature.read(resource);
features.add(new FeatureCall(feature, callTag, line, scenarioName));
return features;
}
}
Collection resources = findResourcesByExtension(workingDir, "feature", paths);
for (Resource resource : resources) {
features.add(new FeatureCall(Feature.read(resource), null, -1, scenarioName)); // TODO smart find of scenario name
}
return features;
}
private static final ScanResult SCAN_RESULT = new ClassGraph().acceptPaths("/").scan(1);
public static Resource getResource(File workingDir, String path) {
if (path.startsWith(Resource.CLASSPATH_COLON)) {
path = removePrefix(path);
File file = classPathToFile(path);
if (file != null) {
return new FileResource(file, true, path);
}
List resources = new ArrayList<>();
synchronized (SCAN_RESULT) {
ResourceList rl = SCAN_RESULT.getResourcesWithPath(path);
if (rl == null) {
rl = ResourceList.emptyList();
}
rl.forEachByteArrayIgnoringIOException((res, bytes) -> {
URI uri = res.getURI();
if ("file".equals(uri.getScheme())) {
File found = Paths.get(uri).toFile();
resources.add(new FileResource(found, true, res.getPath()));
} else {
resources.add(new JarResource(bytes, res.getPath(), uri));
}
});
}
if (resources.isEmpty()) {
throw new RuntimeException("not found: " + path);
}
return resources.get(0);
} else {
path = path.replace('\\', '/'); // windows fix
File file = new File(removePrefix(path));
if (!file.exists()) {
throw new RuntimeException("not found: " + path);
}
Path relativePath = workingDir.toPath().relativize(file.getAbsoluteFile().toPath());
return new FileResource(file, false, relativePath.toString());
}
}
public static Collection findResourcesByExtension(File workingDir, String extension, String path) {
return findResourcesByExtension(workingDir, extension, Collections.singletonList(path));
}
public static List findResourcesByExtension(File workingDir, String extension, List paths) {
List results = new ArrayList();
List fileRoots = new ArrayList();
List pathRoots = new ArrayList();
for (String path : paths) {
if (path.endsWith("." + extension)) {
results.add(getResource(workingDir, path));
} else if (path.startsWith(Resource.CLASSPATH_COLON)) {
pathRoots.add(removePrefix(path));
} else {
fileRoots.add(new File(removePrefix(path)));
}
}
if (!fileRoots.isEmpty()) {
results.addAll(findFilesByExtension(workingDir, extension, fileRoots));
} else if (results.isEmpty() && !pathRoots.isEmpty()) {
String[] searchPaths = pathRoots.toArray(new String[pathRoots.size()]);
try (ScanResult scanResult = new ClassGraph().acceptPaths(searchPaths).scan(1)) {
ResourceList rl = scanResult.getResourcesWithExtension(extension);
rl.forEachByteArrayIgnoringIOException((res, bytes) -> {
URI uri = res.getURI();
if ("file".equals(uri.getScheme())) {
File file = Paths.get(uri).toFile();
results.add(new FileResource(file, true, res.getPath()));
} else {
results.add(new JarResource(bytes, res.getPath(), uri));
}
});
}
}
return results;
}
private static List findFilesByExtension(File workingDir, String extension, List files) {
List results = new ArrayList();
for (File base : files) {
Path searchPath = base.toPath();
Stream stream;
try {
stream = Files.walk(searchPath);
for (Iterator paths = stream.iterator(); paths.hasNext();) {
Path path = paths.next();
String fileName = path.getFileName().toString();
if (fileName.endsWith("." + extension)) {
results.add(path.toFile());
}
}
} catch (IOException e) { // NoSuchFileException
logger.trace("unable to walk path: {} - {}", searchPath, e.getMessage());
}
}
return results.stream()
.map(f -> {
Path relativePath = workingDir.toPath().relativize(f.getAbsoluteFile().toPath());
return new FileResource(f, false, relativePath.toString());
})
.collect(Collectors.toList());
}
public static File getFileRelativeTo(Class clazz, String path) {
Path dirPath = getPathContaining(clazz);
File file = new File(dirPath + File.separator + path);
if (file.exists()) {
return file;
}
try {
URL relativePath = clazz.getClassLoader().getResource(toPathFromClassPathRoot(clazz) + File.separator + path);
return Paths.get(relativePath.toURI()).toFile();
} catch (Exception e) {
throw new RuntimeException("cannot find " + path + " relative to " + clazz + ", " + e.getMessage());
}
}
public static Path getPathContaining(Class clazz) {
String relative = toPathFromClassPathRoot(clazz);
URL url = clazz.getClassLoader().getResource(relative);
try {
return Paths.get(url.toURI());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static File getDirContaining(Class clazz) {
Path path = getPathContaining(clazz);
return path.toFile();
}
public static String toPathFromClassPathRoot(Class clazz) {
Package p = clazz.getPackage();
String relative = "";
if (p != null) {
relative = p.getName().replace('.', '/');
}
return relative;
}
protected static String removePrefix(String text) {
if (text.startsWith(Resource.CLASSPATH_COLON) || text.startsWith(Resource.FILE_COLON)) {
return text.substring(text.indexOf(':') + 1);
} else {
return text;
}
}
public static String getParentPath(String relativePath) {
int pos = relativePath.lastIndexOf('/');
return pos == -1 ? "" : relativePath.substring(0, pos + 1);
}
private static final ClassLoader CLASS_LOADER = ResourceUtils.class.getClassLoader();
public static InputStream classPathResourceToStream(String path) {
return CLASS_LOADER.getResourceAsStream(path);
}
public static String classPathResourceToString(String path) {
return FileUtils.toString(classPathResourceToStream(path));
}
public static File classPathToFile(String path) {
URL url = CLASS_LOADER.getResource(path);
if (url == null || !"file".equals(url.getProtocol())) {
return null;
}
try {
return Paths.get(url.toURI()).toFile();
} catch (URISyntaxException e) {
return null;
}
}
public static File classPathOrFile(String path) {
File temp = classPathToFile(path);
if (temp != null) {
return temp;
}
temp = new File(path);
return temp.exists() ? temp : null;
}
}