0

I have created a new Maven mojo plugin. I want to rename some generated files from another plugin, replace content for some files.

This is my mojo:

package com.mymojo.maven.plugins;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
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.StandardOpenOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.DatatypeConverter;

@Mojo(name = "versionalize")
public class VersionalizeMojo extends AbstractMojo {
    /**
     * Location of the file.
     */
    @Parameter(property = "outputDir", defaultValue = "${project.build.directory}/${project.build.finalName}", required = true)
    private File outputDirectory;

    @Parameter(property = "fileExt", defaultValue = "js|css")
    private String fileExt;

    @Parameter(property = "fileReplaceExt", defaultValue = "html|jsp|vm")
    private String fileReplaceExt;

    @Parameter(property = "excludeDir")
    private String excludeDir;

    private final String extPattern = "([^\\s]+(\\.(?i)(#))$)";

    Map<String, String> filenameMap;

    public void execute() throws MojoExecutionException, MojoFailureException {
        if (outputDirectory.exists()) {
            Path start = FileSystems.getDefault().getPath(outputDirectory.getPath());
            try {

                // create a copy of resources with md5 hashed names
                Files.walkFileTree(start, new MD5HasherFileVisitor());

                // replace all references to old files with new names
                Files.walkFileTree(start, new ReplacerFileVisitor());
            } catch (IOException e) {
                throw new MojoExecutionException(e.getMessage(), e);
            }
        } else {
            getLog().error("Not found");
        }
    }

    private class MD5HasherFileVisitor extends SimpleFileVisitor<Path> {
        Pattern pattern;

        public MD5HasherFileVisitor() {
            String regex = extPattern.replace("#", fileExt);
            pattern = Pattern.compile(regex);
            filenameMap = new HashMap<String, String>();
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            Matcher matcher = pattern.matcher(file.toString());
            if (matcher.matches()) {
                try {
                    MessageDigest md = MessageDigest.getInstance("MD5");
                    md.update(Files.readAllBytes(file));
                    byte[] digest = md.digest();
                    String checksum = DatatypeConverter.printHexBinary(digest).toUpperCase();
                    String newFilename = checksum + "-" + file.getFileName();
                    Path target = FileSystems.getDefault().getPath(file.getParent().toString(), newFilename);
                    getLog().info("File:" + file + " -> " + newFilename);
                    Files.move(file, target, StandardCopyOption.ATOMIC_MOVE);
                    filenameMap.put(file.getFileName().toString(), target.getFileName().toString());
                } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                }
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            getLog().info("Failed: " + file);
            return FileVisitResult.CONTINUE;
        }
    }

    private class ReplacerFileVisitor extends SimpleFileVisitor<Path> {
        Pattern pattern;

        public ReplacerFileVisitor() {
            String regex = extPattern.replace("#", fileReplaceExt);
            pattern = Pattern.compile(regex);
        }

        @Override
        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            Matcher matcher = pattern.matcher(file.toString());
            Charset charset = StandardCharsets.UTF_8;
            if (matcher.matches()) {
                String content = new String(Files.readAllBytes(file), charset);
                for (String f : filenameMap.keySet()) {
                    content = content.replaceAll(f, filenameMap.get(f));
                }
                Files.write(file, content.getBytes(charset));
                getLog().info("Replaced: " + file.getFileName());
            }
            return FileVisitResult.CONTINUE;
        }

        @Override
        public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
            getLog().info("Failed: " + file);
            return FileVisitResult.CONTINUE;
        }
    }
}

The plugin will be used like this:

<plugin>
    <groupId>com.mymojo.maven.plugins</groupId>
    <artifactId>mymojo-maven-plugin</artifactId>
    <version>1.0.0</version>
    <executions>
        <execution>
            <phase>prepare-package</phase>
            <goals>
                <goal>versionalize</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The issue I am facing is existing file is not replaced with new content. If I write to new file, the content is saving. I tried deleting the file and creating new one. But it does not work

sajux
  • 106
  • 1
  • 8
  • First question I have why do you read the content of the files if you only want to rename a file? – khmarbaise Nov 22 '18 at 14:05
  • to generate a md5 hash and rename file with hash – sajux Nov 22 '18 at 14:07
  • md5 hash should not be used anymore furthermore in target folder the checksums should never exist there...only files in target folder can be renamed and no need for checksums...apart from that the checksum is calculated based on the content and not based on the filename... – khmarbaise Nov 22 '18 at 14:09
  • That's fine. I can replace that. I am trying to rename files in target folders. As I said, I can create new files but cannot delete files using the Files.* API. No error. Just failing silently – sajux Nov 22 '18 at 14:11
  • Can you post the plugin code etc. and the output during running ? Please also activate the execution with debugging `-X ..` – khmarbaise Nov 22 '18 at 14:13
  • I run your code successfully by just replacing "/${project.build.finalName}" with "/classes" in your outputDirectory configuration. I put a.html and b.js files in my resources folder. b.js file got a hash code prefix and also present in jar. And a.html was containing a dummy b.js string inside and I saw it's replaced with that new file name as well. – hsnkhrmn Nov 22 '18 at 17:30
  • @hsnkhrmn what happens when you don't change the configuration? – sajux Nov 22 '18 at 19:55
  • fyi, I will be using this plugin in a war project – sajux Nov 22 '18 at 20:00
  • As I understand, you're creating a new directory (with final name of pkg?) and manually put resources there. My test is building a jar, without additional hacks, so only considers resources under target/classes directory. So without change I got missing directory error. Not sure about your complete pom, but seems like there is another plugin kicks in after yours and ruins your changes. You can validate this by debugging your plugin (see tutorials on net) or print more logs i.e. newFiles.exists() or printContents(modifiedFile). – hsnkhrmn Nov 23 '18 at 08:47
  • thanks for your support. I found that there was another plugin that was replacing the output of my plugin – sajux Nov 25 '18 at 09:16

0 Answers0