From 4a3899044f07b93b3d3922f1d232fd2119a4de3f Mon Sep 17 00:00:00 2001 From: Alexander Suter Date: Mon, 29 Jul 2024 15:04:38 +0200 Subject: [PATCH] Remove most of commons.io usages - java.nio provides good enough API's to to basic file operations - our code mostly uses java.nio now which makes it more simple - less dependencies to 3rd parties which needs to be updated - FileAlternateObserver still left --- .../ivyteam/ivy/maven/InstallEngineMojo.java | 9 +- .../ivy/maven/MavenDependencyCleanupMojo.java | 17 ++-- .../maven/ShareEngineCoreClasspathMojo.java | 4 +- .../compile/AbstractEngineInstanceMojo.java | 2 +- .../ivy/maven/deploy/AbstractDeployMojo.java | 17 ++-- .../ivy/maven/deploy/DeployToEngineMojo.java | 2 +- .../maven/deploy/DeployToTestEngineMojo.java | 2 +- .../engine/EngineClassLoaderFactory.java | 64 ++++++++----- .../ivy/maven/engine/EngineControl.java | 10 +- .../ivy/maven/engine/EngineMojoContext.java | 2 +- .../engine/MavenProjectBuilderProxy.java | 4 +- .../deploy/DeploymentOptionsFileFactory.java | 7 +- .../maven/engine/deploy/dir/FileDeployer.java | 15 ++- .../engine/deploy/dir/FileLogForwarder.java | 4 +- .../ch/ivyteam/ivy/maven/util/PathUtils.java | 47 +++++++++ .../ivy/maven/BaseEngineProjectMojoTest.java | 17 +--- .../ch/ivyteam/ivy/maven/ProjectMojoRule.java | 36 +++++-- .../ivy/maven/TestIarPackagingMojo.java | 51 +++++----- .../ivy/maven/TestInstallEngineMojo.java | 8 +- .../maven/TestShareEngineClasspathMojo.java | 7 +- .../maven/compile/TestCompileProjectMojo.java | 19 +++- .../maven/deploy/TestDeployToEngineMojo.java | 6 +- .../ivyteam/ivy/maven/util/TestPathUtils.java | 95 +++++++++++++++++++ 23 files changed, 318 insertions(+), 127 deletions(-) create mode 100644 src/main/java/ch/ivyteam/ivy/maven/util/PathUtils.java create mode 100644 src/test/java/ch/ivyteam/ivy/maven/util/TestPathUtils.java diff --git a/src/main/java/ch/ivyteam/ivy/maven/InstallEngineMojo.java b/src/main/java/ch/ivyteam/ivy/maven/InstallEngineMojo.java index 2ecff4ce..9747e407 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/InstallEngineMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/InstallEngineMojo.java @@ -24,7 +24,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.SystemUtils; import org.apache.maven.artifact.versioning.ArtifactVersion; @@ -42,6 +41,7 @@ import ch.ivyteam.ivy.maven.engine.download.EngineDownloader; import ch.ivyteam.ivy.maven.engine.download.MavenEngineDownloader; import ch.ivyteam.ivy.maven.engine.download.URLEngineDownloader; +import ch.ivyteam.ivy.maven.util.PathUtils; import net.lingala.zip4j.ZipFile; /** @@ -263,11 +263,10 @@ private void removeOldEngineContent() throws MojoExecutionException { var dir = getRawEngineDirectory(); try { if (dir != null) { - FileUtils.cleanDirectory(dir.toFile()); + PathUtils.clean(dir); } - } catch (IOException ex) { - throw new MojoExecutionException( - "Failed to clean outdated ivy Engine directory '" + dir + "'.", ex); + } catch (Exception ex) { + throw new MojoExecutionException("Failed to clean outdated ivy Engine directory '" + dir + "'.", ex); } } diff --git a/src/main/java/ch/ivyteam/ivy/maven/MavenDependencyCleanupMojo.java b/src/main/java/ch/ivyteam/ivy/maven/MavenDependencyCleanupMojo.java index c7147df0..e4cbd939 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/MavenDependencyCleanupMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/MavenDependencyCleanupMojo.java @@ -16,9 +16,6 @@ package ch.ivyteam.ivy.maven; -import java.io.IOException; - -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -26,13 +23,16 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; +import ch.ivyteam.ivy.maven.util.PathUtils; + /** * Delete copied maven dependencies in the lib/mvn-deps folder. - * + * * @since 9.2.0 */ @Mojo(name = MavenDependencyCleanupMojo.GOAL) public class MavenDependencyCleanupMojo extends AbstractMojo { + public static final String GOAL = "maven-dependency-cleanup"; @Parameter(property = "project", required = true, readonly = true) @@ -51,12 +51,11 @@ public void execute() throws MojoExecutionException, MojoFailureException { return; } var mvnLibDir = project.getBasedir().toPath().resolve("lib").resolve("mvn-deps"); - getLog().info("Deleting " + mvnLibDir.toString()); + getLog().info("Deleting " + mvnLibDir); try { - FileUtils.deleteDirectory(mvnLibDir.toFile()); - } catch (IOException ex) { - getLog().warn("Couldn't delete: " + mvnLibDir.toString(), ex); + PathUtils.delete(mvnLibDir); + } catch (Exception ex) { + getLog().warn("Couldn't delete: " + mvnLibDir, ex); } } - } diff --git a/src/main/java/ch/ivyteam/ivy/maven/ShareEngineCoreClasspathMojo.java b/src/main/java/ch/ivyteam/ivy/maven/ShareEngineCoreClasspathMojo.java index 1fe0163f..b1058be9 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/ShareEngineCoreClasspathMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/ShareEngineCoreClasspathMojo.java @@ -47,10 +47,8 @@ public class ShareEngineCoreClasspathMojo extends AbstractEngineMojo { @Override public void execute() throws MojoExecutionException, MojoFailureException { - List ivyEngineClassPathFiles = EngineClassLoaderFactory - .getIvyEngineClassPathFiles(identifyAndGetEngineDirectory().toFile()); + List ivyEngineClassPathFiles = EngineClassLoaderFactory.getIvyEngineClassPathFiles(identifyAndGetEngineDirectory()); String propertyValue = StringUtils.join(ivyEngineClassPathFiles, ","); - MavenProperties properties = new MavenProperties(project, getLog()); properties.setMavenProperty(IVY_ENGINE_CORE_CLASSPATH_PROPERTY, propertyValue); } diff --git a/src/main/java/ch/ivyteam/ivy/maven/compile/AbstractEngineInstanceMojo.java b/src/main/java/ch/ivyteam/ivy/maven/compile/AbstractEngineInstanceMojo.java index 7d5f8ecc..153de5c7 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/compile/AbstractEngineInstanceMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/compile/AbstractEngineInstanceMojo.java @@ -90,7 +90,7 @@ protected MavenProjectBuilderProxy getMavenProjectBuilder() throws Exception { getLog(), timeoutEngineStartInSeconds); } - classLoaderFactory.writeEngineClasspathJar(toFile(engineDir)); + classLoaderFactory.writeEngineClasspathJar(engineDir); // share engine directory as property for custom follow up plugins: if (engineDir != null) { project.getProperties().put(AbstractEngineMojo.ENGINE_DIRECTORY_PROPERTY, engineDir.toAbsolutePath().toString()); diff --git a/src/main/java/ch/ivyteam/ivy/maven/deploy/AbstractDeployMojo.java b/src/main/java/ch/ivyteam/ivy/maven/deploy/AbstractDeployMojo.java index 78771d9e..77f6779f 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/deploy/AbstractDeployMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/deploy/AbstractDeployMojo.java @@ -16,13 +16,12 @@ package ch.ivyteam.ivy.maven.deploy; -import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.ReadOnlyFileSystemException; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; @@ -244,12 +243,14 @@ protected final Path createDeployOptionsFile(DeploymentOptionsFileFactory option return null; } - protected static final void removeTemporaryDeploymentOptionsFile(Path deploymentOptionsFile) { - FileUtils.deleteQuietly(toFile(deploymentOptionsFile)); - } - - private static File toFile(Path file) { - return file == null ? null : file.toFile(); + protected static void deleteFile(Path file) { + if (file != null && Files.exists(file)) { + try { + Files.delete(file); + } catch (IOException ex) { + throw new UncheckedIOException("Could not delete " + file, ex); + } + } } protected final void deployToDirectory(Path resolvedOptionsFile, Path deployDir) diff --git a/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToEngineMojo.java b/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToEngineMojo.java index bb5b85d6..558bca62 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToEngineMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToEngineMojo.java @@ -141,7 +141,7 @@ public void execute() throws MojoExecutionException, MojoFailureException { try { deployWithOptions(resolvedOptionsFile); } finally { - removeTemporaryDeploymentOptionsFile(resolvedOptionsFile); + deleteFile(resolvedOptionsFile); } } diff --git a/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToTestEngineMojo.java b/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToTestEngineMojo.java index 0a12cfa0..37d7d5ac 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToTestEngineMojo.java +++ b/src/main/java/ch/ivyteam/ivy/maven/deploy/DeployToTestEngineMojo.java @@ -156,7 +156,7 @@ private void deployTestApp() throws MojoExecutionException { var deployDir = getEngineDir(project).resolve(DeployToEngineMojo.DEPLOY_DEFAULT); deployToDirectory(resolvedOptionsFile, deployDir); } finally { - removeTemporaryDeploymentOptionsFile(resolvedOptionsFile); + deleteFile(resolvedOptionsFile); } } } diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/EngineClassLoaderFactory.java b/src/main/java/ch/ivyteam/ivy/maven/engine/EngineClassLoaderFactory.java index c31449e5..71dde970 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/EngineClassLoaderFactory.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/EngineClassLoaderFactory.java @@ -21,14 +21,13 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.IOFileFilter; -import org.apache.commons.io.filefilter.SuffixFileFilter; -import org.apache.commons.io.filefilter.WildcardFileFilter; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.plugin.logging.Log; @@ -72,12 +71,10 @@ public EngineClassLoaderFactory(MavenContext mavenContext) { this.maven = mavenContext; } - public URLClassLoader createEngineClassLoader(File engineDirectory) throws IOException { + public URLClassLoader createEngineClassLoader(Path engineDirectory) throws IOException { List osgiClasspath = getOsgiBootstrapClasspath(engineDirectory); - var filter = WildcardFileFilter.builder() - .setWildcards("org.eclipse.osgi_*.jar") - .get(); - addToClassPath(osgiClasspath, new File(engineDirectory, OsgiDir.PLUGINS), filter); + var pluginsDir = engineDirectory.resolve(OsgiDir.PLUGINS); + addToClassPath(osgiClasspath, pluginsDir, p -> p.getFileName().toString().startsWith("org.eclipse.osgi_") && p.getFileName().toString().endsWith(".jar")); osgiClasspath.addAll(0, getSlf4jJars()); if (maven.log.isDebugEnabled()) { maven.log.debug("Configuring OSGi engine classpath:"); @@ -93,35 +90,55 @@ public List getSlf4jJars() { maven.getJar("org.slf4j", "log4j-over-slf4j", SLF4J_VERSION)); } - public static List getOsgiBootstrapClasspath(File engineDirectory) { - if (engineDirectory == null || !engineDirectory.isDirectory()) { + public static List getOsgiBootstrapClasspath(Path engineDirectory) { + if (engineDirectory == null || !Files.isDirectory(engineDirectory)) { throw new RuntimeException("The engineDirectory is missing: " + engineDirectory); } List classPathFiles = new ArrayList<>(); - addToClassPath(classPathFiles, new File(engineDirectory, OsgiDir.INSTALL_AREA + "/" + OsgiDir.LIB_BOOT), - new SuffixFileFilter(".jar")); + var libBoot = engineDirectory.resolve(OsgiDir.INSTALL_AREA).resolve(OsgiDir.LIB_BOOT); + addToClassPath(classPathFiles, libBoot, p -> p.getFileName().toString().endsWith(".jar")); return classPathFiles; } - private static void addToClassPath(List classPathFiles, File dir, IOFileFilter fileFilter) { - if (dir.isDirectory()) { - classPathFiles.addAll(FileUtils.listFiles(dir, fileFilter, null)); + private static void addToClassPath(List classPathFiles, Path dir, Predicate filter) { + if (Files.isDirectory(dir)) { + try (var stream = Files.list(dir)) { + var files = stream + .filter(filter) + .map(p -> p.toFile()) + .toList(); + classPathFiles.addAll(files); + } catch (IOException ex) { + throw new RuntimeException(ex); + } } } - public static List getIvyEngineClassPathFiles(File engineDirectory) { - List classPathFiles = new ArrayList<>(); + public static List getIvyEngineClassPathFiles(Path engineDirectory) { + if (engineDirectory == null) { + return List.of(); + } + + var classPathFiles = new ArrayList(); for (String libDirPath : ENGINE_LIB_DIRECTORIES) { - File jarDir = new File(engineDirectory, libDirPath + File.separator); - if (!jarDir.isDirectory()) { + var jarDir = engineDirectory.resolve(libDirPath); + if (!Files.isDirectory(jarDir)) { continue; } - classPathFiles.addAll(FileUtils.listFiles(jarDir, new String[] {"jar"}, true)); + try (var walker = Files.walk(jarDir)) { + var jars = walker + .filter(p -> p.getFileName().toString().endsWith(".jar")) + .map(p -> p.toFile()) + .toList(); + classPathFiles.addAll(jars); + } catch (IOException ex) { + throw new RuntimeException(ex); + } } return classPathFiles; } - public void writeEngineClasspathJar(File engineDirectory) throws IOException { + public void writeEngineClasspathJar(Path engineDirectory) throws IOException { writeEngineClasspathJar(getIvyEngineClassPathFiles(engineDirectory)); } @@ -163,5 +180,4 @@ public File getJar(String groupId, String artifactId, String version) { return jar; } } - -} \ No newline at end of file +} diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/EngineControl.java b/src/main/java/ch/ivyteam/ivy/maven/engine/EngineControl.java index 56dd386f..ce1440ef 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/EngineControl.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/EngineControl.java @@ -41,7 +41,6 @@ import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.exec.ShutdownHookProcessDestroyer; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; @@ -272,8 +271,15 @@ private String executeSynch(CommandLine statusCmd) { executor.execute(statusCmd); } catch (IOException ex) { // expected! } finally { + try { engineOutput = outputStream.toString(); - IOUtils.closeQuietly(outputStream); + } finally { + try { + outputStream.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } } return engineOutput; } diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/EngineMojoContext.java b/src/main/java/ch/ivyteam/ivy/maven/engine/EngineMojoContext.java index 65b4b42c..84dbe91f 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/EngineMojoContext.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/EngineMojoContext.java @@ -63,7 +63,7 @@ private Path setupEngineClasspathJarIfNotExists() { try { log.info("Creating a classpath jar for starting the engine"); new ClasspathJar(classpathJar.toFile()) - .createFileEntries(EngineClassLoaderFactory.getOsgiBootstrapClasspath(engineDirectory.toFile())); + .createFileEntries(EngineClassLoaderFactory.getOsgiBootstrapClasspath(engineDirectory)); } catch (Exception ex) { throw new RuntimeException( "Could not create engine classpath jar: '" + classpathJar + "'", ex); diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/MavenProjectBuilderProxy.java b/src/main/java/ch/ivyteam/ivy/maven/engine/MavenProjectBuilderProxy.java index ec50e356..1075b2a2 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/MavenProjectBuilderProxy.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/MavenProjectBuilderProxy.java @@ -56,13 +56,13 @@ public MavenProjectBuilderProxy(EngineClassLoaderFactory classLoaderFactory, Fil logEngine(); - URLClassLoader ivyEngineClassLoader = classLoaderFactory.createEngineClassLoader(baseDirToBuildIn); + URLClassLoader ivyEngineClassLoader = classLoaderFactory.createEngineClassLoader(baseDirToBuildIn.toPath()); delegateClass = getOsgiBundledDelegate(ivyEngineClassLoader, timeoutEngineStartInSeconds); Constructor constructor = delegateClass.getDeclaredConstructor(File.class); delegate = executeInEngineDir(() -> constructor.newInstance(workspace)); - List engineJars = EngineClassLoaderFactory.getIvyEngineClassPathFiles(baseDirToBuildIn); + List engineJars = EngineClassLoaderFactory.getIvyEngineClassPathFiles(baseDirToBuildIn.toPath()); engineClasspath = getEngineClasspath(engineJars); } diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/DeploymentOptionsFileFactory.java b/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/DeploymentOptionsFileFactory.java index e7c98029..bf173339 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/DeploymentOptionsFileFactory.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/DeploymentOptionsFileFactory.java @@ -6,13 +6,14 @@ import java.nio.file.Path; import java.util.Collections; -import org.apache.commons.io.FilenameUtils; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.maven.shared.filtering.MavenFileFilter; import org.apache.maven.shared.filtering.MavenFilteringException; +import ch.ivyteam.ivy.maven.util.PathUtils; + public class DeploymentOptionsFileFactory { private static final String YAML = "yaml"; @@ -28,8 +29,8 @@ public Path createFromTemplate(Path optionsFile, MavenProject project, MavenSess return null; } - String fileFormat = FilenameUtils.getExtension(optionsFile.getFileName().toString()); - var targetFile = getTargetFile(fileFormat); + var ext = PathUtils.toExtension(optionsFile); + var targetFile = getTargetFile(ext); try { fileFilter.copyFile(optionsFile.toFile(), targetFile.toFile(), true, project, Collections.emptyList(), false, StandardCharsets.UTF_8.name(), session); diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileDeployer.java b/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileDeployer.java index f74e730e..b6e566df 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileDeployer.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileDeployer.java @@ -15,7 +15,6 @@ */ package ch.ivyteam.ivy.maven.engine.deploy.dir; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -23,7 +22,6 @@ import java.util.concurrent.TimeoutException; import java.util.function.Supplier; -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.logging.Log; @@ -71,21 +69,20 @@ private void clear() { private void initDeployment() throws MojoExecutionException { try { if (deploymentOptionsFile != null) { - //var engineOption = deploymentFiles.getDeployCandidate().resolveSibling(deploymentOptionsFile.getName()); - //Files.copy(deploymentOptionsFile.toPath(), engineOption); - File engineOption = new File(deploymentFiles.getDeployCandidate().getParent().toFile(), deploymentOptionsFile.getFileName().toString()); - FileUtils.copyFile(deploymentOptionsFile.toFile(), engineOption); + var engineOption = deploymentFiles.getDeployCandidate().resolveSibling(deploymentOptionsFile.getFileName().toString()); + Files.createDirectories(engineOption.getParent()); + Files.copy(deploymentOptionsFile, engineOption); } } catch (IOException ex) { - throw new MojoExecutionException("Failed to initialize engine deployment, could not copy options file", - ex); + throw new MojoExecutionException("Failed to initialize engine deployment, could not copy options file", ex); } } private void copyDeployableToEngine() throws MojoExecutionException { try { log.info("Uploading file " + deployFile + " to " + targetDeployableFile); - FileUtils.copyFile(deployFile.toFile(), targetDeployableFile.toFile()); + Files.createDirectories(targetDeployableFile.getParent()); + Files.copy(deployFile, targetDeployableFile); } catch (IOException ex) { throw new MojoExecutionException("Upload of file '" + deployFile.getFileName().toString() + "' to engine failed.", ex); } diff --git a/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileLogForwarder.java b/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileLogForwarder.java index d307df29..682fb80b 100644 --- a/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileLogForwarder.java +++ b/src/main/java/ch/ivyteam/ivy/maven/engine/deploy/dir/FileLogForwarder.java @@ -34,6 +34,7 @@ * @since 6.1.0 */ class FileLogForwarder { + private final Path engineLog; private final Log mavenLog; @@ -102,5 +103,4 @@ private void readNewLines(RandomAccessFile readableLog) throws IOException { static interface LogLineHandler { void handleLine(String newLogLine); } - -} \ No newline at end of file +} diff --git a/src/main/java/ch/ivyteam/ivy/maven/util/PathUtils.java b/src/main/java/ch/ivyteam/ivy/maven/util/PathUtils.java new file mode 100644 index 00000000..a9d3dfe0 --- /dev/null +++ b/src/main/java/ch/ivyteam/ivy/maven/util/PathUtils.java @@ -0,0 +1,47 @@ +package ch.ivyteam.ivy.maven.util; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; + +import org.apache.commons.lang3.StringUtils; + +public interface PathUtils { + + public static String toExtension(Path path) { + return toExtension(path.getFileName().toString()); + } + + public static String toExtension(String path) { + return StringUtils.substringAfterLast(path, "."); + } + + public static void delete(Path path) { + if (path == null) { + return; + } + if (!Files.exists(path)) { + return; + } + + try (var stream = Files.walk(path)) { + stream.sorted(Comparator.reverseOrder()) + .map(Path::toFile) + .forEach(File::delete); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + public static void clean(Path path) { + delete(path); + try { + Files.createDirectories(path); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } +} \ No newline at end of file diff --git a/src/test/java/ch/ivyteam/ivy/maven/BaseEngineProjectMojoTest.java b/src/test/java/ch/ivyteam/ivy/maven/BaseEngineProjectMojoTest.java index 5f39690b..9ad7a2c9 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/BaseEngineProjectMojoTest.java +++ b/src/test/java/ch/ivyteam/ivy/maven/BaseEngineProjectMojoTest.java @@ -23,17 +23,15 @@ import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; import java.util.concurrent.TimeUnit; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.SystemUtils; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.junit.Rule; import ch.ivyteam.ivy.maven.engine.EngineClassLoaderFactory; import ch.ivyteam.ivy.maven.util.ClasspathJar; +import ch.ivyteam.ivy.maven.util.PathUtils; import ch.ivyteam.ivy.maven.util.SharedFile; public class BaseEngineProjectMojoTest { @@ -73,13 +71,6 @@ private static String getLocalRepoPath() { return defaultHomePath.toString(); } - protected final static Collection findFiles(Path dir, String fileExtension) { - if (!Files.exists(dir)) { - return Collections.emptyList(); - } - return FileUtils.listFiles(dir.toFile(), new String[] {fileExtension}, true); - } - private static final Path evalEngineDir(AbstractEngineMojo mojo) { return mojo.engineCacheDirectory.resolve(System.getProperty("ivy.engine.version", AbstractEngineMojo.DEFAULT_VERSION)); } @@ -107,7 +98,7 @@ protected void before() throws Throwable { addTimestampToDownloadedEngine(); } - private void deleteOutdatedEngine() throws IOException { + private void deleteOutdatedEngine() { var engineDir = getMojo().getRawEngineDirectory(); if (engineDir == null || !Files.exists(engineDir)) { return; @@ -116,7 +107,7 @@ private void deleteOutdatedEngine() throws IOException { var timestampFile = engineDir.resolve(TIMESTAMP_FILE_NAME); if (isOlderThan24h(timestampFile.toFile())) { System.out.println("Deleting cached outdated engine."); - FileUtils.deleteDirectory(engineDir.toFile()); + PathUtils.delete(engineDir); } } @@ -181,7 +172,7 @@ protected void before() throws Throwable { private void provideClasspathJar() throws IOException { var cpJar = new SharedFile(project).getEngineOSGiBootClasspathJar(); new ClasspathJar(cpJar.toFile()).createFileEntries(EngineClassLoaderFactory - .getOsgiBootstrapClasspath(installUpToDateEngineRule.getMojo().getRawEngineDirectory().toFile())); + .getOsgiBootstrapClasspath(installUpToDateEngineRule.getMojo().getRawEngineDirectory())); } @Override diff --git a/src/test/java/ch/ivyteam/ivy/maven/ProjectMojoRule.java b/src/test/java/ch/ivyteam/ivy/maven/ProjectMojoRule.java index 4abb013d..7afbc8a5 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/ProjectMojoRule.java +++ b/src/test/java/ch/ivyteam/ivy/maven/ProjectMojoRule.java @@ -17,14 +17,16 @@ package ch.ivyteam.ivy.maven; import java.io.IOException; +import java.io.UncheckedIOException; import java.nio.file.Files; import java.nio.file.Path; -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.Mojo; import org.apache.maven.plugin.testing.MojoRule; import org.apache.maven.project.MavenProject; +import ch.ivyteam.ivy.maven.util.PathUtils; + /** * Simple rule that can provide a real set-up MOJO that works on a copy of the * given projectDirectory. This simplifies TEST dramatically whenever your MOJO @@ -51,21 +53,41 @@ public ProjectMojoRule(Path srcDir, String mojoName) { @SuppressWarnings("unchecked") protected void before() throws Throwable { projectDir = Files.createTempDirectory("MyBaseProject"); - FileUtils.copyDirectory(templateProjectDir.toFile(), projectDir.toFile()); + copyDirectory(templateProjectDir, projectDir); project = readMavenProject(projectDir.toFile()); mojo = (T) lookupConfiguredMojo(project, mojoName); } @Override protected void after() { - try { - FileUtils.deleteDirectory(projectDir.toFile()); - } catch (IOException ex) { - throw new RuntimeException(ex); - } + PathUtils.delete(projectDir); } public T getMojo() { return mojo; } + + private static void copyDirectory(Path source, Path target) { + try (var walker = Files.walk(source)) { + walker.forEach(fileToCopy -> { + if (fileToCopy.equals(source)) { + return; + } + var destination = source.relativize(fileToCopy); + var fileToMove = target.resolve(destination); + + try { + var dirToMove = fileToMove.getParent(); + if (!Files.exists(dirToMove)) { + Files.createDirectories(dirToMove); + } + Files.copy(fileToCopy, fileToMove); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + }); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } } \ No newline at end of file diff --git a/src/test/java/ch/ivyteam/ivy/maven/TestIarPackagingMojo.java b/src/test/java/ch/ivyteam/ivy/maven/TestIarPackagingMojo.java index d276c098..6808a5c5 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/TestIarPackagingMojo.java +++ b/src/test/java/ch/ivyteam/ivy/maven/TestIarPackagingMojo.java @@ -18,27 +18,26 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; -import org.apache.commons.io.FileUtils; import org.apache.maven.model.FileSet; -import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.MatchPattern; import org.codehaus.plexus.util.StringUtils; import org.junit.Rule; import org.junit.Test; +import ch.ivyteam.ivy.maven.util.PathUtils; + /** * @author Reguel Wermelinger * @since 03.11.2014 @@ -55,12 +54,11 @@ protected void before() throws Throwable { createEmptySrcDirs(); } - private void createEmptySrcDirs() throws IOException { + private void createEmptySrcDirs() { var emptySrcDirNames = List.of("src_dataClasses", "src_hd", "src_rd", "src_ws", "src_wsproc"); for (var emptySrcDirName : emptySrcDirNames) { var srcDir = projectDir.resolve(emptySrcDirName); - FileUtils.deleteDirectory(srcDir.toFile()); - Files.createDirectories(srcDir); + PathUtils.clean(srcDir); } } }; @@ -76,17 +74,18 @@ public void archiveCreationDefault() throws Exception { var svn = dir.resolve("svn.txt"); Files.writeString(svn, "svn"); mojo.execute(); - var targetDir = mojo.project.getBasedir().toPath().resolve("target").toFile(); - Collection iarFiles = FileUtils.listFiles(targetDir, new String[] {"iar"}, false); + var targetDir = mojo.project.getBasedir().toPath().resolve("target"); + + var iarFiles = iarFiles(targetDir); assertThat(iarFiles).hasSize(1); - File iarFile = iarFiles.iterator().next(); - assertThat(iarFile.getName()).isEqualTo("base-1.0.0.iar"); + var iarFile = iarFiles.getFirst(); + assertThat(iarFile).hasFileName("base-1.0.0.iar"); assertThat(mojo.project.getArtifact().getFile()) .as("Created IAR must be registered as artifact for later repository installation.") - .isEqualTo(iarFile); + .isEqualTo(iarFile.toFile()); - try (ZipFile archive = new ZipFile(iarFile)) { + try (ZipFile archive = new ZipFile(iarFile.toFile())) { assertThat(archive.getEntry(".classpath")).as(".classpath must be packed for internal binary retrieval") .isNotNull(); assertThat(archive.getEntry("src_hd")).as("Empty directories should be included (by default) " @@ -108,6 +107,12 @@ public void archiveCreationDefault() throws Exception { } } + private List iarFiles(Path dir) throws IOException { + try (var dirs = Files.list(dir)) { + return dirs.filter(p -> p.getFileName().toString().endsWith(".iar")).toList(); + } + } + @Test public void canDefineCustomExclusions() throws Exception { IarPackagingMojo mojo = rule.getMojo(); @@ -157,7 +162,7 @@ public void canOverwriteDefaultInclusions() throws Exception { mojo.execute(); try (ZipFile archive = new ZipFile(mojo.project.getArtifact().getFile())) { try (InputStream is = archive.getInputStream(archive.getEntry("pom.xml"))) { - String pomInArchive = IOUtil.toString(is); + String pomInArchive = new String(is.readAllBytes(), StandardCharsets.UTF_8); assertThat(pomInArchive) .as("customer should be able to overwrite pre-defined resource with their own includes.") .contains("flattened"); @@ -188,17 +193,17 @@ public void canExcludeEmptyDirectories() throws Exception { public void doNotPackTargetFolderIfThereAreNoTargetClasses() throws Exception { IarPackagingMojo mojo = rule.getMojo(); var targetClasses = mojo.project.getBasedir().toPath().resolve("target/classes"); - FileUtils.deleteDirectory(targetClasses.toFile()); + PathUtils.delete(targetClasses); mojo.execute(); var dir = mojo.project.getBasedir().toPath().resolve("target"); - Collection iarFiles = FileUtils.listFiles(dir.toFile(), new String[] {"iar"}, false); + var iarFiles = iarFiles(dir); assertThat(iarFiles).hasSize(1); - File iarFile = iarFiles.iterator().next(); - try (ZipFile archive = new ZipFile(iarFile)) { + var iarFile = iarFiles.getFirst(); + try (ZipFile archive = new ZipFile(iarFile.toFile())) { assertThat(archive.getEntry("target")) - .as("'target' will not be packed when there are no target/classes").isNull(); + .as("'target' will not be packed when there are no target/classes").isNull(); } } @@ -215,13 +220,13 @@ public void includeTarget_srcHdGenerated() throws Exception { mojo.execute(); var dir = mojo.project.getBasedir().toPath().resolve("target"); - Collection iarFiles = FileUtils.listFiles(dir.toFile(), new String[] {"iar"}, false); + var iarFiles = iarFiles(dir); assertThat(iarFiles).hasSize(1); - File iarFile = iarFiles.iterator().next(); - try (ZipFile archive = new ZipFile(iarFile)) { + var iarFile = iarFiles.getFirst(); + try (ZipFile archive = new ZipFile(iarFile.toFile())) { assertThat(archive.getEntry("target/src_hd/com/acme/FormDialog/FormDialog.xhtml")) - .as("generated jsf.dialog views are included").isNotNull(); + .as("generated jsf.dialog views are included").isNotNull(); } } diff --git a/src/test/java/ch/ivyteam/ivy/maven/TestInstallEngineMojo.java b/src/test/java/ch/ivyteam/ivy/maven/TestInstallEngineMojo.java index 6cb45881..32cd4a20 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/TestInstallEngineMojo.java +++ b/src/test/java/ch/ivyteam/ivy/maven/TestInstallEngineMojo.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; @@ -29,7 +30,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import org.apache.commons.io.IOUtils; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.wagon.proxy.ProxyInfo; import org.apache.wink.client.MockHttpServer; @@ -369,8 +369,10 @@ public void testEngineLinkFinder_multipleLinks() throws Exception { .isEqualTo("http://localhost/7.0.0/AxonIvyEngine7.0.0.46949_Linux_x86.zip"); } - private String findLink(String html) throws MojoExecutionException, MalformedURLException, URISyntaxException { - return getUrlDownloader().findEngineDownloadUrl(IOUtils.toInputStream(html, StandardCharsets.UTF_8)).toExternalForm(); + private String findLink(String html) throws MojoExecutionException, URISyntaxException, IOException { + try (var in = new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8))) { + return getUrlDownloader().findEngineDownloadUrl(in).toExternalForm(); + } } @Test diff --git a/src/test/java/ch/ivyteam/ivy/maven/TestShareEngineClasspathMojo.java b/src/test/java/ch/ivyteam/ivy/maven/TestShareEngineClasspathMojo.java index 0b04aea3..a18fd6eb 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/TestShareEngineClasspathMojo.java +++ b/src/test/java/ch/ivyteam/ivy/maven/TestShareEngineClasspathMojo.java @@ -22,7 +22,6 @@ import java.nio.file.Files; import java.nio.file.Path; -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.MojoExecutionException; import org.junit.Rule; import org.junit.Test; @@ -30,6 +29,7 @@ import ch.ivyteam.ivy.maven.engine.EngineClassLoaderFactory.OsgiDir; public class TestShareEngineClasspathMojo { + @Test public void engineClasspathIsSharedAsProperty() throws Exception { ShareEngineCoreClasspathMojo mojo = rule.getMojo(); @@ -38,7 +38,6 @@ public void engineClasspathIsSharedAsProperty() throws Exception { .isNullOrEmpty(); mojo.execute(); - assertThat(getEngineClasspathProperty()) .as("used classpath must be shared as property so that other mojos can access it") .contains("dummy-boot.jar"); @@ -68,11 +67,11 @@ private void writeEngineLibDir() { try { var engineDirectory = rule.getMojo().identifyAndGetEngineDirectory(); var dummy = engineDirectory.resolve(OsgiDir.INSTALL_AREA).resolve(OsgiDir.LIB_BOOT).resolve("dummy-boot.jar"); - FileUtils.touch(dummy.toFile()); + Files.createDirectories(dummy.getParent()); + Files.createFile(dummy); } catch (IOException | MojoExecutionException ex) { throw new RuntimeException("Cannot create server jars", ex); } - } }; } diff --git a/src/test/java/ch/ivyteam/ivy/maven/compile/TestCompileProjectMojo.java b/src/test/java/ch/ivyteam/ivy/maven/compile/TestCompileProjectMojo.java index ab4494ef..c6f3ff1d 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/compile/TestCompileProjectMojo.java +++ b/src/test/java/ch/ivyteam/ivy/maven/compile/TestCompileProjectMojo.java @@ -18,15 +18,17 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; -import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.Test; import ch.ivyteam.ivy.maven.BaseEngineProjectMojoTest; import ch.ivyteam.ivy.maven.log.LogCollector; +import ch.ivyteam.ivy.maven.util.PathUtils; public class TestCompileProjectMojo extends BaseEngineProjectMojoTest { private CompileTestProjectMojo testMojo; @@ -50,8 +52,8 @@ public void buildWithExistingProject() throws Exception { var dataClassDir = mojo.project.getBasedir().toPath().resolve("src_dataClasses"); var wsProcDir = mojo.project.getBasedir().toPath().resolve("src_wsproc"); var classDir = mojo.project.getBasedir().toPath().resolve("classes"); - FileUtils.cleanDirectory(wsProcDir.toFile()); - FileUtils.cleanDirectory(dataClassDir.toFile()); + PathUtils.clean(wsProcDir); + PathUtils.clean(dataClassDir); mojo.buildApplicationDirectory = Files.createTempDirectory("MyBuildApplication"); mojo.execute(); @@ -72,6 +74,17 @@ public void buildWithExistingProject() throws Exception { .hasSize(5); } + private static List findFiles(Path dir, String fileExtension) throws IOException { + if (!Files.exists(dir)) { + return List.of(); + } + try (var stream = Files.walk(dir)) { + return stream + .filter(p -> p.getFileName().toString().endsWith("." + fileExtension)) + .toList(); + } + } + @Test public void compilerSettingsFile_notFoundWarnings() throws Exception { LogCollector log = new LogCollector(); diff --git a/src/test/java/ch/ivyteam/ivy/maven/deploy/TestDeployToEngineMojo.java b/src/test/java/ch/ivyteam/ivy/maven/deploy/TestDeployToEngineMojo.java index 6130b838..2dab4cdb 100644 --- a/src/test/java/ch/ivyteam/ivy/maven/deploy/TestDeployToEngineMojo.java +++ b/src/test/java/ch/ivyteam/ivy/maven/deploy/TestDeployToEngineMojo.java @@ -24,13 +24,13 @@ import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; -import org.apache.commons.io.FileUtils; import org.apache.maven.plugin.MojoExecutionException; import org.junit.Rule; import org.junit.Test; import ch.ivyteam.ivy.maven.ProjectMojoRule; import ch.ivyteam.ivy.maven.engine.deploy.dir.DeploymentFiles; +import ch.ivyteam.ivy.maven.util.PathUtils; public class TestDeployToEngineMojo { @@ -180,7 +180,7 @@ protected void before() throws Throwable { } private Path createEngineDir() throws IOException { - var engine = Path.of("target/myTestIvyEngine"); + var engine = Path.of("target").resolve("myTestIvyEngine"); var deploy = engine.resolve("deploy"); Files.createDirectories(deploy); return engine.toAbsolutePath(); @@ -189,7 +189,7 @@ private Path createEngineDir() throws IOException { @Override protected void after() { super.after(); - FileUtils.deleteQuietly(getMojo().deployEngineDirectory.toFile()); + PathUtils.delete(getMojo().deployEngineDirectory); } }; diff --git a/src/test/java/ch/ivyteam/ivy/maven/util/TestPathUtils.java b/src/test/java/ch/ivyteam/ivy/maven/util/TestPathUtils.java new file mode 100644 index 00000000..ed1e83fc --- /dev/null +++ b/src/test/java/ch/ivyteam/ivy/maven/util/TestPathUtils.java @@ -0,0 +1,95 @@ +package ch.ivyteam.ivy.maven.util; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + + +class TestPathUtils { + + @Test + void toExtension_fromFilename() { + var path = Paths.get("test.pdf"); + assertThat(PathUtils.toExtension(path)).isEqualTo("pdf"); + } + + @Test + void toExtension_fromPath() { + var path = Paths.get("/root/folder/test.pdf"); + assertThat(PathUtils.toExtension(path)).isEqualTo("pdf"); + } + + @Test + void toExtension_missing() { + var path = Paths.get("test"); + assertThat(PathUtils.toExtension(path)).isEmpty(); + } + + @Test + void toExtension_string_fromFilename() { + assertThat(PathUtils.toExtension("test.pdf")).isEqualTo("pdf"); + } + + @Test + void toExtension_string_fromPath() { + assertThat(PathUtils.toExtension("/root/folder/test.pdf")).isEqualTo("pdf"); + } + + @Test + void toExtension_string_missing() { + assertThat(PathUtils.toExtension("test")).isEmpty(); + } + + @Test + void delete_null() { + assertThatNoException().isThrownBy(() -> PathUtils.delete(null)); + } + + @Test + void delete_nonExisting() { + assertThatNoException().isThrownBy(() -> PathUtils.delete(Path.of("non-existing-directory"))); + } + + @Test + void delete_emptyDir(@TempDir Path tempDir) { + assertThat(tempDir).exists(); + + PathUtils.delete(tempDir); + assertThat(tempDir).doesNotExist(); + } + + @Test + void delete_file(@TempDir Path tempDir) throws IOException { + var file = tempDir.resolve("louis.txt"); + Files.writeString(file, "müller"); + assertThat(file).exists(); + + PathUtils.delete(file); + assertThat(file).doesNotExist(); + } + + @Test + void delete_notEmptyFolder(@TempDir Path tempDir) throws IOException { + var file = tempDir.resolve("louis.txt"); + Files.writeString(file, "müller"); + assertThat(file).exists(); + + var subFolder = tempDir.resolve("subFolder"); + Files.createDirectory(subFolder); + assertThat(subFolder).exists(); + + var subFile = subFolder.resolve("chrischel.txt"); + Files.writeString(subFile, "strebschel"); + assertThat(subFile).exists(); + + PathUtils.delete(tempDir); + assertThat(tempDir).doesNotExist(); + } +}