All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tinkerpop.gremlin.groovy.util.DependencyGrabber.groovy Maven / Gradle / Ivy

The newest version!
package com.tinkerpop.gremlin.groovy.util

import com.tinkerpop.gremlin.groovy.plugin.Artifact
import groovy.grape.Grape
import org.apache.commons.lang3.SystemUtils

import java.nio.file.*
import java.util.jar.JarFile
import java.util.jar.Manifest

/**
 * This class is a rough copy of the {@code InstallCommand} in Gremlin Console.  There are far more detailed
 * comments there with respect to the workings of this class.
 *
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
class DependencyGrabber {

    private final static String fileSep = System.getProperty("file.separator")
    private final ClassLoader classLoaderToUse
    private final String extensionDirectory

    public DependencyGrabber(final ClassLoader cl, final String extensionDirectory) {
        this.classLoaderToUse = cl
        this.extensionDirectory = extensionDirectory
    }

    def void copyDependenciesToPath(final Artifact artifact) {
        final def dep = makeDepsMap(artifact)
        final String extClassPath = getPathFromDependency(dep)
        final File f = new File(extClassPath)

        if (f.exists()) throw new IllegalStateException("a module with the name ${dep.module} is already installed")
        if (!f.mkdirs()) throw new IOException("could not create directory at ${f}")

        new File(extClassPath + fileSep + "plugin-info.txt").withWriter { out -> out << [artifact.group, artifact.artifact, artifact.version].join(":") }

        def fs = FileSystems.default
        def target = fs.getPath(extClassPath)

        def filesAlreadyInPath = []
        def libClassPath
        try {
            libClassPath = fs.getPath(System.getProperty("user.dir") + fileSep + "lib")
            getFileNames(filesAlreadyInPath, libClassPath)
        } catch (Exception ignored) {
            println "Detected a non-standard Gremlin directory structure during install.  Expecting a 'lib' " +
                    "directory sibling to 'ext'. This message does not necessarily imply failure, however " +
                    "the console requires a certain directory structure for proper execution. Altering that " +
                    "structure can lead to unexpected behavior."
        }

        final def dependencyLocations = [] as Set
        dependencyLocations.addAll(Grape.resolve([classLoader: this.classLoaderToUse], null, dep))

        // if windows then the path contains a starting forward slash that prevents it from being
        // recognized by FileSystem - strip it off
        dependencyLocations.collect {
            def p = SystemUtils.IS_OS_WINDOWS ? it.path.substring(1) : it.path
            return fs.getPath(p)
        }
        .findAll { !(it.fileName.toFile().name ==~ /(slf4j|logback\-classic)-.*\.jar/) }
                .findAll {
            !filesAlreadyInPath.collect { it.getFileName().toString() }.contains(it.fileName.toFile().name)
        }.each {
            def copying = target.resolve(it.fileName)
            Files.copy(it, copying, StandardCopyOption.REPLACE_EXISTING)
            println "Copying - $copying"
        }

        getAdditionalDependencies(target, artifact).collect { fs.getPath(it.path) }
                .findAll { !(it.fileName.toFile().name ==~ /(slf4j|logback\-classic)-.*\.jar/) }
                .findAll {
            !filesAlreadyInPath.collect { it.getFileName().toString() }.contains(it.fileName.toFile().name)
        }.each {
            def copying = target.resolve(it.fileName)
            Files.copy(it, copying, StandardCopyOption.REPLACE_EXISTING)
            println "Copying - $copying"
        }

        alterPaths(target, artifact)
    }

    private Set getAdditionalDependencies(final Path extPath, final Artifact artifact) {
        try {
            def pathToInstalled = extPath.resolve(artifact.artifact + "-" + artifact.version + ".jar")
            final JarFile jar = new JarFile(pathToInstalled.toFile())
            final Manifest manifest = jar.getManifest()
            def attrLine = manifest.mainAttributes.getValue("Gremlin-Plugin-Dependencies")
            def additionalDependencies = [] as Set
            if (attrLine != null) {
                def splitLine = attrLine.split(";")
                splitLine.each {
                    def artifactBits = it.split(":")
                    def additional = new Artifact(artifactBits[0], artifactBits[1], artifactBits[2])

                    final def additionalDep = makeDepsMap(additional)
                    additionalDependencies.addAll(Grape.resolve([classLoader: this.classLoaderToUse], null, additionalDep))
                }
            }

            return additionalDependencies
        } catch (Exception ex) {
            throw new RuntimeException(ex)
        }
    }

    private static alterPaths(final Path extPath, final Artifact artifact) {
        try {
            def pathToInstalled = extPath.resolve(artifact.artifact + "-" + artifact.version + ".jar")
            final JarFile jar = new JarFile(pathToInstalled.toFile());
            final Manifest manifest = jar.getManifest()
            def attrLine = manifest.mainAttributes.getValue("Gremlin-Plugin-Paths")
            if (attrLine != null) {
                def splitLine = attrLine.split(";")
                splitLine.each {
                    def kv = it.split("=")
                    Files.move(extPath.resolve(kv[0]), extPath.resolve(kv[1]), StandardCopyOption.REPLACE_EXISTING)
                }
            }
        } catch (Exception ex) {
            throw new RuntimeException(ex)
        }
    }

    private String getPathFromDependency(final Map dep) {
        def fileSep = System.getProperty("file.separator")
        return this.extensionDirectory + fileSep + (String) dep.module
    }

    private def makeDepsMap(final Artifact artifact) {
        final Map map = new HashMap<>()
        map.put("classLoader", this.classLoaderToUse)
        map.put("group", artifact.getGroup())
        map.put("module", artifact.getArtifact())
        map.put("version", artifact.getVersion())
        map.put("changing", false)
        return map
    }

    private static void getFileNames(final List fileNames, final Path dir) {
        final DirectoryStream stream = Files.newDirectoryStream(dir)
        for (Path path : stream) {
            if (path.toFile().isDirectory()) getFileNames(fileNames, path)
            else {
                fileNames.add(path.toAbsolutePath())
            }
        }
        stream.close()
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy