diff --git a/karate-core/pom.xml b/karate-core/pom.xml index 94e40d117..25bd7ec55 100644 --- a/karate-core/pom.xml +++ b/karate-core/pom.xml @@ -103,6 +103,11 @@ picocli 4.5.2 + + io.github.classgraph + classgraph + 4.8.90 + org.junit.jupiter junit-jupiter diff --git a/karate-core/src/main/java/com/intuit/karate/resource/FileResource.java b/karate-core/src/main/java/com/intuit/karate/resource/FileResource.java new file mode 100644 index 000000000..f9549c4e6 --- /dev/null +++ b/karate-core/src/main/java/com/intuit/karate/resource/FileResource.java @@ -0,0 +1,84 @@ +/* + * The MIT License + * + * Copyright 2020 Intuit 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 java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +/** + * + * @author pthomas3 + */ +public class FileResource implements Resource { + + private final File file; + private final boolean classPath; + private final String relativePath; + + public FileResource(File file) { + this(file, false, file.getPath().replace('\\', '/')); + } + + public FileResource(File file, boolean classPath, String relativePath) { + this.file = file; + this.classPath = classPath; + this.relativePath = relativePath; + } + + @Override + public boolean isFile() { + return true; + } + + @Override + public File getFile() { + return file; + } + + @Override + public boolean isClassPath() { + return classPath; + } + + @Override + public String getRelativePath() { + return relativePath; + } + + @Override + public InputStream getStream() { + try { + return new FileInputStream(file); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String toString() { + return getPrefixedPath(); + } + +} diff --git a/karate-core/src/main/java/com/intuit/karate/resource/JarResource.java b/karate-core/src/main/java/com/intuit/karate/resource/JarResource.java new file mode 100644 index 000000000..3522dbfb4 --- /dev/null +++ b/karate-core/src/main/java/com/intuit/karate/resource/JarResource.java @@ -0,0 +1,74 @@ +/* + * The MIT License + * + * Copyright 2020 Intuit 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 java.io.ByteArrayInputStream; +import java.io.File; +import java.io.InputStream; + +/** + * + * @author pthomas3 + */ +public class JarResource implements Resource { + + private final byte[] bytes; + private final String relativePath; + + public JarResource(byte[] bytes, String relativePath) { + this.bytes = bytes; + this.relativePath = relativePath; + } + + @Override + public boolean isFile() { + return false; + } + + @Override + public boolean isClassPath() { + return true; + } + + @Override + public File getFile() { + return null; + } + + @Override + public String getRelativePath() { + return relativePath; + } + + @Override + public InputStream getStream() { + return new ByteArrayInputStream(bytes); + } + + @Override + public String toString() { + return getPrefixedPath(); + } + +} diff --git a/karate-core/src/main/java/com/intuit/karate/resource/Resource.java b/karate-core/src/main/java/com/intuit/karate/resource/Resource.java new file mode 100644 index 000000000..5d896fed9 --- /dev/null +++ b/karate-core/src/main/java/com/intuit/karate/resource/Resource.java @@ -0,0 +1,49 @@ +/* + * The MIT License + * + * Copyright 2020 Intuit 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 java.io.File; +import java.io.InputStream; + +/** + * + * @author pthomas3 + */ +public interface Resource { + + boolean isFile(); + + boolean isClassPath(); + + File getFile(); + + String getRelativePath(); + + default String getPrefixedPath() { + return isClassPath() ? "classpath:" + getRelativePath() : getRelativePath(); + } + + InputStream getStream(); + +} diff --git a/karate-core/src/main/java/com/intuit/karate/resource/ResourceUtils.java b/karate-core/src/main/java/com/intuit/karate/resource/ResourceUtils.java new file mode 100644 index 000000000..1f1d1b51c --- /dev/null +++ b/karate-core/src/main/java/com/intuit/karate/resource/ResourceUtils.java @@ -0,0 +1,95 @@ +/* + * The MIT License + * + * Copyright 2020 Intuit 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 io.github.classgraph.ClassGraph; +import io.github.classgraph.ResourceList; +import io.github.classgraph.ScanResult; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +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 findResourcesByExtension(String extension, String... paths) { + List list = new ArrayList(); + try (ScanResult scanResult = new ClassGraph().acceptPaths(paths).scan()) { + ResourceList rl = scanResult.getResourcesWithExtension(extension); + rl.forEachByteArrayIgnoringIOException((res, bytes) -> { + URI uri = res.getURI(); + if ("file".equals(uri.getScheme())) { + File file = Paths.get(uri).toFile(); + list.add(new FileResource(file, true, res.getPath())); + } else { + list.add(new JarResource(bytes, res.getPath())); + } + }); + } + return list; + } + + public static List findFilesByExtension(String extension, File... files) { + Set results = new HashSet(); + 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 -> new FileResource(f)).collect(Collectors.toList()); + } + +} diff --git a/karate-core/src/test/java/com/intuit/karate/resource/ResourceUtilsTest.java b/karate-core/src/test/java/com/intuit/karate/resource/ResourceUtilsTest.java new file mode 100644 index 000000000..2d2e1c881 --- /dev/null +++ b/karate-core/src/test/java/com/intuit/karate/resource/ResourceUtilsTest.java @@ -0,0 +1,78 @@ +/* + * The MIT License + * + * Copyright 2020 Intuit 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 java.io.File; +import java.util.List; +import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * + * @author pthomas3 + */ +class ResourceUtilsTest { + + static final Logger logger = LoggerFactory.getLogger(ResourceUtilsTest.class); + + @Test + void testFindFilesByExtension() { + List list = ResourceUtils.findFilesByExtension("txt", new File("src/test/java/com/intuit/karate/resource")); + assertEquals(1, list.size()); + Resource resource = list.iterator().next(); + assertTrue(resource.isFile()); + assertFalse(resource.isClassPath()); + assertEquals("src/test/java/com/intuit/karate/resource/test1.txt", resource.getRelativePath()); + assertEquals("src/test/java/com/intuit/karate/resource/test1.txt", resource.getPrefixedPath()); + assertEquals("foo", FileUtils.toString(resource.getStream())); + } + + @Test + void testFindJarFilesByExtension() { + List list = ResourceUtils.findResourcesByExtension("properties", "cucumber"); + assertEquals(1, list.size()); + Resource resource = list.iterator().next(); + assertFalse(resource.isFile()); + assertTrue(resource.isClassPath()); + assertEquals("cucumber/version.properties", resource.getRelativePath()); + assertEquals("classpath:cucumber/version.properties", resource.getPrefixedPath()); + assertEquals("cucumber-jvm.version=1.2.5", FileUtils.toString(resource.getStream())); + } + + @Test + void testFindClassPathFilesByExtension() { + List list = ResourceUtils.findResourcesByExtension("txt", "com/intuit/karate/resource"); + assertEquals(1, list.size()); + Resource resource = list.iterator().next(); + assertTrue(resource.isFile()); + assertTrue(resource.isClassPath()); + assertEquals("com/intuit/karate/resource/test1.txt", resource.getRelativePath()); + assertEquals("classpath:com/intuit/karate/resource/test1.txt", resource.getPrefixedPath()); + assertEquals("foo", FileUtils.toString(resource.getStream())); + } + +} diff --git a/karate-core/src/test/java/com/intuit/karate/resource/test1.txt b/karate-core/src/test/java/com/intuit/karate/resource/test1.txt new file mode 100644 index 000000000..191028156 --- /dev/null +++ b/karate-core/src/test/java/com/intuit/karate/resource/test1.txt @@ -0,0 +1 @@ +foo \ No newline at end of file