<commit_before>/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.build

import androidx.build.AndroidXComposePlugin.Companion.isMultiplatformEnabled
import com.android.build.gradle.LibraryPlugin
import groovy.util.Node
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.XmlProvider
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.component.SoftwareComponent
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPom
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.tasks.GenerateModuleMetadata
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.findByType
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import java.io.File

fun Project.configureMavenArtifactUpload(extension: AndroidXExtension) {
    apply(mapOf("plugin" to "maven-publish"))

    afterEvaluate {
        components.all { component ->
            configureComponent(extension, component)
        }
    }
}

private fun Project.configureComponent(
    extension: AndroidXExtension,
    component: SoftwareComponent
) {
    if (extension.publish.shouldPublish() && component.isAndroidOrJavaReleaseComponent()) {
        val androidxGroup = validateCoordinatesAndGetGroup(extension)
        group = androidxGroup.group
        configure<PublishingExtension> {
            repositories {
                it.maven { repo ->
                    repo.setUrl(getRepositoryDirectory())
                }
            }
            publications {
                if (appliesJavaGradlePluginPlugin()) {
                    // The 'java-gradle-plugin' will also add to the 'pluginMaven' publication
                    it.create<MavenPublication>("pluginMaven")
                    tasks.getByName("publishPluginMavenPublicationToMavenRepository").doFirst {
                        removePreviouslyUploadedArchives(androidxGroup.group)
                    }
                } else {
                    it.create<MavenPublication>("maven") {
                        from(component)
                    }
                    tasks.getByName("publishMavenPublicationToMavenRepository").doFirst {
                        removePreviouslyUploadedArchives(androidxGroup.group)
                    }
                }
            }
            publications.withType(MavenPublication::class.java).all {
                it.pom { pom ->
                    addInformativeMetadata(extension, pom)
                    tweakDependenciesMetadata(androidxGroup, pom)
                }
            }
        }

        // Register it as part of release so that we create a Zip file for it
        Release.register(this, extension)

        // Workaround for https://github.com/gradle/gradle/issues/11717
        project.tasks.withType(GenerateModuleMetadata::class.java).configureEach { task ->
            task.doLast {
                val metadata = task.outputFile.asFile.get()
                var text = metadata.readText()
                metadata.writeText(
                    text.replace(
                        "\"buildId\": .*".toRegex(),
                        "\"buildId:\": \"${getBuildId()}\""
                    )
                )
            }
        }

        if (isMultiplatformEnabled()) {
            configureMultiplatformPublication()
        }
    }
}

private fun Project.configureMultiplatformPublication() {
    val multiplatformExtension = extensions.findByType<KotlinMultiplatformExtension>() ?: return

    // publishMavenPublicationToMavenRepository will produce conflicting artifacts with the same
    // name as the artifacts producing by publishKotlinMultiplatformPublicationToMavenRepository
    project.tasks.findByName("publishMavenPublicationToMavenRepository")?.enabled = false

    multiplatformExtension.targets.all { target ->
        if (target is KotlinAndroidTarget) {
            target.publishAllLibraryVariants()
        }
    }
}

private fun SoftwareComponent.isAndroidOrJavaReleaseComponent() =
    name == "release" || name == "java"

private fun Project.validateCoordinatesAndGetGroup(extension: AndroidXExtension): LibraryGroup {
    val mavenGroup = extension.mavenGroup
        ?: throw Exception("You must specify mavenGroup for $name project")
    val strippedGroupId = mavenGroup.group.substringAfterLast(".")
    if (mavenGroup.group.startsWith("androidx") && !name.startsWith(strippedGroupId)) {
        throw Exception("Your artifactId must start with '$strippedGroupId'. (currently is $name)")
    }
    return mavenGroup
}

/**
 * Delete any existing archives, so that developers don't get
 * confused/surprised by the presence of old versions.
 * Additionally, deleting old versions makes it more convenient to iterate
 * over all existing archives without visiting archives having old versions too
 */
private fun Project.removePreviouslyUploadedArchives(group: String) {
    val projectArchiveDir = File(
        getRepositoryDirectory(),
        "${group.replace('.', '/')}/${project.name}"
    )
    projectArchiveDir.deleteRecursively()
}

private fun Project.addInformativeMetadata(extension: AndroidXExtension, pom: MavenPom) {
    pom.name.set(extension.name)
    pom.description.set(provider { extension.description })
    pom.url.set(
        provider {
            fun defaultUrl() = "https://developer.android.com/jetpack/androidx/releases/" +
                extension.mavenGroup!!.group.removePrefix("androidx.")
                    .replace(".", "-") +
                "#" + extension.project.version()
            getAlternativeProjectUrl() ?: defaultUrl()
        }
    )
    pom.inceptionYear.set(provider { extension.inceptionYear })
    pom.licenses { licenses ->
        licenses.license { license ->
            license.name.set("The Apache Software License, Version 2.0")
            license.url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
            license.distribution.set("repo")
        }<commit_msg>Calculate projectArchiveDir before task execution.<commit_after>/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.build

import androidx.build.AndroidXComposePlugin.Companion.isMultiplatformEnabled
import com.android.build.gradle.LibraryPlugin
import groovy.util.Node
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.XmlProvider
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.component.SoftwareComponent
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPom
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.tasks.GenerateModuleMetadata
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.create
import org.gradle.kotlin.dsl.findByType
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
import java.io.File

fun Project.configureMavenArtifactUpload(extension: AndroidXExtension) {
    apply(mapOf("plugin" to "maven-publish"))

    afterEvaluate {
        components.all { component ->
            configureComponent(extension, component)
        }
    }
}

private fun Project.configureComponent(
    extension: AndroidXExtension,
    component: SoftwareComponent
) {
    if (extension.publish.shouldPublish() && component.isAndroidOrJavaReleaseComponent()) {
        val androidxGroup = validateCoordinatesAndGetGroup(extension)
        val projectArchiveDir = File(
            getRepositoryDirectory(),
            "${androidxGroup.group.replace('.', '/')}/$name"
        )
        group = androidxGroup.group
        configure<PublishingExtension> {
            repositories {
                it.maven { repo ->
                    repo.setUrl(getRepositoryDirectory())
                }
            }
            publications {
                if (appliesJavaGradlePluginPlugin()) {
                    // The 'java-gradle-plugin' will also add to the 'pluginMaven' publication
                    it.create<MavenPublication>("pluginMaven")
                    tasks.getByName("publishPluginMavenPublicationToMavenRepository").doFirst {
                        removePreviouslyUploadedArchives(projectArchiveDir)
                    }
                } else {
                    it.create<MavenPublication>("maven") {
                        from(component)
                    }
                    tasks.getByName("publishMavenPublicationToMavenRepository").doFirst {
                        removePreviouslyUploadedArchives(projectArchiveDir)
                    }
                }
            }
            publications.withType(MavenPublication::class.java).all {
                it.pom { pom ->
                    addInformativeMetadata(extension, pom)
                    tweakDependenciesMetadata(androidxGroup, pom)
                }
            }
        }

        // Register it as part of release so that we create a Zip file for it
        Release.register(this, extension)

        // Workaround for https://github.com/gradle/gradle/issues/11717
        project.tasks.withType(GenerateModuleMetadata::class.java).configureEach { task ->
            task.doLast {
                val metadata = task.outputFile.asFile.get()
                var text = metadata.readText()
                metadata.writeText(
                    text.replace(
                        "\"buildId\": .*".toRegex(),
                        "\"buildId:\": \"${getBuildId()}\""
                    )
                )
            }
        }

        if (isMultiplatformEnabled()) {
            configureMultiplatformPublication()
        }
    }
}

private fun Project.configureMultiplatformPublication() {
    val multiplatformExtension = extensions.findByType<KotlinMultiplatformExtension>() ?: return

    // publishMavenPublicationToMavenRepository will produce conflicting artifacts with the same
    // name as the artifacts producing by publishKotlinMultiplatformPublicationToMavenRepository
    project.tasks.findByName("publishMavenPublicationToMavenRepository")?.enabled = false

    multiplatformExtension.targets.all { target ->
        if (target is KotlinAndroidTarget) {
            target.publishAllLibraryVariants()
        }
    }
}

private fun SoftwareComponent.isAndroidOrJavaReleaseComponent() =
    name == "release" || name == "java"

private fun Project.validateCoordinatesAndGetGroup(extension: AndroidXExtension): LibraryGroup {
    val mavenGroup = extension.mavenGroup
        ?: throw Exception("You must specify mavenGroup for $name project")
    val strippedGroupId = mavenGroup.group.substringAfterLast(".")
    if (mavenGroup.group.startsWith("androidx") && !name.startsWith(strippedGroupId)) {
        throw Exception("Your artifactId must start with '$strippedGroupId'. (currently is $name)")
    }
    return mavenGroup
}

/**
 * Delete any existing archives, so that developers don't get
 * confused/surprised by the presence of old versions.
 * Additionally, deleting old versions makes it more convenient to iterate
 * over all existing archives without visiting archives having old versions too
 */
private fun removePreviouslyUploadedArchives(projectArchiveDir: File) {
    projectArchiveDir.deleteRecursively()
}

private fun Project.addInformativeMetadata(extension: AndroidXExtension, pom: MavenPom) {
    pom.name.set(extension.name)
    pom.description.set(provider { extension.description })
    pom.url.set(
        provider {
            fun defaultUrl() = "https://developer.android.com/jetpack/androidx/releases/" +
                extension.mavenGroup!!.group.removePrefix("androidx.")
                    .replace(".", "-") +
                "#" + extension.project.version()
            getAlternativeProjectUrl() ?: defaultUrl()
        }
    )
    pom.inceptionYear.set(provider { extension.inceptionYear })
    pom.licenses { licenses ->
        licenses.license { license ->
            license.name.set("The Apache Software License, Version 2.0")
            license.url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
            license.distribution.set("repo")
        }
{'fraction_non_alphanumeric': 0.0917742530431575, 'fraction_numerical': 0.0025082995204721505, 'mean_word_length': 2.6178275954096613, 'pattern_counts': {'":': 4, '<': 11, '<?xml version=': 0, '>': 25, 'https://': 4, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6648080', 'n_tokens_mistral': 3554, 'n_tokens_neox': 3370, 'n_words': 754}