maven ramdisk plugin
发布于
Top
maven

一直都想让maven的target目录放在内存盘,但把target mklink在mvn clean后又会消失,不够智能

发现了插件 https://plugin.maven.earcam.io/ramdisk/ 但不兼容 win

https://bitbucket.org/earcam/io.earcam.maven.plugin/src/master/

魔改之,只留一个类即可

parent pom.xml

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.earcam.maven</groupId>
    <artifactId>io.earcam.maven.plugin</artifactId>
    <version>0.0.4</version>
    <packaging>pom</packaging>

    <modules>
        <module>io.earcam.maven.plugin.ramdisk</module>
    </modules>

    <properties>
        <version.java.platform>8</version.java.platform>
        <version.java>1.${version.java.platform}</version.java>
        <maven.compiler.source>${version.java}</maven.compiler.source>
        <maven.compiler.target>${version.java}</maven.compiler.target>

        <earcam.project.root.artifactId>io.earcam.maven.plugin</earcam.project.root.artifactId>
        <coordinate.username.project>earcam/${earcam.project.root.artifactId}</coordinate.username.project>
        <version.slf4j>1.7.25</version.slf4j>
        <version.utilitarian>1.2.1</version.utilitarian>
        <version.instrumental>0.1.0</version.instrumental>
        <version.unexceptional>1.0.0</version.unexceptional>
        <version.maven>3.5.4</version.maven>

        <version.this.plugin>${project.version}</version.this.plugin>
    </properties>

    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>org.apache.maven</groupId>
                <artifactId>maven-plugin-api</artifactId>
                <version>${version.maven}</version>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.7.0</version>
                    <configuration>
                        <source>${maven.compiler.source}</source>
                        <target>${maven.compiler.target}</target>
                        <encoding>utf-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

io.earcam.maven.plugin.ramdisk\pom.xml

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<parent>
		<groupId>io.earcam.maven</groupId>
		<artifactId>io.earcam.maven.plugin</artifactId>
		<version>0.0.4</version>
	</parent>

	<groupId>io.earcam.maven.plugin</groupId>
	<artifactId>io.earcam.maven.plugin.ramdisk</artifactId>
	<packaging>maven-plugin</packaging>

	<properties>
		<earcam.project.name.short>ramdisk</earcam.project.name.short>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.apache.maven</groupId>
			<artifactId>maven-plugin-api</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-invoker-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<goals>
						<goal>package</goal>
					</goals>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
				<version>3.4.1</version>
				<executions>
					<execution>
						<id>fat-jar-for-mvn-home-lib-ext</id>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
						<configuration>
							<shadedClassifierName>uber</shadedClassifierName>
							<shadedArtifactAttached>true</shadedArtifactAttached>
							<artifactSet>
								<includes>
									<include>io.earcam*:*</include>
								</includes>
							</artifactSet>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>
package io.earcam.maven.plugin.ramdisk;

import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Scm;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.component.annotations.Component;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;

import static io.earcam.maven.plugin.ramdisk.RamdiskBuildExtension.NAME;

@Component(role = AbstractMavenLifecycleParticipant.class, hint = NAME, instantiationStrategy = "singleton")
public class RamdiskBuildExtension extends AbstractMavenLifecycleParticipant {

    static final String NAME = "ramdisk";

    Path tmpFsRoot = Paths.get("z:/");

    @Override
    public void afterProjectsRead(MavenSession session) {

        List<MavenProject> modules = session.getAllProjects();

        modules.forEach(this::createTmpFsBuildDir);
    }

    private void createTmpFsBuildDir(MavenProject project) {

        if (null != project.getPackaging() && project.getPackaging().equals("pom")) {
            return;
        }

        try {
            createTmpFsBuildDir(project, tmpFsRoot);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    static boolean isJunction(Path p) {
        boolean isJunction = false;
        try {
            isJunction = (p.compareTo(p.toRealPath()) != 0);
        } catch (IOException e) {

        }
        return isJunction;
    }

    static void createTmpFsBuildDir(MavenProject project, Path tmpFs) throws IOException {

        Path link = Paths.get(project.getBuild().getDirectory());
        Path linkTarget = tmpFs.resolve(relativePathFor(project));
        if (!linkTarget.toFile().exists()) {
            Files.createDirectories(linkTarget);
        }
        if (!link.toFile().exists()) {
            Runtime runtime = Runtime.getRuntime();
            runtime.exec(new String[]{"cmd", "/c", "mklink", "/j", link.toString(), linkTarget.toString()});
        } else {
            boolean junction = isJunction(link);
            if (!junction) {
                delete(link);
            }
            Runtime runtime = Runtime.getRuntime();
            runtime.exec(new String[]{"cmd", "/c", "mklink", "/j", link.toString(), linkTarget.toString()});
        }

    }

    static Path relativePathFor(MavenProject project) {
        Path linkTarget = Paths.get("maven", project.getGroupId(), project.getArtifactId(), project.getVersion());
        return appendScmTag(project, linkTarget);
    }

    private static Path appendScmTag(MavenProject project, Path linkTarget) {
        Scm scm = project.getScm();
        if (scm != null) {
            String tag = scm.getTag();
            if (tag != null && !tag.isEmpty()) {
                linkTarget = linkTarget.resolve(tag);
            }
        }
        return linkTarget;
    }

    @Override
    public void afterSessionEnd(MavenSession session) {
        session.getAllProjects().forEach(this::createTmpFsBuildDir);
    }


    public static void delete(Path path, LinkOption... options) throws IOException {
        recurse(path, new DeleteVisitor(path, options));
    }

    private static void recurse(Path source, AbstractVisitor visitor) throws IOException {
        boolean noFollow = Arrays.asList(visitor.options).contains(LinkOption.NOFOLLOW_LINKS);
        EnumSet<FileVisitOption> options = noFollow ? EnumSet.noneOf(FileVisitOption.class) : EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        Files.walkFileTree(source, options, Integer.MAX_VALUE, visitor);
    }

    private static final class DeleteVisitor extends AbstractVisitor {
        public DeleteVisitor(Path source, CopyOption... options) {
            super(source, source, options);
        }

        public FileVisitResult postVisitDirectory(Path directory) throws IOException {
            Files.delete(directory);
            return FileVisitResult.CONTINUE;
        }

        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
            Files.delete(file);
            return FileVisitResult.CONTINUE;
        }
    }

    abstract static class AbstractVisitor extends SimpleFileVisitor<Path> {
        final Path sink;

        final Path source;

        final CopyOption[] options;

        Path sinkSub;

        public AbstractVisitor(Path source, Path sink, CopyOption... options) {
            this.source = source;
            this.sink = sink;
            this.options = options;
        }

        public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
            this.sinkSub = this.sink.resolve(this.source.relativize(dir));
            this.sinkSub.toFile().mkdirs();
            return FileVisitResult.CONTINUE;
        }

        public FileVisitResult postVisitDirectory(Path directory, IOException thrown) throws IOException {
            super.postVisitDirectory(directory, thrown);
            return this.postVisitDirectory(directory);
        }

        protected abstract FileVisitResult postVisitDirectory(Path var1) throws IOException;

        public abstract FileVisitResult visitFile(Path var1, BasicFileAttributes var2) throws IOException;
    }
}