From 578f7317fa4e5d0d14034ae6924111a6f1796197 Mon Sep 17 00:00:00 2001 From: Daniel Alome Date: Mon, 10 Aug 2026 14:47:32 +0100 Subject: [PATCH] ADFA-2602: Resolve buildscript classpaths from the on-device Maven repo COTGSettingsPlugin injects the bundled repo into pluginManagement and dependencyResolutionManagement only. A `buildscript { }` block resolves against its own repositories, which nothing reached, so any project declaring its build classpath that way could only be built online. That is why plugin-template builds required network. Inject the repo for both scopes, each before the script that consumes it is evaluated: - beforeSettings, for a buildscript block in settings.gradle.kts (the plugin template declares AGP and Kotlin there) - beforeProject, for a buildscript block in build.gradle.kts settingsEvaluated is too late: by then the settings buildscript classpath has already resolved. A missing repo is not fatal. The directory does not exist until onboarding has installed the assets, and failing there would break every build before that point. --- .../gradle/AndroidIDEInitScriptPlugin.kt | 8 +++++ .../androidide/gradle/COTGSettingsPlugin.kt | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/AndroidIDEInitScriptPlugin.kt b/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/AndroidIDEInitScriptPlugin.kt index 29ee857794..0b5785caa5 100644 --- a/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/AndroidIDEInitScriptPlugin.kt +++ b/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/AndroidIDEInitScriptPlugin.kt @@ -39,6 +39,14 @@ class AndroidIDEInitScriptPlugin : Plugin { override fun apply(target: Gradle) { removeDaemonLogs(target) + target.beforeSettings { settings -> + settings.addLocalMavenRepoToBuildscript(logger) + } + + target.beforeProject { project -> + project.addLocalMavenRepoToBuildscript(logger) + } + target.settingsEvaluated { settings -> settings.pluginManager.apply(COTGSettingsPlugin::class.java) } diff --git a/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt b/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt index 165413b9df..554592b627 100644 --- a/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt +++ b/gradle-plugin/src/main/java/com/itsaky/androidide/gradle/COTGSettingsPlugin.kt @@ -5,6 +5,7 @@ import com.itsaky.androidide.tooling.api.GradlePluginConfig._PROPERTY_MAVEN_LOCA import org.adfa.constants.MAVEN_LOCAL_REPOSITORY import org.gradle.StartParameter import org.gradle.api.Plugin +import org.gradle.api.Project import org.gradle.api.artifacts.dsl.RepositoryHandler import org.gradle.api.artifacts.repositories.MavenArtifactRepository import org.gradle.api.initialization.Settings @@ -64,6 +65,41 @@ class COTGSettingsPlugin : Plugin { } } +/** + * Add the on-device Maven repo to a settings-level `buildscript` classpath. + * + * [COTGSettingsPlugin] only reaches `pluginManagement` and + * `dependencyResolutionManagement`, and it is applied from `settingsEvaluated` -- by + * which point a `buildscript { }` block in `settings.gradle.kts` has already resolved + * against its own repositories. A project that declares its build classpath that way + * (the plugin template does) therefore had no offline repository to resolve from and + * could only be built online. This must run from `beforeSettings`. + * + * Missing repo is not fatal here: the directory does not exist until onboarding has + * installed the assets, and failing would break every build before that point. + */ +fun Settings.addLocalMavenRepoToBuildscript(logger: Logger) { + localMavenRepoDir(logger)?.let { buildscript.repositories.addMavenRepoIfMissing(logger, it.toURI()) } +} + +/** + * Same problem, project scope: a `buildscript { }` block in build.gradle.kts resolves against + * its own repositories, which [COTGSettingsPlugin] never reaches. Templates pin the Kotlin + * version there for AGP 9's built-in Kotlin, so that classpath must resolve offline. + */ +fun Project.addLocalMavenRepoToBuildscript(logger: Logger) { + localMavenRepoDir(logger)?.let { buildscript.repositories.addMavenRepoIfMissing(logger, it.toURI()) } +} + +private fun localMavenRepoDir(logger: Logger): File? { + val dir = File(MAVEN_LOCAL_REPOSITORY) + if (!dir.isDirectory) { + logger.info("Local maven repo not installed yet, skipping buildscript injection: $MAVEN_LOCAL_REPOSITORY") + return null + } + return dir +} + private fun RepositoryHandler.addLocalMavenRepoIfMissing( logger: Logger, path: String,