From b262638c713362e021b3b6e344884f5bc2aa8e3c Mon Sep 17 00:00:00 2001 From: Philip Helger Date: Mon, 10 Feb 2025 13:51:53 +0100 Subject: [PATCH] Added the targetDirectory propert to the Maven plugin; #106 --- README.md | 8 +- .../maven/csscompress/CSSCompressMojo.java | 101 ++++++++++++++---- 2 files changed, 88 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index be57d3b4..bb26d319 100644 --- a/README.md +++ b/README.md @@ -252,8 +252,11 @@ Replace `x.y.z` with the version you want to use. Configuration items are: * `File` **sourceDirectory** - The directory where the CSS files reside. It must be an existing directory. + The directory where the source CSS files reside. It must be an existing directory. Defaults to `${basedir}/src/main/resources` +* `File` **targetDirectory** + The directory where the taget CSS files reside. If the directory is not existig, it is created. + Defaults to the source directory * `boolean` **recursive** Should all directories be scanned recursively for CSS files to compress? Defaults to `true` @@ -313,9 +316,10 @@ Configuration items are: * v7.0.4 - work in progress * Added additional media query features. See [#104}(https://github.com/phax/ph-css/pull/104) - thx @nhubbard - * Added new setting `CSSReaderSettings.setKeepDeprecatedProperties(boolean)` to customize if they should be read or discarded. See [#107}(https://github.com/phax/ph-css/issues/107) - thx @hrozhkov1 + * Added new setting `CSSReaderSettings.setKeepDeprecatedProperties(boolean)` to customize if they should be read or discarded. See [#107](https://github.com/phax/ph-css/issues/107) - thx @hrozhkov1 * Added the property `keepDeprecatedProperties` to the Maven plugin * Changed the default reading charset of the Maven plugin from `UTF-8` to `ISO-8859-1` to comply to the API based reading + * Added the `targetDirectory` property to the Maven plugin. See [#106](https://github.com/phax/ph-css/issues/106) - thx @isochronous * v7.0.3 - 2024-09-23 * Added support for the `:is`, `:has` and `:where` pseudo functions, fixing [#88](https://github.com/phax/ph-css/issues/88) (thx @brbog), [#97](https://github.com/phax/ph-css/issues/97) (thx @nafg) and [#101](https://github.com/phax/ph-css/issues/101) (thx @subbudvk) * v7.0.2 - 2024-03-28 diff --git a/ph-csscompress-maven-plugin/src/main/java/com/helger/maven/csscompress/CSSCompressMojo.java b/ph-csscompress-maven-plugin/src/main/java/com/helger/maven/csscompress/CSSCompressMojo.java index 9a65a316..84accb47 100644 --- a/ph-csscompress-maven-plugin/src/main/java/com/helger/maven/csscompress/CSSCompressMojo.java +++ b/ph-csscompress-maven-plugin/src/main/java/com/helger/maven/csscompress/CSSCompressMojo.java @@ -20,6 +20,8 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.Locale; +import java.util.function.Function; import javax.annotation.Nonnull; @@ -30,15 +32,16 @@ import com.helger.commons.charset.CharsetHelper; import com.helger.commons.io.EAppend; import com.helger.commons.io.file.FileHelper; +import com.helger.commons.io.file.FileOperationManager; import com.helger.commons.io.file.FilenameHelper; import com.helger.commons.io.resource.FileSystemResource; import com.helger.commons.system.ENewLineMode; +import com.helger.commons.system.EOperatingSystem; import com.helger.css.CCSS; import com.helger.css.CSSFilenameHelper; import com.helger.css.ECSSVersion; import com.helger.css.decl.CascadingStyleSheet; import com.helger.css.handler.ICSSParseExceptionCallback; -import com.helger.css.parser.ParseException; import com.helger.css.reader.CSSReader; import com.helger.css.reader.CSSReaderSettings; import com.helger.css.writer.CSSWriter; @@ -69,7 +72,8 @@ public final class CSSCompressMojo extends AbstractMojo private MavenProject project; /** - * The directory where the CSS files reside. It must be an existing directory. + * The directory where the source CSS files reside. It must be an existing + * directory. * * @required * @parameter property="sourceDirectory" @@ -77,6 +81,15 @@ public final class CSSCompressMojo extends AbstractMojo */ private File sourceDirectory; + /** + * The directory where the target CSS files reside. If the directory is not + * existing, it is created. If no target directory is provided, the source + * directory will be used. + * + * @parameter property="targetDirectory" + */ + private File targetDirectory; + /** * Should all directories be scanned recursively for CSS files to compress? * @@ -228,15 +241,23 @@ public final class CSSCompressMojo extends AbstractMojo private ENewLineMode newLineMode = CSSWriterSettings.DEFAULT_NEW_LINE_MODE; @SuppressFBWarnings ({ "NP_UNWRITTEN_FIELD", "UWF_UNWRITTEN_FIELD" }) - public void setSourceDirectory (final File aDir) + public void setSourceDirectory (final File aDir) throws IOException { sourceDirectory = aDir; if (!sourceDirectory.isAbsolute ()) - sourceDirectory = new File (project.getBasedir (), aDir.getPath ()); + sourceDirectory = new File (project.getBasedir (), aDir.getPath ()).getCanonicalFile (); if (!sourceDirectory.exists ()) getLog ().error ("CSS source directory '" + sourceDirectory + "' does not exist!"); } + public void setTargetDirectory (final File aDir) throws IOException + { + targetDirectory = aDir; + if (!targetDirectory.isAbsolute ()) + targetDirectory = new File (project.getBasedir (), aDir.getPath ()).getCanonicalFile (); + // The creation happens below, if the prerequisites are fulfilled + } + public void setRecursive (final boolean bRecursive) { recursive = bRecursive; @@ -363,37 +384,57 @@ private static boolean _isAlreadyCompressed (final String sFilename) } @Nonnull - private String _getRelativePath (@Nonnull final File aFile) + private String _getSourceRelativePath (@Nonnull final File aFile) { return aFile.getAbsolutePath ().substring (sourceDirectory.getAbsolutePath ().length () + 1); } - private void _compressCSSFile (@Nonnull final File aChild) + private void _compressCSSFile (@Nonnull final File aSourceFile) { + final String sSourceRelativePath = _getSourceRelativePath (aSourceFile); + // Compress the file only if the compressed file is older than the original // file. Note: lastModified on a non-existing file returns 0L - final File aCompressed = new File (FilenameHelper.getWithoutExtension (aChild.getAbsolutePath ()) + - targetFileExtension); - if (aCompressed.lastModified () < aChild.lastModified () || forceCompress) + final boolean bTargetDirEqualsSourceDir = targetDirectory == null || + targetDirectory.getAbsolutePath () + .equals (sourceDirectory.getAbsolutePath ()); + final File aCompressedFile; + { + if (bTargetDirEqualsSourceDir) + { + // Use the custom extension + aCompressedFile = new File (FilenameHelper.getWithoutExtension (aSourceFile.getAbsolutePath ()) + + targetFileExtension); + } + else + { + // Source and target are different + aCompressedFile = new File (targetDirectory, + FilenameHelper.getWithoutExtension (sSourceRelativePath) + targetFileExtension); + } + } + + if (aCompressedFile.lastModified () < aSourceFile.lastModified () || forceCompress) { if (verbose) - getLog ().info ("Start compressing CSS file " + _getRelativePath (aChild)); + getLog ().info ("Start compressing CSS file " + sSourceRelativePath); else - getLog ().debug ("Start compressing CSS file " + _getRelativePath (aChild)); - final ICSSParseExceptionCallback aExHdl = (@Nonnull final ParseException ex) -> getLog ().error ("Failed to parse CSS file " + - _getRelativePath (aChild), - ex); + getLog ().debug ("Start compressing CSS file " + sSourceRelativePath); + + final ICSSParseExceptionCallback aExHdl = ex -> getLog ().error ("Failed to parse CSS file " + + sSourceRelativePath, + ex); final Charset aFallbackCharset = CharsetHelper.getCharsetFromName (sourceEncoding); final CSSReaderSettings aSettings = new CSSReaderSettings ().setCSSVersion (ECSSVersion.CSS30) .setFallbackCharset (aFallbackCharset) .setCustomExceptionHandler (aExHdl) .setBrowserCompliantMode (browserCompliantMode) .setKeepDeprecatedProperties (keepDeprecatedProperties); - final CascadingStyleSheet aCSS = CSSReader.readFromFile (aChild, aSettings); + final CascadingStyleSheet aCSS = CSSReader.readFromFile (aSourceFile, aSettings); if (aCSS != null) { // We read it! - final FileSystemResource aDestFile = new FileSystemResource (aCompressed); + final FileSystemResource aDestFile = new FileSystemResource (aCompressedFile); try { final CSSWriterSettings aWriterSettings = new CSSWriterSettings (ECSSVersion.CSS30); @@ -415,16 +456,16 @@ private void _compressCSSFile (@Nonnull final File aChild) } catch (final IOException ex) { - getLog ().error ("Failed to write compressed CSS file '" + aCompressed.toString () + "' to disk", ex); + getLog ().error ("Failed to write compressed CSS file '" + aCompressedFile.toString () + "' to disk", ex); } } } else { if (verbose) - getLog ().info ("Ignoring already compressed CSS file " + _getRelativePath (aChild)); + getLog ().info ("Ignoring already compressed CSS file " + sSourceRelativePath); else - getLog ().debug ("Ignoring already compressed CSS file " + _getRelativePath (aChild)); + getLog ().debug ("Ignoring already compressed CSS file " + sSourceRelativePath); } } @@ -453,6 +494,28 @@ public void execute () throws MojoExecutionException { if (verbose) getLog ().info ("Start compressing CSS files in directory " + sourceDirectory.getPath ()); + + // Consistency check + if (targetDirectory != null) + { + // Case insensitive comparison on Windows + final boolean bCaseInsensitiveOS = EOperatingSystem.getCurrentOS ().isWindowsBased (); + final Function fGetPath = bCaseInsensitiveOS ? f -> f.getAbsolutePath ().toLowerCase (Locale.ROOT) + : File::getAbsolutePath; + + if (recursive && fGetPath.apply (targetDirectory).startsWith (fGetPath.apply (sourceDirectory))) + { + throw new IllegalStateException ("Target directory MUST NOT be a child of the source directory in recursive mode"); + } + + // Make sure, target directory exists + if (!targetDirectory.exists ()) + { + getLog ().info ("CSS target directory '" + targetDirectory + "' does not exist and will be created!"); + FileOperationManager.INSTANCE.createDirRecursive (targetDirectory); + } + } + _scanDirectory (sourceDirectory); } }