From c068b8e9b98a46fbc9e36acbad1d7d9b35de76f3 Mon Sep 17 00:00:00 2001 From: Jean-Francois Denise Date: Thu, 14 Mar 2024 12:06:50 +0100 Subject: [PATCH] WFGP-269, Move the transformer module to the deployment transformer project --- pom.xml | 14 -- transformer/pom.xml | 97 -------- .../transformer/BataviaTransformer.java | 68 ------ .../transformer/JakartaTransformer.java | 226 ------------------ .../galleon/plugin/transformer/JarUtils.java | 128 ---------- .../transformer/TransformedArtifact.java | 74 ------ .../galleon/plugin/transformer/Utils.java | 200 ---------------- 7 files changed, 807 deletions(-) delete mode 100644 transformer/pom.xml delete mode 100644 transformer/src/main/java/org/wildfly/galleon/plugin/transformer/BataviaTransformer.java delete mode 100644 transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JakartaTransformer.java delete mode 100644 transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JarUtils.java delete mode 100644 transformer/src/main/java/org/wildfly/galleon/plugin/transformer/TransformedArtifact.java delete mode 100644 transformer/src/main/java/org/wildfly/galleon/plugin/transformer/Utils.java diff --git a/pom.xml b/pom.xml index 5c49bf00..7d600632 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,6 @@ - transformer galleon-plugins config-gen maven-plugin @@ -90,7 +89,6 @@ false 1.0.8.Final - 1.0.12.Final 1.5.0.Final @@ -373,18 +371,6 @@ ${version.org.wildfly.core.wildfly-core} - - org.wildfly.extras.batavia - transformer-api - ${version.org.wildfly.extras.batavia} - - - - org.wildfly.extras.batavia - transformer-impl-eclipse - ${version.org.wildfly.extras.batavia} - - junit junit diff --git a/transformer/pom.xml b/transformer/pom.xml deleted file mode 100644 index 9036b312..00000000 --- a/transformer/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - 4.0.0 - - - org.wildfly.galleon-plugins - wildfly-provisioning-parent - 7.0.0.Beta9-SNAPSHOT - - - transformer - jar - - WildFly Galleon Plugins EE9 transformer - http://maven.apache.org - - - - org.wildfly.extras.batavia - transformer-api - - - org.wildfly.extras.batavia - transformer-impl-eclipse - runtime - - - junit - junit - test - - - - - - - sonatype - sonatype - https://oss.sonatype.org/content/repositories/snapshots - default - - true - never - - - true - never - - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - - - org.wildfly.galleon.plugin.transformer.JakartaTransformer - - true - - - - - - - - - - - diff --git a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/BataviaTransformer.java b/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/BataviaTransformer.java deleted file mode 100644 index d7938624..00000000 --- a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/BataviaTransformer.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.wildfly.galleon.plugin.transformer; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; - -import org.wildfly.extras.transformer.ArchiveTransformer; -import org.wildfly.extras.transformer.TransformerBuilder; -import org.wildfly.galleon.plugin.transformer.JakartaTransformer.LogHandler; -import org.wildfly.extras.transformer.TransformerFactory; - -/** - * - * @author jdenise - * @author Richard Opalka - */ -public class BataviaTransformer { - - static TransformedArtifact transform(Path configsDir, Path src, Path target, boolean verbose, LogHandler log) throws IOException { - boolean transformed; - boolean signed = false; - boolean unsigned = false; - try { - transformed = transform(configsDir != null ? configsDir.toString() : null, src.toString(), target.toString(), verbose); - // TODO Only check for jar not for exploded for now - if (src.getFileName().toString().endsWith(".jar")) { - signed = JarUtils.isSignedJar(src); - } - if (transformed) { - log.print("EE9: transformed %s", target.getFileName().toString()); - } - if (signed && transformed) { - log.print("WARNING: EE9: unsigning transformed %s ", target.getFileName().toString()); - JarUtils.unsign(target); - unsigned = true; - } - - } catch (Exception ex) { - throw new RuntimeException(ex); - } - return new TransformedArtifact(src, target, transformed, signed, unsigned); - } - - static boolean transform(final String configsDir, final String source, final String target, boolean verbose) throws Exception { - final TransformerBuilder builder = TransformerFactory.getInstance().newTransformer(); - builder.setVerbose(verbose); - if (configsDir != null) builder.setConfigsDir(configsDir); - final ArchiveTransformer transformer = builder.build(); - return transformer.transform(new File(source), new File(target)); - } - -} diff --git a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JakartaTransformer.java b/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JakartaTransformer.java deleted file mode 100644 index 8757cfa8..00000000 --- a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JakartaTransformer.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.wildfly.galleon.plugin.transformer; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; - -/** - * - * @author jdenise - */ -public class JakartaTransformer { - - static class WrappedInputStream extends FileInputStream { - - private final Path dir; - - public WrappedInputStream(File file, Path dir) throws FileNotFoundException { - super(file); - this.dir = dir; - } - - @Override - public void close() throws IOException { - super.close(); - Utils.recursiveDelete(dir); - } - - } - - public interface LogHandler { - - void print(String format, Object... args); - } - - public static final String TRANSFORM_ARTIFACTS = "jakarta.transform.artifacts"; - public static final String TRANSFORM_CONFIGS_DIR = "jakarta.transform.configs.dir"; - public static final String TRANSFORM_VERBOSE = "jakarta.transform.verbose"; - - private static final LogHandler DEFAULT_LOG_HANDLER = new LogHandler() { - @Override - public void print(String format, Object... args) { - System.out.println(String.format(format, args)); - } - }; - - private static final String CONFIGS_DIR_PARAM = "--configs-dir="; - private static final String VERBOSE_PARAM = "--verbose"; - private static final String HELP_PARAM = "--help"; - - // POC entry point to use galleon-plugins to transform artifacts offline. - public static void main(String[] args) throws Exception { - String configsDir = null; - boolean verbose = false; - String source = null; - String target = null; - for (String arg : args) { - if (arg.equals(HELP_PARAM)) { - printHelp(); - return; - } else if (arg.startsWith(CONFIGS_DIR_PARAM)) { - configsDir = arg.substring(CONFIGS_DIR_PARAM.length()); - } else { - if (arg.equals(VERBOSE_PARAM)) { - verbose = true; - } else { - if (source == null) { - source = arg; - Path sourcePath = Paths.get(source); - if (Files.notExists(sourcePath)) { - throw new Exception("Source artifact " + source + " doesn't exist."); - } - } else if (target == null) { - target = arg; - Path targetPath = Paths.get(target); - if (Files.exists(targetPath)) { - Files.delete(targetPath); - } - } else { - throw new Exception("Invalid argument " + arg); - } - } - } - } - if (source == null || target == null) { - throw new Exception("Source and target artifact must be set."); - } - - boolean ret = BataviaTransformer.transform(configsDir, source, target, verbose); - if (ret) { - System.out.println("Artifact has been transformed."); - } else { - System.out.println("No transformation occured."); - } - } - - private static void printHelp() { - StringBuilder builder = new StringBuilder(); - builder.append("WildFly Galleon EE9 transformer usage:\n"); - builder.append("java -jar [ARGUMENTS]\n"); - builder.append("If the target file already exists, it will be first deleted."); - builder.append("Arguments:\n"); - builder.append(" --help : print this help\n"); - builder.append(" --verbose : print transformation traces\n"); - builder.append(" --configs-dir= : path to a directory containing transformation rules\n"); - builder.append("To redirect traces into a file: java -jar --verbose &> traces.txt\n"); - System.out.println(builder.toString()); - } - - public static InputStream transform(Path configsDir, InputStream in, String name, boolean verbose, LogHandler log) throws IOException { - if (log == null) { - log = DEFAULT_LOG_HANDLER; - } - if (!name.endsWith(".war") && !name.endsWith(".ear") - && !name.endsWith(".rar") && !name.endsWith(".jar") && !name.endsWith(".xml")) { - name = name + ".war"; - } - Path dir = Files.createTempDirectory("jakarta-transform"); - Path src = dir.resolve("jakartaee-" + name); - Path target = dir.resolve(name); - - FileOutputStream out = new FileOutputStream(src.toFile()); - byte[] buffer = new byte[1024]; - int size; - while ((size = in.read(buffer)) != -1) { - out.write(buffer, 0, size); - } - out.close(); - BataviaTransformer.transform(configsDir, src, target, verbose, log); - return new WrappedInputStream(target.toFile(), dir); - } - - public static TransformedArtifact transform(Path configsDir, Path src, Path target, boolean verbose, LogHandler log) throws IOException { - if (log == null) { - log = DEFAULT_LOG_HANDLER; - } - Path originalSrc = src; - Path actualTarget = null; - Path safeCopy = null; - boolean failed = false; - boolean isExploded = false; - if (Files.isDirectory(src)) { - // Exploded - isExploded = true; - if (target.equals(src)) { - safeCopy = target.getParent().resolve("jakartaee-" + target.getFileName().toString()); - log.print("Transformation target is equal to src, moving src artifact directory to %s", safeCopy); - Utils.copy(src, safeCopy); - Utils.recursiveDelete(src); - src = safeCopy; - } - actualTarget = target; - } else { - if (Files.isDirectory(target)) { - actualTarget = target.resolve(src.getFileName()); - } else { - // target and src are the same file. - if (src.equals(target)) { - safeCopy = target.getParent().resolve("jakartaee-" + target.getFileName().toString()); - log.print("Transformation target is equal to src, moving src artifact to %s", safeCopy); - if (Files.exists(safeCopy)) { - Files.delete(safeCopy); - } - Files.copy(src, safeCopy); - Files.delete(src); - src = safeCopy; - } - actualTarget = target; - } - } - if (Files.exists(actualTarget)) { - throw new IOException("Transformation target " + actualTarget + " already exist"); - } - try { - return BataviaTransformer.transform(configsDir, src, actualTarget, verbose, log); - } catch (Throwable ex) { - failed = true; - if (ex instanceof IOException) { - throw (IOException) ex; - } else { - throw new IOException(ex); - } - } finally { - if (failed) { - // revert - if (safeCopy != null) { - log.print("Exception occured, reverting original src artifact"); - if (isExploded) { - Utils.copy(safeCopy, originalSrc); - } else { - Files.copy(safeCopy, originalSrc); - } - } - } - if (safeCopy != null) { - if (isExploded) { - Utils.recursiveDelete(safeCopy); - } else { - Files.delete(safeCopy); - } - } - } - } - -} diff --git a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JarUtils.java b/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JarUtils.java deleted file mode 100644 index 4a9d6b5b..00000000 --- a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/JarUtils.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.wildfly.galleon.plugin.transformer; - -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Map; -import java.util.jar.Attributes; -import java.util.jar.JarFile; -import java.util.jar.Manifest; - -/** - * - * - * @author jdenise - */ -class JarUtils { - - private static final Path MANIFEST_DIR = Paths.get("META-INF"); - private static final Path MANIFEST_FILE = MANIFEST_DIR.resolve("MANIFEST.MF"); - - static boolean isSignedJar(Path jarFile) throws IOException { - JarFile jar = new JarFile(jarFile.toFile()); - Manifest manifest = jar.getManifest(); - - boolean signed = false; - if (manifest != null) { - for (Map.Entry entry : manifest.getEntries().entrySet()) { - for (Object attrkey : entry.getValue().keySet()) { - if (attrkey instanceof Attributes.Name - && ((Attributes.Name) attrkey).toString().indexOf("-Digest") != -1) { - signed = true; - break; - } - } - } - } - return signed; - } - - // We can't use Jar API to unsign, the jar to unsign can't be verified. - static void unsign(Path jarFile) throws Exception { - FileInputStream fi = new FileInputStream(jarFile.toFile()); - Path dir = Files.createTempDirectory("unsign-jar-" + jarFile.getFileName()); - Utils.unzip(fi, dir.toFile()); - visitJar(dir); - fi.close(); - Files.delete(jarFile); - // Do not depend on galleon-core ZipUtils. - Utils.zip(dir, jarFile); - // Do not depend on galleon-core IoUtils. - Utils.recursiveDelete(dir); - } - - private static void visitJar(Path dir) throws IOException { - Files.walkFileTree(dir, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - Path f = dir.relativize(file); - if (MANIFEST_DIR.equals(f.getParent())) { - if (MANIFEST_FILE.equals(f)) { - transformManifest(file); - } else { - if (f.toString().endsWith(".SF") || f.toString().endsWith(".RSA") || f.toString().endsWith(".DSA")) { - Files.delete(file); - } - } - } - return FileVisitResult.CONTINUE; - } - }); - } - - private static void transformManifest(Path manifestFile) throws IOException { - FileInputStream fi = new FileInputStream(manifestFile.toFile()); - Manifest manifest2 = new Manifest(); - try { - Manifest manifest = new Manifest(fi); - - for (Map.Entry entry : manifest.getMainAttributes().entrySet()) { - manifest2.getMainAttributes().put(entry.getKey(), entry.getValue()); - } - - for (Map.Entry entry : manifest.getEntries().entrySet()) { - boolean toRemove = false; - for (Object attrkey : entry.getValue().keySet()) { - if (attrkey instanceof Attributes.Name - && ((Attributes.Name) attrkey).toString().indexOf("-Digest") != -1) { - toRemove = true; - break; - } - } - if (!toRemove) { - manifest2.getEntries().put(entry.getKey(), entry.getValue()); - } - } - - } finally { - fi.close(); - Files.delete(manifestFile); - try (FileOutputStream out = new FileOutputStream(manifestFile.toFile())) { - manifest2.write(out); - } - } - } -} diff --git a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/TransformedArtifact.java b/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/TransformedArtifact.java deleted file mode 100644 index 0c498224..00000000 --- a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/TransformedArtifact.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.wildfly.galleon.plugin.transformer; - -import java.nio.file.Path; -/** - * - * @author jdenise - */ -public class TransformedArtifact { - private final Path src; - private final Path target; - private final boolean transformed; - private final boolean srcSigned; - private final boolean unsigned; - - TransformedArtifact(Path src, Path target, boolean transformed, boolean srcSigned, boolean unsigned) { - this.src = src; - this.target = target; - this.transformed = transformed; - this.srcSigned = srcSigned; - this.unsigned = unsigned; - } - - /** - * @return the src - */ - public Path getSrc() { - return src; - } - - /** - * @return the target - */ - public Path getTarget() { - return target; - } - - /** - * @return the transformed - */ - public boolean isTransformed() { - return transformed; - } - - /** - * @return the unsigned - */ - public boolean isUnsigned() { - return unsigned; - } - - /** - * @return the srcSigned - */ - public boolean isSrcSigned() { - return srcSigned; - } - -} diff --git a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/Utils.java b/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/Utils.java deleted file mode 100644 index 8ca7edc3..00000000 --- a/transformer/src/main/java/org/wildfly/galleon/plugin/transformer/Utils.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2016-2020 Red Hat, Inc. and/or its affiliates - * and other contributors as indicated by the @author tags. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.wildfly.galleon.plugin.transformer; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.DirectoryStream; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitOption; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -/** - * Content copied from Galleon core. No dependency on galleon-core. - * - * @author jdenise - */ -public class Utils { - - private static final String JAR_URI_PREFIX = "jar:"; - private static final Map CREATE_ENV = Collections.singletonMap("create", "true"); - - public static void unzip(InputStream wf, File dir) throws Exception { - byte[] buffer = new byte[1024]; - try (ZipInputStream zis = new ZipInputStream(wf)) { - ZipEntry ze = zis.getNextEntry(); - while (ze != null) { - String fileName = ze.getName(); - File newFile = new File(dir, fileName); - if (fileName.endsWith("/")) { - newFile.mkdirs(); - zis.closeEntry(); - ze = zis.getNextEntry(); - continue; - } else { - newFile.getParentFile().mkdirs(); - } - try (FileOutputStream fos = new FileOutputStream(newFile)) { - int len; - while ((len = zis.read(buffer)) > 0) { - fos.write(buffer, 0, len); - } - } - zis.closeEntry(); - ze = zis.getNextEntry(); - } - } - } - - static void recursiveDelete(Path root) { - if (root == null || !Files.exists(root)) { - return; - } - try { - Files.walkFileTree(root, new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - try { - Files.delete(file); - } catch (IOException ex) { - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - if (e != null) { - // directory iteration failed - throw e; - } - try { - Files.delete(dir); - } catch (IOException ex) { - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - } - } - - private static URI toZipUri(Path zipFile) throws IOException { - URI zipUri = zipFile.toUri(); - try { - zipUri = new URI(JAR_URI_PREFIX + zipUri.getScheme(), zipUri.getPath(), null); - } catch (URISyntaxException e) { - throw new IOException("Failed to create a JAR URI for " + zipFile, e); - } - return zipUri; - } - - private static void copyToZip(Path srcRoot, Path srcPath, FileSystem zipfs) throws IOException { - Files.walkFileTree(srcPath, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, - new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - throws IOException { - final Path targetDir = zipfs.getPath(srcRoot.relativize(dir).toString()); - try { - Files.copy(dir, targetDir); - } catch (FileAlreadyExistsException e) { - if (!Files.isDirectory(targetDir)) { - throw e; - } - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - Files.copy(file, zipfs.getPath(srcRoot.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING); - return FileVisitResult.CONTINUE; - } - }); - } - - public static void zip(Path src, Path zipFile) throws IOException { - try (FileSystem zipfs = newFileSystem(toZipUri(zipFile), Files.exists(zipFile) ? Collections.emptyMap() : CREATE_ENV)) { - if (Files.isDirectory(src)) { - try (DirectoryStream stream = Files.newDirectoryStream(src)) { - for (Path srcPath : stream) { - copyToZip(src, srcPath, zipfs); - } - } - } else { - Files.copy(src, zipfs.getPath(src.getFileName().toString()), StandardCopyOption.REPLACE_EXISTING); - } - } - } - - private static FileSystem newFileSystem(URI uri, Map env) throws IOException { - // If Multi threading required, logic should be added to wrap this fs - // onto a fs that handles a reference counter and close the fs only when all thread are done - // with it. - return FileSystems.newFileSystem(uri, env); - } - - static void copy(Path source, Path target) throws IOException { - if (Files.isDirectory(source)) { - Files.createDirectories(target); - } else { - Files.createDirectories(target.getParent()); - } - Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, - new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - throws IOException { - final Path targetDir = target.resolve(source.relativize(dir).toString()); - try { - Files.copy(dir, targetDir); - } catch (FileAlreadyExistsException e) { - if (!Files.isDirectory(targetDir)) { - throw e; - } - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - Files.copy(file, target.resolve(source.relativize(file).toString()), StandardCopyOption.REPLACE_EXISTING); - return FileVisitResult.CONTINUE; - } - }); - } -}