diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/OptimizeMojo.java b/eo-maven-plugin/src/main/java/org/eolang/maven/OptimizeMojo.java index 2783e9bd86..b7e0cd3d78 100644 --- a/eo-maven-plugin/src/main/java/org/eolang/maven/OptimizeMojo.java +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/OptimizeMojo.java @@ -51,6 +51,9 @@ import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.cactoos.scalar.Unchecked; +import org.eolang.maven.optimization.OptCached; +import org.eolang.maven.optimization.OptLambda; +import org.eolang.maven.optimization.Optimization; import org.eolang.parser.ParsingTrain; /** @@ -146,6 +149,14 @@ public final class OptimizeMojo extends SafeMojo { ) private boolean failOnWarning; + /** + * EO cache directory. + * @checkstyle MemberNameCheck (7 lines) + */ + @Parameter(property = "eo.cache") + @SuppressWarnings("PMD.ImmutableField") + private Path cache = Paths.get(System.getProperty("user.home")).resolve(".eo"); + @Override public void exec() throws IOException { final Collection sources = this.scopedTojos().select( @@ -176,7 +187,7 @@ public void exec() throws IOException { Executors.callable( () -> { try { - final XML optimized = this.optimize(src); + final XML optimized = this.optimization(tojo).apply(src); done.incrementAndGet(); if (this.shouldPass(optimized)) { tojo.set( @@ -236,6 +247,26 @@ public void exec() throws IOException { } } + /** + * Optimization for specific tojo. + * + * @param tojo Tojp + * @return Optimization for specific Tojo + */ + private Optimization optimization(final SynchronizedTojo tojo) { + final Optimization optimization; + if (tojo.exists(AssembleMojo.ATTR_HASH)) { + optimization = new OptCached( + new OptLambda(this::optimize), + this.cache.resolve(OptimizeMojo.OPTIMIZED) + .resolve(tojo.get(AssembleMojo.ATTR_HASH)) + ); + } else { + optimization = new OptLambda(this::optimize); + } + return optimization; + } + /** * Optimize XML file after parsing. * @@ -244,6 +275,9 @@ public void exec() throws IOException { * @throws FileNotFoundException If fails * @throws IllegalArgumentException If error is detected within XMIR and * fail on error is enabled. + * @todo #1431:90min move that method implementation to a separate class under + * {@link org.eolang.maven.optimization} package. Probably, after implementation we will able + * to remove {@link org.eolang.maven.optimization.OptLambda}. */ private XML optimize(final Path file) throws FileNotFoundException { final String name = new XMLDocument(file).xpath("/program/@name").get(0); diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/Place.java b/eo-maven-plugin/src/main/java/org/eolang/maven/Place.java index 694d5a74f4..d5c4d0a47e 100644 --- a/eo-maven-plugin/src/main/java/org/eolang/maven/Place.java +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/Place.java @@ -31,7 +31,7 @@ * * @since 0.1 */ -final class Place { +public final class Place { /** * The name of the object, e.g. "org.eolang.io.stdout" @@ -42,7 +42,7 @@ final class Place { * Ctor. * @param obj The name of the object */ - Place(final String obj) { + public Place(final String obj) { this.name = obj; } diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/OptCached.java b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/OptCached.java new file mode 100644 index 0000000000..6569a686f5 --- /dev/null +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/OptCached.java @@ -0,0 +1,91 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2022 Objectionary.com + * + * 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 NON-INFRINGEMENT. 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 org.eolang.maven.optimization; + +import com.jcabi.xml.XML; +import com.jcabi.xml.XMLDocument; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import org.eolang.maven.AssembleMojo; +import org.eolang.maven.Place; + +/** + * The cached optimization. + * Returns already optimized XML if it's found in the cache. + * + * @since 0.28.11 + * @todo #1431:90min Unit test are required. We have to test different cases like: + * - if XML file is already in cache + * - if XML file is absent + * - if some {@link java.io.IOException} happens + */ +public final class OptCached implements Optimization { + + /** + * Real optimization. + */ + private final Optimization delegate; + + /** + * Cache folder. + */ + private final Path folder; + + /** + * The main constructor. + * + * @param delegate Real optimization. + * @param folder Cache folder. + */ + public OptCached( + final Optimization delegate, + final Path folder + ) { + this.delegate = delegate; + this.folder = folder; + } + + @Override + public XML apply(final Path xml) { + try { + final Path path = new Place( + new XMLDocument(xml).xpath("/program/@name").get(0) + ).make(this.folder, AssembleMojo.ATTR_XMIR); + final XML optimized; + if (Files.exists(path)) { + optimized = new XMLDocument(path); + } else { + optimized = this.delegate.apply(xml); + Files.createDirectories(path.getParent()); + Files.createFile(path); + Files.write(path, optimized.toString().getBytes(StandardCharsets.UTF_8)); + } + return optimized; + } catch (final IOException ex) { + throw new IllegalStateException(String.format("Can't optimize '%s'", xml), ex); + } + } +} diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/OptLambda.java b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/OptLambda.java new file mode 100644 index 0000000000..9190e94cde --- /dev/null +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/OptLambda.java @@ -0,0 +1,57 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2022 Objectionary.com + * + * 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 NON-INFRINGEMENT. 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 org.eolang.maven.optimization; + +import com.jcabi.xml.XML; +import java.nio.file.Path; +import org.cactoos.Func; +import org.cactoos.func.UncheckedFunc; + +/** + * Lambda optimization is adapter for custom optimization. + * Optimization provided by external function. + * + * @since 0.28.11 + */ +public final class OptLambda implements Optimization { + + /** + * Custom foreign optimisation. + */ + private final UncheckedFunc delegate; + + /** + * The main constructor. + * + * @param delegate Custom optimization. + */ + public OptLambda(final Func delegate) { + this.delegate = new UncheckedFunc<>(delegate); + } + + @Override + public XML apply(final Path xml) { + return this.delegate.apply(xml); + } +} diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/Optimization.java b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/Optimization.java new file mode 100644 index 0000000000..e008e58a0d --- /dev/null +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/Optimization.java @@ -0,0 +1,37 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2022 Objectionary.com + * + * 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 NON-INFRINGEMENT. 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 org.eolang.maven.optimization; + +import com.jcabi.xml.XML; +import java.nio.file.Path; +import java.util.function.Function; + +/** + * Abstraction for XML optimizations. + * + * @since 0.28.11 + */ +@FunctionalInterface +public interface Optimization extends Function { +} diff --git a/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/package-info.java b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/package-info.java new file mode 100644 index 0000000000..45c54c0d29 --- /dev/null +++ b/eo-maven-plugin/src/main/java/org/eolang/maven/optimization/package-info.java @@ -0,0 +1,31 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2016-2022 Objectionary.com + * + * 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 NON-INFRINGEMENT. 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. + */ +/** + * Optimizations package. + * The main purpose of classes under the package is to provide different implementations + * of xml optimizations: + * - {@link org.eolang.maven.optimization.OptLambda} - makes an optimization using foreign function + * - {@link org.eolang.maven.optimization.OptCached} - looks for optimization in cache first + */ +package org.eolang.maven.optimization; diff --git a/eo-maven-plugin/src/test/java/org/eolang/maven/OptimizeMojoTest.java b/eo-maven-plugin/src/test/java/org/eolang/maven/OptimizeMojoTest.java index 2152373a97..09401117cc 100644 --- a/eo-maven-plugin/src/test/java/org/eolang/maven/OptimizeMojoTest.java +++ b/eo-maven-plugin/src/test/java/org/eolang/maven/OptimizeMojoTest.java @@ -40,7 +40,6 @@ import org.hamcrest.Matchers; import org.hamcrest.io.FileMatchers; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -137,13 +136,8 @@ void optimizesIfExpired(@TempDir final Path temp) throws Exception { * * @param temp Temporary test directory. * @throws Exception if unexpected error happened. - * @todo #1223:90min Implement caching for optimization step. After implementation don't forget - * to remove '@Disabled' annotation from the next tests: - * - 'getsAlreadyOptimizedResultsFromCache' - * - 'savesOptimizedResultsToCache' */ @Test - @Disabled void getsAlreadyOptimizedResultsFromCache(@TempDir final Path temp) throws Exception { final Path src = temp.resolve("foo/main.eo"); new Home(temp).save( @@ -194,7 +188,6 @@ void getsAlreadyOptimizedResultsFromCache(@TempDir final Path temp) throws Excep } @Test - @Disabled void savesOptimizedResultsToCache(@TempDir final Path temp) throws Exception { final Path src = temp.resolve("foo/main.eo"); new Home(temp).save(