Build: Improve intellij-sdk repo up-to-date check time & layout

Up-to-date check is very heavy for intellij repo due to artifact size.
If module directory in repo is written only by one task we can assume
that task if up-to-date if target directory exists.
This commit is contained in:
Vyacheslav Gerasimov
2019-03-05 00:56:59 +03:00
parent f890cab145
commit fc8be48fa8
13 changed files with 232 additions and 203 deletions
@@ -74,11 +74,12 @@ repositories {
val intellij by configurations.creating
val intellijUltimate by configurations.creating
val androidStudio by configurations.creating
val sources by configurations.creating
val `jps-standalone` by configurations.creating
val `jps-build-test` by configurations.creating
val `intellij-core` by configurations.creating
val `plugins-NodeJS` by configurations.creating
val jpsStandalone by configurations.creating
val jpsBuildTest by configurations.creating
val intellijCore by configurations.creating
val nodeJS by configurations.creating
/**
* Special repository for annotations.jar required for idea runtime only.
@@ -87,15 +88,14 @@ val `plugins-NodeJS` by configurations.creating
*/
val intellijRuntimeAnnotations = "intellij-runtime-annotations"
val customDepsRepoDir = File(rootProject.rootDir, "../dependencies/repo")
val customDepsRepoDir = rootProject.rootDir.parentFile.resolve("dependencies/repo")
val customDepsOrg: String by rootProject.extra
val customDepsRevision = intellijVersion
val customDepsRepoModulesDir = File(customDepsRepoDir, "$customDepsOrg/$customDepsRevision")
val repoDir = customDepsRepoModulesDir
val repoDir = File(customDepsRepoDir, customDepsOrg)
dependencies {
if (androidStudioRelease != null) {
intellij("google:android-studio-ide:$androidStudioBuild")
androidStudio("google:android-studio-ide:$androidStudioBuild")
} else {
if (installIntellijCommunity) {
intellij("com.jetbrains.intellij.idea:ideaIC:$intellijVersion")
@@ -110,67 +110,40 @@ dependencies {
}
sources("com.jetbrains.intellij.idea:ideaIC:$intellijVersion:sources@jar")
`jps-standalone`("com.jetbrains.intellij.idea:jps-standalone:$intellijVersion")
`jps-build-test`("com.jetbrains.intellij.idea:jps-build-test:$intellijVersion")
`intellij-core`("com.jetbrains.intellij.idea:intellij-core:$intellijVersion")
jpsStandalone("com.jetbrains.intellij.idea:jps-standalone:$intellijVersion")
jpsBuildTest("com.jetbrains.intellij.idea:jps-build-test:$intellijVersion")
intellijCore("com.jetbrains.intellij.idea:intellij-core:$intellijVersion")
if (intellijUltimateEnabled) {
`plugins-NodeJS`("com.jetbrains.plugins:NodeJS:${rootProject.extra["versions.idea.NodeJS"]}@zip")
nodeJS("com.jetbrains.plugins:NodeJS:${rootProject.extra["versions.idea.NodeJS"]}@zip")
}
}
fun Task.configureExtractFromConfigurationTask(sourceConfig: Configuration,
pathRemap: (String) -> String = { it },
extractor: (Configuration) -> Any) {
dependsOn(sourceConfig)
inputs.files(sourceConfig)
val targetDir = File(repoDir, sourceConfig.name)
outputs.dirs(targetDir)
doFirst {
project.copy {
from(extractor(sourceConfig))
into(targetDir)
eachFile {
path = pathRemap(path)
}
}
}
}
fun removePathPrefix(path: String): String {
if (androidStudioRelease == null) return path
val slashes = if (studioOs == "mac") 2 else 1
var result = path
repeat(slashes) {
result = result.substringAfter('/')
}
return result
}
val unzipIntellijSdk by tasks.creating {
configureExtractFromConfigurationTask(intellij, pathRemap = { removePathPrefix(it) }) {
zipTree(it.singleFile).matching {
exclude("**/plugins/Kotlin/**")
}
}
}
val unzipIntellijUltimateSdk by tasks.creating {
configureExtractFromConfigurationTask(intellijUltimate) {
zipTree(it.singleFile).matching {
exclude("plugins/Kotlin/**")
}
}
}
val unzipIntellijCore by tasks.creating { configureExtractFromConfigurationTask(`intellij-core`) { zipTree(it.singleFile) } }
val makeIntellijCore = buildIvyRepositoryTask(intellijCore, customDepsOrg, customDepsRepoDir)
val makeIntellijAnnotations by tasks.creating(Copy::class.java) {
dependsOn(unzipIntellijCore)
from(repoDir.resolve(`intellij-core`.name).resolve("annotations.jar"))
into(repoDir.resolve(intellijRuntimeAnnotations))
}
dependsOn(makeIntellijCore)
val unzipJpsStandalone by tasks.creating { configureExtractFromConfigurationTask(`jps-standalone`) { zipTree(it.singleFile) } }
from(repoDir.resolve("intellij-core/$intellijVersion/artifacts/annotations.jar"))
val targetDir = File(repoDir, "$intellijRuntimeAnnotations/$intellijVersion")
into(targetDir)
val ivyFile = File(targetDir, "$intellijRuntimeAnnotations.ivy.xml")
outputs.files(ivyFile)
doLast {
writeIvyXml(
customDepsOrg,
intellijRuntimeAnnotations,
intellijVersion,
intellijRuntimeAnnotations,
targetDir,
targetDir,
targetDir,
allowAnnotations = true
)
}
}
val mergeSources by tasks.creating(Jar::class.java) {
dependsOn(sources)
@@ -181,14 +154,130 @@ val mergeSources by tasks.creating(Jar::class.java) {
version = intellijVersion
}
val copyJpsBuildTest by tasks.creating { configureExtractFromConfigurationTask(`jps-build-test`) { it.singleFile } }
val sourcesFile = mergeSources.outputs.files.singleFile
val unzipNodeJSPlugin by tasks.creating { configureExtractFromConfigurationTask(`plugins-NodeJS`) { zipTree(it.singleFile) } }
val makeIde = if (androidStudioBuild != null) {
buildIvyRepositoryTask(
androidStudio,
customDepsOrg,
customDepsRepoDir,
if (studioOs == "mac")
::skipContentsDirectory
else
::skipToplevelDirectory
)
} else {
val task = if (installIntellijUltimate) {
buildIvyRepositoryTask(intellijUltimate, customDepsOrg, customDepsRepoDir, null, sourcesFile)
} else {
buildIvyRepositoryTask(intellij, customDepsOrg, customDepsRepoDir, null, sourcesFile)
}
task.configure {
dependsOn(mergeSources)
}
task
}
val build by tasks.creating {
dependsOn(
makeIntellijCore,
makeIde,
buildIvyRepositoryTask(jpsStandalone, customDepsOrg, customDepsRepoDir, null, sourcesFile),
buildIvyRepositoryTask(jpsBuildTest, customDepsOrg, customDepsRepoDir, null, sourcesFile),
makeIntellijAnnotations
)
if (installIntellijUltimate) {
dependsOn(
buildIvyRepositoryTask(nodeJS, customDepsOrg, customDepsRepoDir, ::skipToplevelDirectory, sourcesFile)
)
}
}
fun buildIvyRepositoryTask(
configuration: Configuration,
organization: String,
repoDirectory: File,
pathRemap: ((String) -> String)? = null,
sources: File? = null
) = tasks.register("buildIvyRepositoryFor${configuration.name.capitalize()}") {
fun ResolvedArtifact.moduleDirectory(): File =
File(repoDirectory, "$organization/${moduleVersion.id.name}/${moduleVersion.id.version}")
dependsOn(configuration)
inputs.files(configuration)
outputs.upToDateWhen {
configuration.resolvedConfiguration.resolvedArtifacts.single()
.let { it.moduleDirectory() }
.exists()
}
doFirst {
configuration.resolvedConfiguration.resolvedArtifacts.single().run {
val moduleDirectory = moduleDirectory()
val artifactsDirectory = File(moduleDirectory(), "artifacts")
logger.info("Unpacking ${file.name} into ${artifactsDirectory.absolutePath}")
copy {
from(zipTree(file).matching {
exclude("**/plugins/Kotlin/**")
})
into(artifactsDirectory)
if (pathRemap != null) {
eachFile {
path = pathRemap(path)
}
}
includeEmptyDirs = false
}
writeIvyXml(
organization,
moduleVersion.id.name,
moduleVersion.id.version,
moduleVersion.id.name,
File(artifactsDirectory, "lib"),
File(artifactsDirectory, "lib"),
File(moduleDirectory, "ivy"),
*listOfNotNull(sources).toTypedArray()
)
val pluginsDirectory = File(artifactsDirectory, "plugins")
if (pluginsDirectory.exists()) {
file(File(artifactsDirectory, "plugins"))
.listFiles { file: File -> file.isDirectory }
.forEach {
writeIvyXml(
organization,
it.name,
moduleVersion.id.version,
it.name,
File(it, "lib"),
File(it, "lib"),
File(moduleDirectory, "ivy"),
*listOfNotNull(sources).toTypedArray()
)
}
}
}
}
}
fun writeIvyXml(
organization: String,
moduleName: String,
version: String,
fileName: String,
baseDir: File,
artifactDir: File,
targetDir: File,
vararg sourcesJar: File,
allowAnnotations: Boolean = false
) {
@@ -198,116 +287,40 @@ fun writeIvyXml(
&& !jar.name.startsWith("kotlin-")
&& (allowAnnotations || jar.name != "annotations.jar") // see comments for [intellijAnnotations] above
with(IvyDescriptorFileGenerator(DefaultIvyPublicationIdentity(customDepsOrg, moduleName, intellijVersion))) {
with(IvyDescriptorFileGenerator(DefaultIvyPublicationIdentity(organization, moduleName, version))) {
addConfiguration(DefaultIvyConfiguration("default"))
addConfiguration(DefaultIvyConfiguration("sources"))
baseDir.listFiles()?.forEach { jarFile ->
artifactDir.listFiles()?.forEach { jarFile ->
if (shouldIncludeIntellijJar(jarFile)) {
val relativeName = jarFile.toRelativeString(baseDir).removeSuffix(".jar")
addArtifact(
FileBasedIvyArtifact(jarFile, DefaultIvyPublicationIdentity(customDepsOrg, jarFile.nameWithoutExtension, intellijVersion)).also {
FileBasedIvyArtifact(
jarFile,
DefaultIvyPublicationIdentity(organization, relativeName, version)
).also {
it.conf = "default"
}
)
}
}
sourcesJar.forEach {
val sourcesArtifactName = it.name.substringBeforeLast("-").substringBeforeLast("-")
addArtifact(
FileBasedIvyArtifact(it, DefaultIvyPublicationIdentity(customDepsOrg, sourcesArtifactName, intellijVersion)).also { artifact ->
FileBasedIvyArtifact(
it,
DefaultIvyPublicationIdentity(organization, sourcesArtifactName, version)
).also { artifact ->
artifact.conf = "sources"
artifact.classifier = "sources"
}
)
}
writeTo(File(customDepsRepoModulesDir, "$fileName.ivy.xml"))
writeTo(File(targetDir, "$fileName.ivy.xml"))
}
}
val prepareIvyXmls by tasks.creating {
dependsOn(unzipIntellijCore, makeIntellijAnnotations, unzipJpsStandalone, mergeSources, copyJpsBuildTest)
fun skipToplevelDirectory(path: String) = path.substringAfter('/')
val intellijSdkDir = File(repoDir, intellij.name)
val intellijUltimateSdkDir = File(repoDir, intellijUltimate.name)
if (installIntellijCommunity) {
dependsOn(unzipIntellijSdk)
inputs.dir(intellijSdkDir)
outputs.file(File(repoDir, "${intellij.name}.ivy.xml"))
}
if (installIntellijUltimate) {
dependsOn(unzipIntellijUltimateSdk)
inputs.dir(intellijUltimateSdkDir)
outputs.file(File(repoDir, "${intellijUltimate.name}.ivy.xml"))
}
val flatDeps = listOf(`intellij-core`, `jps-standalone`, `jps-build-test`)
flatDeps.forEach {
inputs.dir(File(repoDir, it.name))
outputs.file(File(repoDir, "${it.name}.ivy.xml"))
}
inputs.dir(File(repoDir, sources.name))
if (intellijUltimateEnabled) {
dependsOn(unzipNodeJSPlugin)
inputs.dir(File(repoDir, `plugins-NodeJS`.name))
outputs.file(File(repoDir, "${`plugins-NodeJS`.name}.ivy.xml"))
}
doFirst {
val sources = File(repoDir, sources.name).listFiles()
if (installIntellijCommunity) {
val libDir = File(intellijSdkDir, "lib")
writeIvyXml(
intellij.name,
intellij.name,
libDir,
*sources
)
File(intellijSdkDir, "plugins").listFiles { file: File -> file.isDirectory }.forEach {
writeIvyXml(it.name, "intellij.plugin.${it.name}", File(it, "lib"), *sources)
}
}
if (installIntellijUltimate) {
val libDir = File(intellijUltimateSdkDir, "lib")
writeIvyXml(
intellij.name, // important! the module name should be "intellij"
intellijUltimate.name,
libDir,
*sources
)
File(intellijUltimateSdkDir, "plugins").listFiles { it: File -> it.isDirectory }.forEach {
writeIvyXml(it.name, "intellijUltimate.plugin.${it.name}", File(it, "lib"), *sources)
}
}
flatDeps.forEach {
writeIvyXml(it.name, it.name, File(repoDir, it.name), *sources)
}
if (intellijUltimateEnabled) {
val nodeJsBaseDir = "${`plugins-NodeJS`.name}/NodeJS/lib"
writeIvyXml("NodeJS", `plugins-NodeJS`.name, File(repoDir, nodeJsBaseDir), *sources)
}
val intellijAnnotationsDir = File(repoDir, intellijRuntimeAnnotations)
writeIvyXml(
intellijRuntimeAnnotations, intellijRuntimeAnnotations,
intellijAnnotationsDir, *sources,
allowAnnotations = true
)
}
}
val build by tasks.creating {
dependsOn(prepareIvyXmls)
}
val clean by tasks.creating(Delete::class) {
delete(customDepsRepoModulesDir)
delete(buildDir)
}
fun skipContentsDirectory(path: String) = path.substringAfter("Contents/")