Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,11 @@
package com.itsaky.androidide.gradle

import com.itsaky.androidide.buildinfo.BuildInfo
import com.itsaky.androidide.tooling.api.LogSenderConfig._PROPERTY_IS_TEST_ENV
import com.itsaky.androidide.tooling.api.LogSenderConfig._PROPERTY_MAVEN_LOCAL_REPOSITORY
import org.adfa.constants.ANDROIDIDE_HOME
import org.adfa.constants.MAVEN_LOCAL_REPOSITORY
import org.gradle.StartParameter
import org.gradle.api.Plugin
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.initialization.Settings
import org.gradle.api.invocation.Gradle
import org.gradle.api.logging.Logging
import java.io.File
import java.io.FileNotFoundException
import java.net.URI

const val MAX_LOGFILE_COUNT = 2

Expand All @@ -41,187 +32,71 @@ const val MAX_LOGFILE_COUNT = 2
* @author Akash Yadav
*/
class AndroidIDEInitScriptPlugin : Plugin<Gradle> {

companion object {

private val logger = Logging.getLogger(AndroidIDEInitScriptPlugin::class.java)
}

/**
* Keywords: [gradle, agp, androidGradlePlugin, classpath, build ]
* It seeme like this method adds custom android-gradle-plugin to the classpath.
* Without explicitly adding it to any gradle files.
* This script is a prat of androidIde. So even if child process fails to build,
* it only means that androidIDE toolchain was not satisfied.
* So far I can't find
* @see VERSION_NAME_DOWNLOAD
* gradle .jar and it seems to be required.
* This script has no direct usage by AS search, but is invoked from string and in gradle tasks.
*/
override fun apply(target: Gradle) {
removeDaemonLogs(target)

target.settingsEvaluated { settings ->
settings.addDependencyRepositories()
}

target.rootProject { rootProject ->
rootProject.buildscript.apply {
dependencies.apply {
add("classpath", rootProject.files("$ANDROIDIDE_HOME/plugin/cogo-plugin.jar"))
}
}
}

target.projectsLoaded { gradle ->
gradle.rootProject.subprojects { sub ->
if (!sub.buildFile.exists()) {
// For subproject ':nested:module',
// ':nested' represented as a 'Project', but it may or may not have a buildscript file
// if the project doesn't have a buildscript, then the plugins should not be applied
return@subprojects
}

sub.afterEvaluate {
logger.info("Trying to apply plugin '${BuildInfo.PACKAGE_NAME}' to project '${sub.path}'")
sub.pluginManager.apply(BuildInfo.PACKAGE_NAME)
}
}
}
}

private fun removeDaemonLogs(gradle: Gradle) {
// logger.lifecycle("#@^*( Applyingg Clean Plugin")
// Get the Gradle user home directory
val gradleUserHomeDir = gradle.gradleUserHomeDir

// Get the current Gradle version
val currentGradleVersion = gradle.gradleVersion
val logsDir = File(gradleUserHomeDir, "daemon/$currentGradleVersion")

if (logsDir.exists() && logsDir.isDirectory) {
logger.lifecycle("Code On the Go clean logs of gradle ($currentGradleVersion) task running....")

// Filter and iterate over log files, sorted by last modified date
logsDir.listFiles()?.filter { it.isFile && it.name.endsWith(".log") }
?.sortedByDescending { it.lastModified() }
?.drop(MAX_LOGFILE_COUNT)
?.forEach { logFile ->
logger.lifecycle("deleting log: ${logFile.name}")
logFile.delete()
}
}
else {
logger.lifecycle("No deletions made, number of log files does not exceed ($MAX_LOGFILE_COUNT) for gradle ($currentGradleVersion). ")
}
}

private fun Settings.addDependencyRepositories() {
val (isTestEnv, mavenLocalRepos) = getTestEnvProps(startParameter)
if (isTestEnv) {
addDependencyRepositories(isTestEnv, mavenLocalRepos)
} else {
addDependencyRepositories(MAVEN_LOCAL_REPOSITORY)
}
}

@Suppress("UnstableApiUsage")
private fun Settings.addDependencyRepositories(
mavenLocalRepo: String
) {
dependencyResolutionManagement.run {
repositories.configureRepositories(mavenLocalRepo)
}

pluginManagement.apply {
repositories.configureRepositories(mavenLocalRepo)
}
}

private fun RepositoryHandler.configureRepositories(
mavenLocalRepo: String
) {

val repo = File(mavenLocalRepo)
if (!repo.exists() || !repo.isDirectory) {
throw FileNotFoundException("Maven local repository '$mavenLocalRepo' not found")
}

maven { repository ->
repository.url = repo.toURI()
}

}

@Suppress("UnstableApiUsage")
private fun Settings.addDependencyRepositories(
isMavenLocalEnabled: Boolean,
mavenLocalRepo: String
) {
dependencyResolutionManagement.run {
repositories.configureRepositories(isMavenLocalEnabled, mavenLocalRepo)
}

pluginManagement.apply {
repositories.configureRepositories(isMavenLocalEnabled, mavenLocalRepo)
}
}

private fun RepositoryHandler.addDependencyRepositories(startParams: StartParameter) {
val (isTestEnv, mavenLocalRepos) = getTestEnvProps(startParams)
configureRepositories(isTestEnv, mavenLocalRepos)
}

private fun getTestEnvProps(startParameter: StartParameter): Pair<Boolean, String> {
return startParameter.run {
val isTestEnv = projectProperties.containsKey(_PROPERTY_IS_TEST_ENV)
&& projectProperties[_PROPERTY_IS_TEST_ENV].toString().toBoolean()
val mavenLocalRepos = projectProperties.getOrDefault(_PROPERTY_MAVEN_LOCAL_REPOSITORY, "")

isTestEnv to mavenLocalRepos
}
}

private fun RepositoryHandler.configureRepositories(
isMavenLocalEnabled: Boolean,
mavenLocalRepos: String
) {

if (!isMavenLocalEnabled) {

// For AndroidIDE CI builds
maven { repository ->
repository.url = URI.create(BuildInfo.SNAPSHOTS_REPOSITORY)
}
} else {
logger.info("Using local maven repository for classpath resolution...")

for (mavenLocalRepo in mavenLocalRepos.split(':')) {
if (mavenLocalRepo.isBlank()) {
mavenLocal()
} else {
logger.info("Local repository path: $mavenLocalRepo")

val repo = File(mavenLocalRepo)
if (!repo.exists() || !repo.isDirectory) {
throw FileNotFoundException("Maven local repository '$mavenLocalRepo' not found")
}

maven { repository ->
repository.url = repo.toURI()
}
}
}
}

// for AGP API dependency
google()

maven { repository ->
repository.setUrl(BuildInfo.PUBLIC_REPOSITORY)
}

mavenCentral()
gradlePluginPortal()
}
companion object {
private val logger = Logging.getLogger(AndroidIDEInitScriptPlugin::class.java)
}

override fun apply(target: Gradle) {
removeDaemonLogs(target)

target.settingsEvaluated { settings ->
settings.pluginManager.apply(COTGSettingsPlugin::class.java)
}

target.rootProject { rootProject ->
rootProject.buildscript.apply {
dependencies.apply {
add(
"classpath",
rootProject.files("$ANDROIDIDE_HOME/plugin/cogo-plugin.jar"),
)
}
}
}

target.projectsLoaded { gradle ->
gradle.rootProject.subprojects { sub ->
if (!sub.buildFile.exists()) {
// For subproject ':nested:module',
// ':nested' represented as a 'Project', but it may or may not have a buildscript file
// if the project doesn't have a buildscript, then the plugins should not be applied
return@subprojects
}

sub.afterEvaluate {
logger.info("Trying to apply plugin '${BuildInfo.PACKAGE_NAME}' to project '${sub.path}'")
sub.pluginManager.apply(BuildInfo.PACKAGE_NAME)
}
}
}
}

private fun removeDaemonLogs(gradle: Gradle) {
// Get the Gradle user home directory
val gradleUserHomeDir = gradle.gradleUserHomeDir

// Get the current Gradle version
val currentGradleVersion = gradle.gradleVersion
val logsDir = File(gradleUserHomeDir, "daemon/$currentGradleVersion")

if (logsDir.exists() && logsDir.isDirectory) {
logger.lifecycle("Code On the Go clean logs of gradle ($currentGradleVersion) task running....")

// Filter and iterate over log files, sorted by last modified date
logsDir
.listFiles()
?.filter { it.isFile && it.name.endsWith(".log") }
?.sortedByDescending { it.lastModified() }
?.drop(MAX_LOGFILE_COUNT)
?.forEach { logFile ->
logger.lifecycle("deleting log: ${logFile.name}")
logFile.delete()
}
} else {
logger.lifecycle(
"No deletions made, number of log files does not" +
" exceed ($MAX_LOGFILE_COUNT) for gradle ($currentGradleVersion).",
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.itsaky.androidide.gradle

import com.itsaky.androidide.tooling.api.LogSenderConfig._PROPERTY_IS_TEST_ENV
import com.itsaky.androidide.tooling.api.LogSenderConfig._PROPERTY_MAVEN_LOCAL_REPOSITORY
import org.adfa.constants.MAVEN_LOCAL_REPOSITORY
import org.gradle.StartParameter
import org.gradle.api.Plugin
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.artifacts.repositories.MavenArtifactRepository
import org.gradle.api.initialization.Settings
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import java.io.File
import java.net.URI

class COTGSettingsPlugin : Plugin<Settings> {
private val logger = Logging.getLogger(COTGSettingsPlugin::class.java)

override fun apply(target: Settings) {
if (target.gradle.parent != null) {
// only apply the settings plugin to the root Gradle build
return
}

logger.info("Plugin instance: ${System.identityHashCode(this)}")
// Add our local maven repo, always.
val allLocalRepos = mutableListOf(MAVEN_LOCAL_REPOSITORY)

// Then check if we need to add additional repos, based on whether
// we're in a test environment
val (isTestEnv, mavenLocalRepos) = getTestEnvProps(target.startParameter)
if (isTestEnv) {
allLocalRepos += mavenLocalRepos
}

target.addLocalRepos(allLocalRepos)
}

private fun RepositoryHandler.addLocalRepos(repos: List<String>) {
repos.forEach { repo ->
addLocalMavenRepoIfMissing(logger, repo)
}
}

@Suppress("UnstableApiUsage")
private fun Settings.addLocalRepos(mavenLocalRepos: List<String>) {
dependencyResolutionManagement.repositories.addLocalRepos(mavenLocalRepos)
pluginManagement.repositories.addLocalRepos(mavenLocalRepos)
}

private fun getTestEnvProps(startParameter: StartParameter): Pair<Boolean, List<String>> =
startParameter.run {
val isTestEnv =
projectProperties.containsKey(_PROPERTY_IS_TEST_ENV) &&
projectProperties[_PROPERTY_IS_TEST_ENV].toString().toBoolean()
val mavenLocalRepos =
projectProperties.getOrDefault(_PROPERTY_MAVEN_LOCAL_REPOSITORY, "")

isTestEnv to mavenLocalRepos.split(File.pathSeparatorChar).toList().filter { it.isNotBlank() }
}
}

private fun RepositoryHandler.addLocalMavenRepoIfMissing(
logger: Logger,
path: String,
) {
val dir = File(path)
require(dir.isDirectory) { "Repo not found: $path" }

val uri = dir.toURI()

addMavenRepoIfMissing(logger, uri)
}

private fun RepositoryHandler.addMavenRepoIfMissing(
logger: Logger,
uri: URI,
) {
if (none { it is MavenArtifactRepository && it.url == uri }) {
logger.info("Adding maven repository: $uri")
maven { it.url = uri }
}
}