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

io.github.pixee.maven.operator.QueryByParsing.kt Maven / Gradle / Ivy

@file:Suppress("DEPRECATION")

package io.github.pixee.maven.operator

import org.apache.commons.lang3.builder.CompareToBuilder
import org.apache.commons.lang3.text.StrSubstitutor
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.util.*

/**
 * this one is a bit more complex, as it intents to to a "best effort" attempt at parsing a pom
 * focusing only on dependency right now,  * without relying to any maven infrastructure at all
 */
class QueryByParsing : AbstractQueryCommand() {
    override fun extractDependencyTree(outputPath: File, pomFilePath: File, c: ProjectModel) {
        TODO("Not yet implemented")
    }

    private val dependencies: MutableSet = LinkedHashSet()

    private val dependencyManagement: MutableSet =
        TreeSet(object : Comparator {
            override fun compare(o1: Dependency?, o2: Dependency?): Int {
                if (o1 == o2)
                    return 0

                if (o1 == null)
                    return 1

                if (o2 == null)
                    return -1

                return CompareToBuilder().append(o1.groupId, o2.groupId)
                    .append(o1.artifactId, o2.artifactId).toComparison()
            }
        })

    private val properties: MutableMap = LinkedHashMap()

    private val strSubstitutor = StrSubstitutor(properties)

    override fun execute(pm: ProjectModel): Boolean {
        /**
         * Enlist all pom files given an hierarchy
         */
        val pomFilesByHierarchy = pm.allPomFiles.reversed()

        for (pomDocument in pomFilesByHierarchy) {
            updateProperties(pomDocument)

            updateDependencyManagement(pomDocument)

            updateDependencies(pomDocument)
        }

        this.result = dependencies

        return true
    }

    private fun updateDependencyManagement(pomDocument: POMDocument) {
        val dependencyManagementDependenciesToAdd: Collection =
            pomDocument.pomDocument.//
            rootElement. //
            element("dependencyManagement")?. //
            element("dependencies")?. //
            elements("dependency")?. //
            map { dependencyElement ->
                val groupId = dependencyElement.element("groupId").text
                val artifactId = dependencyElement.element("artifactId").text

                val version = dependencyElement.element("version")?.text ?: "UNKNOWN"

                val classifier = dependencyElement.element("classifier")?.text
                val packaging = dependencyElement.element("packaging")?.text

                val versionInterpolated = try {
                    strSubstitutor.replace(version)
                } catch (e: java.lang.IllegalStateException) {
                    LOGGER.warn("while interpolating version", e)

                    "UNKNOWN"
                }

                Dependency(groupId, artifactId, versionInterpolated, classifier, packaging)
            }?.toList() ?: emptyList()

        this.dependencyManagement.addAll(dependencyManagementDependenciesToAdd)
    }

    fun lookForDependencyManagement(groupId: String, artifactId: String): Dependency? =
        this.dependencyManagement.firstOrNull { it.groupId == groupId && it.artifactId == artifactId }

    private fun updateDependencies(pomDocument: POMDocument) {
        val dependenciesToAdd: Collection =
            pomDocument.pomDocument.//
            rootElement. //
            element("dependencies")?. //
            elements("dependency")?. //
            map { dependencyElement ->
                val groupId = dependencyElement.element("groupId").text
                val artifactId = dependencyElement.element("artifactId").text

                val versionElement = dependencyElement.element("version")

                val proposedDependency = lookForDependencyManagement(groupId, artifactId)

                if (versionElement == null && null != proposedDependency) {
                    proposedDependency
                } else {
                    val version = versionElement?.text ?: "UNKNOWN"

                    val classifier = dependencyElement.element("classifier")?.text
                    val packaging = dependencyElement.element("packaging")?.text

                    val versionInterpolated = try {
                        strSubstitutor.replace(version)
                    } catch (e: java.lang.IllegalStateException) {
                        LOGGER.warn("while interpolating version", e)

                        "UNKNOWN"
                    }

                    Dependency(groupId, artifactId, versionInterpolated, classifier, packaging)
                }
            }?.toList() ?: emptyList()

        this.dependencies.addAll(
            dependenciesToAdd
        )
    }

    /**
     * Updates the Properties member variable based on whats on the POMDocument
     */
    private fun updateProperties(pomDocument: POMDocument) {
        val propsDefined = ProjectModel.propertiesDefinedOnPomDocument(pomDocument)

        propsDefined.entries.filterNot { it.value.matches(RE_INTERPOLATION) }
            .forEach {
                properties[it.key] = it.value
            }

        propsDefined.entries.filterNot { it.value.matches(RE_INTERPOLATION) }
            .forEach {
                val newValue = try {
                    strSubstitutor.replace(it.value)
                } catch (e: IllegalStateException) {
                    LOGGER.warn("while replacing variables: ", e)

                    it.value
                }

                properties.put(it.key, it.value)
            }
    }

    companion object {
        val RE_INTERPOLATION = Regex(""".*\$\{[\p{Alnum}.-_]+\}.*""")

        val logger: Logger = LoggerFactory.getLogger(QueryByParsing::class.java)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy