Files
kotlin-fork/repo/scripts/kotlin-bootstrap.settings.gradle.kts
T
Yahor Berdnikau a14d0d148b Simplify Kotlin bootstrap application in the project
Move all the code to apply Kotlin bootstrap into settings script plugin
which does following:
- configures based either on the repo root 'local.properties' or on the
root project gradle properties or on the repo root 'gradle.properties'
current type of bootstrap
- automatically adds Kotlin bootstrap repository with
exclusive content, so bootstrap dependencies will not be by mistake
downloaded from other repository
- automatically forces all Kotlin plugins applied in the build to use
bootstrap version

This script should be applied only in project settings.gradle and then
it does all the configuration by itself.
2022-11-29 14:31:48 +00:00

303 lines
12 KiB
Kotlin

/*
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
// Apply this settings script in the project settings.gradle following way:
// pluginManagement {
// apply from: 'kotlin-bootstrap.settings.gradle.kts'
// }
import java.util.Properties
import org.gradle.api.internal.GradleInternal
object Config {
const val LOCAL_BOOTSTRAP = "bootstrap.local"
const val LOCAL_BOOTSTRAP_VERSION = "bootstrap.local.version"
const val LOCAL_BOOTSTRAP_PATH = "bootstrap.local.path"
const val TEAMCITY_BOOTSTRAP_VERSION = "bootstrap.teamcity.kotlin.version"
const val TEAMCITY_BOOTSTRAP_BUILD_NUMBER = "bootstrap.teamcity.build.number"
const val TEAMCITY_BOOTSTRAP_PROJECT = "bootstrap.teamcity.project"
const val TEAMCITY_BOOTSTRAP_URL = "bootstrap.teamcity.url"
const val CUSTOM_BOOTSTRAP_VERSION = "bootstrap.kotlin.version"
const val CUSTOM_BOOTSTRAP_REPO = "bootstrap.kotlin.repo"
const val DEFAULT_SNAPSHOT_VERSION = "defaultSnapshotVersion"
const val DEFAULT_BOOTSTRAP_VERSION = "bootstrap.kotlin.default.version"
const val PROJECT_KOTLIN_VERSION = "bootstrapKotlinVersion"
const val PROJECT_KOTLIN_REPO = "bootstrapKotlinRepo"
const val IS_JPS_BUILD_ENABLED = "jpsBuild"
}
abstract class PropertiesValueSource : ValueSource<Properties, PropertiesValueSource.Parameters> {
interface Parameters : ValueSourceParameters {
val fileName: Property<String>
val rootDir: Property<File>
}
override fun obtain(): Properties? {
val localPropertiesFile = parameters.rootDir.get().resolve(parameters.fileName.get())
return if (localPropertiesFile.exists()) {
localPropertiesFile.bufferedReader().use {
Properties().apply { load(it) }
}
} else {
null
}
}
}
fun getRootSettings(
settings: Settings,
gradle: Gradle
): Settings {
// Gradle interface neither exposes flag if it is a root of composite-build hierarchy
// nor gives access to Settings object. Fortunately it is availaibe inside GradleInternal internal api
// used by build scan plugin.
val gradleInternal = (gradle as GradleInternal)
return if (gradleInternal.isRootBuild()) {
settings
} else {
val gradleParent = gradle.parent ?: error("Could not get includedBuild parent build for ${settings.rootDir}!")
getRootSettings(gradle.parent!!.settings, gradle.parent!!)
}
}
val rootSettings = getRootSettings(settings, settings.gradle)
// Workaround for the case when included build could be run directly via --project-dir option.
// In this case `rootSettings.rootDir` will point to --project-dir location rather then Kotlin repo real root.
// So in such case script falls back to manual mapping
val kotlinRootDir: File = when (rootSettings.rootProject.name) {
"buildSrc" -> {
val parentDir = rootSettings.rootDir.parentFile
when (parentDir.name) {
"benchmarksAnalyzer", "performance-server" -> parentDir.parentFile.parentFile.parentFile
"performance" -> parentDir.parentFile.parentFile
"ui" -> parentDir.parentFile.parentFile.parentFile.parentFile
else -> parentDir
}
}
"benchmarksAnalyzer", "performance-server" -> rootSettings.rootDir.parentFile.parentFile.parentFile
"performance" -> rootSettings.rootDir.parentFile.parentFile
"ui" -> rootSettings.rootDir.parentFile.parentFile.parentFile.parentFile
else -> rootSettings.rootDir
}
private val localProperties = providers.of(PropertiesValueSource::class.java) {
parameters {
fileName.set("local.properties")
rootDir.set(kotlinRootDir)
}
}.forUseAtConfigurationTime()
private val rootGradleProperties = providers.of(PropertiesValueSource::class.java) {
parameters {
fileName.set("gradle.properties")
rootDir.set(kotlinRootDir)
}
}.forUseAtConfigurationTime()
fun loadLocalOrGradleProperty(
propertyName: String
): Provider<String> {
// Workaround for https://github.com/gradle/gradle/issues/19114
// as in the includedBuild GradleProperties are empty on configuration cache reuse
return if ((gradle as GradleInternal).isRootBuild()) {
localProperties.map { it.getProperty(propertyName) }.forUseAtConfigurationTime()
.orElse(providers.gradleProperty(propertyName).forUseAtConfigurationTime())
.orElse(rootGradleProperties.map { it.getProperty(propertyName) }.forUseAtConfigurationTime())
} else {
localProperties.map { it.getProperty(propertyName) }.forUseAtConfigurationTime()
.orElse(rootSettings.providers.gradleProperty(propertyName).forUseAtConfigurationTime())
.orElse(rootGradleProperties.map { it.getProperty(propertyName) }.forUseAtConfigurationTime())
}
}
fun Project.logBootstrapApplied(message: String) {
if (this == rootProject) logger.lifecycle(message) else logger.info(message)
}
fun String?.propValueToBoolean(default: Boolean = false): Boolean {
return when {
this == null -> default
isEmpty() -> true // has property without value means 'true'
else -> trim().toBoolean()
}
}
fun Provider<String>.mapToBoolean(): Provider<Boolean> = map { it?.propValueToBoolean() }
fun RepositoryHandler.addBootstrapRepo(
bootstrapRepo: String,
bootstrapVersion: String,
additionalBootstrapRepos: List<String> = emptyList()
) {
exclusiveContent {
forRepositories(
*(listOf(bootstrapRepo) + additionalBootstrapRepos)
.map {
maven { url = uri(it) }
}
.toTypedArray()
)
filter {
// kotlin-build-gradle-plugin and non bootstrap-versions
// should be excluded from strict content filtering
includeVersionByRegex(
"org\\.jetbrains\\.kotlin",
"^(?!kotlin-build-gradle-plugin).*$",
bootstrapVersion.toRegex().pattern
)
// Kotlin Gradle plugins that have slightly separate maven coordinates
includeVersionByRegex(
"org\\.jetbrains\\.kotlin\\..*$",
"org\\.jetbrains\\.kotlin\\..*\\.gradle\\.plugin$",
bootstrapVersion.toRegex().pattern
)
}
}
}
@OptIn(kotlin.ExperimentalStdlibApi::class)
fun getAdditionalBootstrapRepos(
bootstrapRepo: String,
bootstrapKotlinVersion: String,
isJpsBuildEnabled: Boolean
): List<String> {
return buildList {
if (bootstrapRepo.startsWith("https://buildserver.labs.intellij.net")
|| bootstrapRepo.startsWith("https://teamcity.jetbrains.com")) {
add(bootstrapRepo.replace("artifacts/content/maven", "artifacts/content/internal/repo"))
}
if (isJpsBuildEnabled) {
add(
"https://teamcity.jetbrains.com/guestAuth/app/rest/builds/buildType:(id:Kotlin_KotlinPublic_Aggregate)," +
"number:$bootstrapKotlinVersion,branch:default:any/artifacts/content/internal/repo/"
)
}
}
}
fun Settings.applyBootstrapConfiguration(
bootstrapVersion: String,
bootstrapRepo: String,
isJpsBuildEnabled: Boolean,
logMessage: String
) {
settings.pluginManagement.repositories.addBootstrapRepo(bootstrapRepo, bootstrapVersion)
settings.pluginManagement.resolutionStrategy.eachPlugin {
if (requested.id.id.startsWith("org.jetbrains.kotlin.")) {
useVersion(bootstrapVersion)
}
}
val additionalRepos = getAdditionalBootstrapRepos(bootstrapRepo, bootstrapVersion, isJpsBuildEnabled)
gradle.beforeProject {
bootstrapKotlinVersion = bootstrapVersion
bootstrapKotlinRepo = bootstrapRepo
repositories.addBootstrapRepo(bootstrapRepo, bootstrapVersion, additionalRepos)
logBootstrapApplied(logMessage)
}
}
val isLocalBootstrapEnabled: Provider<Boolean> = loadLocalOrGradleProperty(Config.LOCAL_BOOTSTRAP)
.mapToBoolean().orElse(false).forUseAtConfigurationTime()
val localBootstrapVersion: Provider<String> = loadLocalOrGradleProperty(Config.LOCAL_BOOTSTRAP_VERSION)
.orElse(loadLocalOrGradleProperty(Config.DEFAULT_SNAPSHOT_VERSION))
val localBootstrapPath: Provider<String> = loadLocalOrGradleProperty(Config.LOCAL_BOOTSTRAP_PATH)
val teamCityBootstrapVersion = loadLocalOrGradleProperty(Config.TEAMCITY_BOOTSTRAP_VERSION)
val teamCityBootstrapBuildNumber = loadLocalOrGradleProperty(Config.TEAMCITY_BOOTSTRAP_BUILD_NUMBER)
val teamCityBootstrapProject = loadLocalOrGradleProperty(Config.TEAMCITY_BOOTSTRAP_PROJECT)
val teamCityBootstrapUrl = loadLocalOrGradleProperty(Config.TEAMCITY_BOOTSTRAP_URL)
val customBootstrapVersion = loadLocalOrGradleProperty(Config.CUSTOM_BOOTSTRAP_VERSION)
val customBootstrapRepo = loadLocalOrGradleProperty(Config.CUSTOM_BOOTSTRAP_REPO)
val defaultBootstrapVersion = loadLocalOrGradleProperty(Config.DEFAULT_BOOTSTRAP_VERSION)
val isJpsBuildEnabled = loadLocalOrGradleProperty(Config.IS_JPS_BUILD_ENABLED)
.mapToBoolean().orElse(false).forUseAtConfigurationTime()
var Project.bootstrapKotlinVersion: String
get() = property(Config.PROJECT_KOTLIN_VERSION) as String
set(value) {
extensions.extraProperties.set(Config.PROJECT_KOTLIN_VERSION, value)
}
var Project.bootstrapKotlinRepo: String?
get() = property(Config.PROJECT_KOTLIN_REPO) as String?
set(value) {
extensions.extraProperties.set(Config.PROJECT_KOTLIN_REPO, value)
}
// Get bootstrap kotlin version and repository url
// and set it using pluginManagement and dependencyManangement
when {
isLocalBootstrapEnabled.get() -> {
val bootstrapVersion = localBootstrapVersion.get()
val localPath = localBootstrapPath.orNull
val rootDirectory = rootSettings.rootDir
val repoPath = if (localPath != null) {
rootDirectory.resolve(localPath).canonicalFile
} else {
rootDirectory.resolve("build").resolve("repo")
}
val bootstrapRepo = repoPath.toURI().toString()
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
isJpsBuildEnabled.get(),
"Using Kotlin local bootstrap version $bootstrapVersion from $bootstrapRepo"
)
}
teamCityBootstrapVersion.orNull != null -> {
val bootstrapVersion = teamCityBootstrapVersion.get()
val query = "branch:default:any"
val baseRepoUrl = teamCityBootstrapUrl.orNull ?: "https://buildserver.labs.intellij.net"
val teamCityProjectId = teamCityBootstrapProject.orNull ?: "Kotlin_KotlinDev_Compiler"
val teamCityBuildNumber = teamCityBootstrapBuildNumber.orNull ?: bootstrapVersion
val bootstrapRepo = "$baseRepoUrl/guestAuth/app/rest/builds/buildType:(id:$teamCityProjectId),number:$teamCityBuildNumber,$query/artifacts/content/maven/"
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
isJpsBuildEnabled.get(),
"Using Kotlin TeamCity bootstrap version $bootstrapVersion from $bootstrapRepo"
)
}
customBootstrapVersion.orNull != null -> {
val bootstrapVersion = customBootstrapVersion.get()
val bootstrapRepo = customBootstrapRepo.get()
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
isJpsBuildEnabled.get(),
"Using Kotlin custom bootstrap version $bootstrapVersion from $bootstrapRepo"
)
}
else -> {
val bootstrapVersion = defaultBootstrapVersion.get()
val bootstrapRepo = "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap"
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
isJpsBuildEnabled.get(),
"Using Kotlin Space bootstrap version $bootstrapVersion from $bootstrapRepo"
)
}
}