blob: e17336daee942b79c693bef4d5e77ba3e4dee276 [file] [log] [blame] [edit]
/*
* 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.
//
// Included builds for build logic are evaluated earlier then root settings leading to error that root settings object is not yet
// available. For such cases we fallback to included build settings object and later manual mapping for kotlinRootDir
val gradleInternal = (gradle as GradleInternal)
return when {
gradleInternal.isRootBuild() ||
setOf("gradle-settings-conventions", "gradle-build-conventions").contains(settings.rootProject.name) -> {
settings
}
else -> {
val gradleParent = gradle.parent ?: error("Could not get includedBuild parent build for ${settings.rootDir}!")
getRootSettings(gradleParent.settings, gradleParent)
}
}
}
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
"gradle-settings-conventions" -> rootSettings.rootDir.parentFile.parentFile
"gradle-build-conventions" -> rootSettings.rootDir.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)
}
}
private val rootGradleProperties = providers.of(PropertiesValueSource::class.java) {
parameters {
fileName.set("gradle.properties")
rootDir.set(kotlinRootDir)
}
}
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) }
.orElse(providers.gradleProperty(propertyName))
.orElse(rootGradleProperties.map { it.getProperty(propertyName) })
} else {
localProperties.map { it.getProperty(propertyName) }
.orElse(rootSettings.providers.gradleProperty(propertyName))
.orElse(rootGradleProperties.map { it.getProperty(propertyName) })
}
}
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): 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"))
}
}
}
fun Settings.applyBootstrapConfiguration(
bootstrapVersion: String,
bootstrapRepo: String,
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)
gradle.beforeProject {
bootstrapKotlinVersion = bootstrapVersion
bootstrapKotlinRepo = bootstrapRepo
repositories.addBootstrapRepo(bootstrapRepo, bootstrapVersion, additionalRepos)
logBootstrapApplied(logMessage)
}
}
val isLocalBootstrapEnabled: Provider<Boolean> = loadLocalOrGradleProperty(Config.LOCAL_BOOTSTRAP)
.mapToBoolean().orElse(false)
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)
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 = kotlinRootDir
val repoPath = if (localPath != null) {
rootDirectory.resolve(localPath).canonicalFile
} else {
rootDirectory.resolve("build").resolve("repo")
}
val bootstrapRepo = repoPath.toURI().toString()
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
"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_Artifacts"
val teamCityBuildNumber = teamCityBootstrapBuildNumber.orNull ?: bootstrapVersion
val bootstrapRepo = "$baseRepoUrl/guestAuth/app/rest/builds/buildType:(id:$teamCityProjectId),number:$teamCityBuildNumber,$query/artifacts/content/maven.zip!/"
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
"Using Kotlin TeamCity bootstrap version $bootstrapVersion from $bootstrapRepo"
)
}
customBootstrapVersion.orNull != null -> {
val bootstrapVersion = customBootstrapVersion.get()
val bootstrapRepo = customBootstrapRepo.get()
applyBootstrapConfiguration(
bootstrapVersion,
bootstrapRepo,
"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,
"Using Kotlin Space bootstrap version $bootstrapVersion from $bootstrapRepo"
)
}
}