Implemented the new IProject service in the IDE

This commit is contained in:
Akash Yadav
2022-05-17 19:05:00 +05:30
parent fd13dce5e0
commit df379478f1
51 changed files with 2020 additions and 1838 deletions
-1
View File
@@ -2,6 +2,5 @@
<project version="4">
<component name="GoogleJavaFormatSettings">
<option name="enabled" value="true" />
<option name="style" value="AOSP" />
</component>
</project>
Binary file not shown.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,117 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.projects
import com.itsaky.androidide.tooling.api.IProject
import com.itsaky.androidide.tooling.api.messages.result.SimpleModuleData
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.IdeGradleTask
import com.itsaky.androidide.utils.ILogger
import java.io.File
import java.util.concurrent.*
/**
* A project which lazily caches some required properties of the given project.
*
* @author Akash Yadav
*/
class CachingProject(val project: IProject) : IProject {
private val log = ILogger.newInstance(javaClass.simpleName)
private val mName: String by lazy { this.project.name.get() }
private val mDescription: String by lazy { this.project.description.get() }
private val mProjectPath: String by lazy { this.project.projectPath.get() }
private val mProjectDir: File by lazy { this.project.projectDir.get() }
private val mBuildDir: File by lazy { this.project.buildDir.get() }
private val mBuildScript: File by lazy { this.project.buildScript.get() }
private var mFirstAppModule: IdeAndroidModule? = null
private val mModules: MutableList<SimpleModuleData> = mutableListOf()
override fun getName(): CompletableFuture<String> {
return CompletableFuture.completedFuture(this.mName)
}
override fun getDescription(): CompletableFuture<String> {
return CompletableFuture.completedFuture(mDescription)
}
override fun getProjectPath(): CompletableFuture<String> {
return CompletableFuture.completedFuture(mProjectPath)
}
override fun getProjectDir(): CompletableFuture<File> {
return CompletableFuture.completedFuture(mProjectDir)
}
override fun getBuildDir(): CompletableFuture<File> {
return CompletableFuture.completedFuture(mBuildDir)
}
override fun getBuildScript(): CompletableFuture<File> {
return CompletableFuture.completedFuture(mBuildScript)
}
override fun getTasks(): CompletableFuture<MutableList<IdeGradleTask>> {
return this.project.tasks
}
override fun getModules(): CompletableFuture<MutableList<IdeGradleProject>> {
return this.project.modules
}
override fun listModules(): CompletableFuture<MutableList<SimpleModuleData>> {
return if (this.mModules.isNotEmpty()) {
CompletableFuture.completedFuture(mModules)
} else {
this.project.listModules().whenComplete { modules, err ->
if (err != null || modules == null || modules.isEmpty()) {
log.warn("Unable to fetch module data", err)
return@whenComplete
}
this.mModules.clear()
this.mModules.addAll(modules.filterNotNull())
}
}
}
override fun findByPath(path: String): CompletableFuture<IdeGradleProject> {
return this.project.findByPath(path)
}
override fun findAndroidModules(): CompletableFuture<MutableList<IdeAndroidModule>> {
return this.project.findAndroidModules()
}
override fun findFirstAndroidModule(): CompletableFuture<IdeAndroidModule> {
return this.project.findFirstAndroidModule()
}
override fun findFirstAndroidAppModule(): CompletableFuture<IdeAndroidModule> {
if (mFirstAppModule != null) {
return CompletableFuture.completedFuture(mFirstAppModule)
}
return this.project.findFirstAndroidAppModule().whenComplete { module, _ ->
this.mFirstAppModule = module
}
}
}
@@ -21,29 +21,50 @@ import com.android.builder.model.v2.ide.LibraryType.JAVA_LIBRARY
import com.android.builder.model.v2.ide.LibraryType.PROJECT
import com.itsaky.androidide.app.StudioApp
import com.itsaky.androidide.services.BuildService
import com.itsaky.androidide.tooling.api.IProject
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.IdeJavaModule
import com.itsaky.androidide.tooling.api.model.IdeModule
import com.itsaky.androidide.utils.ILogger
import com.itsaky.lsp.java.models.JavaServerConfiguration
import java.io.File
import java.nio.file.Path
import java.util.concurrent.*
/**
* Manages projects in AndroidIDE.
*
* @author Akash Yadav
*/
@Suppress("MemberVisibilityCanBePrivate")
object ProjectManager {
private val log = com.itsaky.androidide.utils.ILogger.newInstance(javaClass.simpleName)
var rootProject: IdeGradleProject? = null
private val log = ILogger.newInstance(javaClass.simpleName)
var rootProject: IProject? = null
set(value) {
field = if (value == null) null else CachingProject(value)
// Cache the module data in advance for future use
if (field != null) {
field!!.listModules()
}
}
var projectPath: String? = null
fun getProjectDir(): File? =
if (getProjectDirPath() == null) null else File(getProjectDirPath()!!)
fun isInitialized() = this.rootProject != null && this.rootProject!!.isInitialized.get()
fun checkInit(): Boolean {
if (isInitialized()) {
return true
}
log.warn("Project is not initialized yet!")
return false
}
fun getProjectDir(): File? = if (!checkInit()) null else File(getProjectDirPath()!!)
fun getProjectDirPath(): String? =
if (rootProject == null) projectPath else rootProject!!.projectDir!!.absolutePath
if (!checkInit()) projectPath else rootProject!!.projectDir.get().absolutePath
fun generateSources(builder: BuildService?) {
if (builder == null) {
@@ -51,62 +72,63 @@ object ProjectManager {
return
}
val app =
getApplicationModule()
?: kotlin.run {
log.error("Cannot generate resources...")
return
}
val debug = app.variants.firstOrNull { it.name == "debug" }
if (debug == null) {
log.warn("No debug variant found in application project ${app.name}")
return
}
val mainArtifact = app.variants.first { it.name == "debug" }.mainArtifact
val genResourcesTask = mainArtifact.resGenTaskName
val genSourcesTask = mainArtifact.sourceGenTaskName
builder
.executeProjectTasks(
app.projectPath!!,
genResourcesTask ?: "",
genSourcesTask,
// If view binding is enabled, generate the view binding classes too
if (app.viewBindingOptions != null && app.viewBindingOptions!!.isEnabled)
"dataBindingGenBaseClassesDebug"
else "")
.whenComplete { result, err ->
if (!result.isSuccessful || err != null) {
log.warn(
"Execution for tasks '$genResourcesTask' and '$genSourcesTask' failed.",
err ?: "")
return@whenComplete
}
notifyProjectUpdate()
getApplicationModule().whenComplete { app, _ ->
if (app == null) {
log.warn(
"Cannot run resource and source generation task. No application module found.")
return@whenComplete
}
val debug = app.variants.firstOrNull { it.name == "debug" }
if (debug == null) {
log.warn("No debug variant found in application project ${app.name}")
return@whenComplete
}
val mainArtifact = app.variants.first { it.name == "debug" }.mainArtifact
val genResourcesTask = mainArtifact.resGenTaskName
val genSourcesTask = mainArtifact.sourceGenTaskName
builder
.executeProjectTasks(
app.projectPath,
genResourcesTask ?: "",
genSourcesTask,
// If view binding is enabled, generate the view binding classes too
if (app.viewBindingOptions != null && app.viewBindingOptions!!.isEnabled)
"dataBindingGenBaseClassesDebug"
else "")
.whenComplete { result, taskErr ->
if (!result.isSuccessful || taskErr != null) {
log.warn(
"Execution for tasks '$genResourcesTask' and '$genSourcesTask' failed.",
taskErr ?: "")
} else {
notifyProjectUpdate()
}
}
}
}
fun getApplicationModule(): IdeAndroidModule? {
fun getApplicationModule(): CompletableFuture<IdeAndroidModule?> {
if (rootProject == null) {
log.error(
"No root project instance is set. Is the project initialization process finished?")
return null
return CompletableFuture.completedFuture(null)
}
val app = rootProject!!.findFirstAndroidModule()
if (app == null) {
log.error("No application module found in root project.")
return null
return rootProject!!.findFirstAndroidAppModule().whenComplete { app, err ->
if (app == null || err != null) {
log.debug("An error occurred while fetching model for application module.")
return@whenComplete
}
}
return app
}
fun getApplicationResDirectories(): List<File>? {
return collectResDirectories(getApplicationModule() ?: return null)
fun getApplicationResDirectories(): CompletableFuture<List<File>?> {
return getApplicationModule().thenApplyAsync {
if (it == null) null else collectResDirectories(it)
}
}
fun collectResDirectories(android: IdeAndroidModule): List<File> {
@@ -133,15 +155,21 @@ object ProjectManager {
}
fun notifyProjectUpdate() {
val server = StudioApp.getInstance().javaLanguageServer
val sourceDirs = collectApplicationSourceDirs()
val classPaths = collectApplicationClassPaths()
val configuration = JavaServerConfiguration(classPaths, sourceDirs)
server.configurationChanged(configuration)
getApplicationModule().thenAccept {
if (it == null) {
log.debug("Cannot find application module. Unable to update class paths to LSP.")
return@thenAccept
}
val server = StudioApp.getInstance().javaLanguageServer
val sourceDirs = collectSourceDirs(it)
val classPaths = collectClassPaths(it)
val configuration = JavaServerConfiguration(classPaths, sourceDirs)
server.configurationChanged(configuration)
}
}
private fun collectApplicationClassPaths(): Set<Path> {
val app = getApplicationModule() ?: return emptySet()
private fun collectClassPaths(app: IdeAndroidModule): Set<Path> {
val libraries = app.variantDependencies["debug"]!!.libraries
val paths = mutableSetOf<Path>()
@@ -153,7 +181,7 @@ object ProjectManager {
paths.add(value.artifact!!.toPath())
} else {
val project =
rootProject!!.findByPath(value.projectInfo!!.projectPath)!! as IdeModule
rootProject!!.findByPath(value.projectInfo!!.projectPath).get() as IdeModule
paths.add(project.getGeneratedJar("debug").toPath())
if (project is IdeAndroidModule && project.projectPath != app.projectPath) {
@@ -171,8 +199,7 @@ object ProjectManager {
return paths
}
private fun collectApplicationSourceDirs(): Set<Path> {
val app = getApplicationModule() ?: return emptySet()
private fun collectSourceDirs(app: IdeAndroidModule): Set<Path> {
val sources = app.mainSourceSet ?: return emptySet()
val javaDirs = sources.sourceProvider.javaDirectories
val sourcePaths = javaDirs.toMutableSet()
@@ -181,15 +208,12 @@ object ProjectManager {
return sourcePaths.map { it.toPath() }.toSet()
}
fun collectProjectDependencies(
project: IdeGradleProject,
app: IdeAndroidModule
): List<IdeModule> {
fun collectProjectDependencies(project: IProject, app: IdeAndroidModule): List<IdeModule> {
return app.variantDependencies["debug"]!!
.libraries.values
.filter { it.type == PROJECT }
.mapNotNull { project.findByPath(it.projectInfo!!.projectPath) }
.map { project.findByPath(it.projectInfo!!.projectPath) }
.filterIsInstance(IdeModule::class.java)
}
@@ -245,38 +269,4 @@ object ProjectManager {
android.variants.first { it.name == "debug" }.mainArtifact.generatedSourceFolders)
return sources
}
/**
* Finds the module in which the given file exists.
*
* @return The module in which the given file exists or `null` if the module cannot be found.
*/
fun findModuleForFile(file: File): IdeModule? {
if (rootProject == null) {
log.warn(
"No root project instance is set. Is the project initialization process finished?")
return null
}
val path = file.canonicalPath
val modules = rootProject!!.getModules()
var longestPath = ""
var longestPathModule: IdeModule? = null
for (module in modules) {
val modulePath = module.projectDir!!.canonicalPath
if (path.startsWith(modulePath)) {
if (longestPath.length < modulePath.length && module is IdeModule) {
longestPathModule = module
longestPath = modulePath
}
}
}
if (longestPath.isEmpty()) {
return null
}
return longestPathModule
}
}
@@ -54,6 +54,7 @@ import com.itsaky.androidide.tooling.api.messages.result.BuildResult;
import com.itsaky.androidide.tooling.api.messages.result.GradleWrapperCheckResult;
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult;
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher;
import com.itsaky.androidide.tooling.events.ProgressEvent;
import com.itsaky.androidide.utils.Environment;
@@ -486,14 +487,16 @@ public class GradleBuildService extends Service implements BuildService, IToolin
Environment.TOOLING_API_JAR.getAbsolutePath());
final var launcher =
ToolingApiLauncher.createClientLauncher(
ToolingApiLauncher.newClientLauncher(
GradleBuildService.this, serverStreams.in, serverStreams.out);
final var future = launcher.startListening();
GradleBuildService.this.startServerOutputReader(serverStreams.err);
GradleBuildService.this.server = launcher.getRemoteProxy();
GradleBuildService.this.server = (IToolingApiServer) launcher.getRemoteProxy();
GradleBuildService.this.isToolingServerStarted = true;
ProjectManager.INSTANCE.setRootProject((IProject) launcher.getRemoteProxy());
if (listener != null) {
listener.onServerStarted();
}
@@ -505,7 +508,8 @@ public class GradleBuildService extends Service implements BuildService, IToolin
if (!(err instanceof CancellationException)
&& !(err instanceof InterruptedException)) {
LOG.error(
"An error occurred while waiting for tooling API server to terminate", err);
"An error occurred while waiting for tooling API server to terminate",
err);
}
}
@@ -0,0 +1 @@
/build
@@ -0,0 +1,31 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
}
java {
sourceCompatibility = rootProject.ext.javaSourceVersion
targetCompatibility = rootProject.ext.javaTargetVersion
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
api "com.android.tools.build:builder-model:${project.property ("androidide.tooling.supportedAgpVersion")}"
}
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.AndroidArtifact
import com.android.builder.model.v2.ide.CodeShrinker
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.AndroidGradlePluginProjectFlags
import com.android.builder.model.v2.ide.AndroidGradlePluginProjectFlags.BooleanFlag
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.AndroidLibraryData
import java.io.File
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.ApiVersion
import java.io.Serializable
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.ArtifactDependencies
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.BundleInfo
import java.io.File
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.CustomSourceDirectory
import java.io.File
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.GraphItem
import java.io.Serializable
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.JavaArtifact
import java.io.File
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.JavaCompileOptions
import java.io.Serializable
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.Library
import com.android.builder.model.v2.ide.LibraryType
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.LibraryInfo
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.models.ModelBuilderParameter
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ModelSyncFile
import com.android.builder.model.v2.ModelSyncFile.ModelSyncType
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.ProjectInfo
import java.io.Serializable
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.models.ProjectSyncIssues
import java.io.Serializable
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.SourceProvider
import java.io.File
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.SourceSetContainer
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.SyncIssue
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.TestInfo
import com.android.builder.model.v2.ide.TestInfo.Execution
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.TestedTargetVariant
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.UnresolvedDependency
import java.io.Serializable
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.Variant
import java.io.File
@@ -14,8 +14,7 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.models.VariantDependencies
import java.io.Serializable
@@ -15,7 +15,7 @@
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model.internal
package com.itsaky.androidide.builder.model
import com.android.builder.model.v2.ide.ViewBindingOptions
import java.io.Serializable
@@ -21,7 +21,6 @@ import static com.itsaky.androidide.utils.ILogger.newInstance;
import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.tooling.api.IToolingApiClient;
import com.itsaky.androidide.tooling.api.model.IProject;
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher;
import com.itsaky.androidide.tooling.impl.model.InternalForwardingProject;
import com.itsaky.androidide.tooling.impl.progress.ForwardingProgressListener;
@@ -37,7 +37,7 @@ import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Fai
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Failure.UNSUPPORTED_CONFIGURATION
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult.Failure.UNSUPPORTED_GRADLE_VERSION
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
import com.itsaky.androidide.builder.model.DefaultProjectSyncIssues
import com.itsaky.androidide.tooling.impl.model.InternalForwardingProject
import com.itsaky.androidide.tooling.impl.progress.ForwardingProgressListener
import com.itsaky.androidide.tooling.impl.util.ProjectReader
@@ -229,6 +229,7 @@ internal class ToolingApiServerImpl(private val forwardingProject: InternalForwa
this.client = null
this.project = null
this.buildCancellationToken = null
this.forwardingProject.project = null
Main.future = null
Main.client = null
@@ -17,8 +17,9 @@
package com.itsaky.androidide.tooling.impl.model
import com.itsaky.androidide.tooling.api.IProject
import com.itsaky.androidide.tooling.api.IToolingApiClient
import com.itsaky.androidide.tooling.api.model.IProject
import com.itsaky.androidide.tooling.api.messages.result.SimpleModuleData
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.IdeGradleTask
@@ -40,6 +41,10 @@ class InternalForwardingProject(var project: IProject?) : IProject {
private val log = ILogger.newInstance(javaClass.simpleName)
override fun isInitialized(): CompletableFuture<Boolean> {
return CompletableFuture.completedFuture(this.project != null)
}
override fun getName(): CompletableFuture<String> =
if (this.project != null) this.project!!.name else CompletableFuture.completedFuture("")
@@ -71,6 +76,10 @@ class InternalForwardingProject(var project: IProject?) : IProject {
if (this.project != null) this.project!!.modules
else CompletableFuture.completedFuture(mutableListOf())
override fun listModules(): CompletableFuture<MutableList<SimpleModuleData>> =
if (this.project != null) project!!.listModules()
else CompletableFuture.completedFuture(mutableListOf())
override fun findByPath(path: String): CompletableFuture<IdeGradleProject?> =
if (this.project != null) this.project!!.findByPath(path)
else CompletableFuture.completedFuture(null)
@@ -82,4 +91,8 @@ class InternalForwardingProject(var project: IProject?) : IProject {
override fun findFirstAndroidModule(): CompletableFuture<IdeAndroidModule?> =
if (this.project != null) this.project!!.findFirstAndroidModule()
else CompletableFuture.completedFuture(null)
override fun findFirstAndroidAppModule(): CompletableFuture<IdeAndroidModule> =
if (this.project != null) this.project!!.findFirstAndroidAppModule()
else CompletableFuture.completedFuture(null)
}
@@ -18,7 +18,7 @@
package com.itsaky.androidide.tooling.impl.util
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
import com.itsaky.androidide.builder.model.DefaultProjectSyncIssues
import java.io.Serializable
/** @author Akash Yadav */
@@ -36,7 +36,7 @@ import com.itsaky.androidide.tooling.api.model.JavaModuleDependency;
import com.itsaky.androidide.tooling.api.model.JavaModuleExternalDependency;
import com.itsaky.androidide.tooling.api.model.JavaModuleProjectDependency;
import com.itsaky.androidide.tooling.api.model.JavaSourceDirectory;
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues;
import com.itsaky.androidide.builder.model.DefaultProjectSyncIssues;
import com.itsaky.androidide.tooling.api.model.util.AndroidModulePropertyCopier;
import com.itsaky.androidide.tooling.api.model.util.ProjectBuilder;
import com.itsaky.androidide.tooling.impl.Main;
@@ -27,7 +27,7 @@ import com.itsaky.androidide.tooling.api.IToolingApiServer
import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage
import com.itsaky.androidide.tooling.api.messages.result.BuildResult
import com.itsaky.androidide.tooling.api.messages.result.GradleWrapperCheckResult
import com.itsaky.androidide.tooling.api.model.IProject
import com.itsaky.androidide.tooling.api.IProject
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.IdeJavaModule
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher
+1 -2
View File
@@ -14,7 +14,6 @@
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
@@ -34,9 +33,9 @@ repositories {
dependencies {
implementation project (path: ':build-tools:logger')
implementation project (path: ':build-tools:xml-dom')
api project (path: ':build-tools:builder-model-impl')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
api "com.android.tools.build:builder-model:${project.property ("androidide.tooling.supportedAgpVersion")}"
}
task copyToTestDir (type: Copy) {
@@ -0,0 +1,98 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api;
import com.itsaky.androidide.tooling.api.messages.result.SimpleModuleData;
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule;
import com.itsaky.androidide.tooling.api.model.IdeGradleProject;
import com.itsaky.androidide.tooling.api.model.IdeGradleTask;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
import org.eclipse.lsp4j.jsonrpc.services.JsonSegment;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Root Gradle project. The getter methods return completed {@link CompletableFuture}s.
*
* @author Akash Yadav
*/
@JsonSegment("project")
public interface IProject {
@NotNull
@JsonRequest
default CompletableFuture<Boolean> isInitialized() {
return CompletableFuture.completedFuture(true);
}
@NotNull
@JsonRequest
CompletableFuture<String> getName();
@NotNull
@JsonRequest
CompletableFuture<String> getDescription();
@NotNull
@JsonRequest
CompletableFuture<String> getProjectPath();
@NotNull
@JsonRequest
CompletableFuture<File> getProjectDir();
@NotNull
@JsonRequest
CompletableFuture<File> getBuildDir();
@NotNull
@JsonRequest
CompletableFuture<File> getBuildScript();
@NotNull
@JsonRequest
CompletableFuture<List<IdeGradleTask>> getTasks();
@NotNull
@JsonRequest
CompletableFuture<List<IdeGradleProject>> getModules();
@NotNull
@JsonRequest
CompletableFuture<List<SimpleModuleData>> listModules();
@NotNull
@JsonRequest
CompletableFuture<IdeGradleProject> findByPath(@NotNull String path);
@NotNull
@JsonRequest
CompletableFuture<IdeAndroidModule> findFirstAndroidModule();
@NotNull
@JsonRequest
CompletableFuture<IdeAndroidModule> findFirstAndroidAppModule();
@NotNull
@JsonRequest
CompletableFuture<List<IdeAndroidModule>> findAndroidModules();
}
@@ -0,0 +1,27 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.messages.result
import java.io.File
/**
* Container for basic data about module projects.
*
* @author Akash Yadav
*/
data class SimpleModuleData(val name: String, val path: String, val projectDir: File)
@@ -1,79 +0,0 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.tooling.api.model;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
import org.eclipse.lsp4j.jsonrpc.services.JsonSegment;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Root Gradle project. The getter methods return completed {@link CompletableFuture}s.
*
* @author Akash Yadav
*/
@JsonSegment("project")
public interface IProject {
@NotNull
@JsonRequest
CompletableFuture<String> getName();
@NotNull
@JsonRequest
CompletableFuture<String> getDescription();
@NotNull
@JsonRequest
CompletableFuture<String> getProjectPath();
@NotNull
@JsonRequest
CompletableFuture<File> getProjectDir();
@NotNull
@JsonRequest
CompletableFuture<File> getBuildDir();
@NotNull
@JsonRequest
CompletableFuture<File> getBuildScript();
@NotNull
@JsonRequest
CompletableFuture<List<IdeGradleTask>> getTasks();
@NotNull
@JsonRequest
CompletableFuture<List<IdeGradleProject>> getModules();
@NotNull
@JsonRequest
CompletableFuture<IdeGradleProject> findByPath(@NotNull String path);
@NotNull
@JsonRequest
CompletableFuture<List<IdeAndroidModule>> findAndroidModules();
@NotNull
@JsonRequest
CompletableFuture<IdeAndroidModule> findFirstAndroidModule();
}
@@ -18,14 +18,14 @@ package com.itsaky.androidide.tooling.api.model
import com.android.builder.model.v2.ide.ProjectType
import com.android.builder.model.v2.models.AndroidProject
import com.itsaky.androidide.tooling.api.model.internal.DefaultAndroidGradlePluginProjectFlags
import com.itsaky.androidide.tooling.api.model.internal.DefaultJavaCompileOptions
import com.itsaky.androidide.tooling.api.model.internal.DefaultModelSyncFile
import com.itsaky.androidide.tooling.api.model.internal.DefaultSourceProvider
import com.itsaky.androidide.tooling.api.model.internal.DefaultSourceSetContainer
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariant
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariantDependencies
import com.itsaky.androidide.tooling.api.model.internal.DefaultViewBindingOptions
import com.itsaky.androidide.builder.model.DefaultAndroidGradlePluginProjectFlags
import com.itsaky.androidide.builder.model.DefaultJavaCompileOptions
import com.itsaky.androidide.builder.model.DefaultModelSyncFile
import com.itsaky.androidide.builder.model.DefaultSourceProvider
import com.itsaky.androidide.builder.model.DefaultSourceSetContainer
import com.itsaky.androidide.builder.model.DefaultVariant
import com.itsaky.androidide.builder.model.DefaultVariantDependencies
import com.itsaky.androidide.builder.model.DefaultViewBindingOptions
import org.eclipse.lemminx.dom.DOMParser
import org.eclipse.lemminx.uriresolver.URIResolverExtensionManager
import java.io.File
@@ -16,10 +16,12 @@
*/
package com.itsaky.androidide.tooling.api.model
import com.android.builder.model.v2.ide.ProjectType.APPLICATION
import com.itsaky.androidide.tooling.api.messages.result.SimpleModuleData
import org.eclipse.lsp4j.jsonrpc.CompletableFutures
import java.io.File
import java.io.Serializable
import java.util.concurrent.*
import org.eclipse.lsp4j.jsonrpc.CompletableFutures
/**
* A root Gradle project.
@@ -34,7 +36,7 @@ open class IdeGradleProject(
@JvmField val buildScript: File,
@JvmField val parent: IdeGradleProject?,
@JvmField val tasks: List<IdeGradleTask>,
) : IProject, Serializable {
) : com.itsaky.androidide.tooling.api.IProject, Serializable {
private val serialVersionUID = 1L
private val gsonType: String = javaClass.name
@@ -72,6 +74,14 @@ open class IdeGradleProject(
return CompletableFutures.computeAsync { this.moduleProjects.toMutableList() }
}
override fun listModules(): CompletableFuture<MutableList<SimpleModuleData>> {
return CompletableFutures.computeAsync {
return@computeAsync this.moduleProjects
.map { SimpleModuleData(it.name, it.projectPath, it.projectDir) }
.toMutableList()
}
}
override fun findByPath(path: String): CompletableFuture<IdeGradleProject?> {
return CompletableFutures.computeAsync {
if (path == this.projectPath) {
@@ -91,4 +101,12 @@ open class IdeGradleProject(
override fun findFirstAndroidModule(): CompletableFuture<IdeAndroidModule?> {
return findAndroidModules().thenApply { it.firstOrNull() }
}
override fun findFirstAndroidAppModule(): CompletableFuture<IdeAndroidModule> {
return findAndroidModules().thenApply { modules ->
val application =
modules.stream().filter { it != null && it.projectType == APPLICATION }.findFirst()
application.orElse(null)
}
}
}
@@ -43,30 +43,30 @@ import com.android.builder.model.v2.ide.ViewBindingOptions
import com.android.builder.model.v2.models.ProjectSyncIssues
import com.android.builder.model.v2.models.VariantDependencies
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule
import com.itsaky.androidide.tooling.api.model.internal.DefaultAndroidArtifact
import com.itsaky.androidide.tooling.api.model.internal.DefaultAndroidGradlePluginProjectFlags
import com.itsaky.androidide.tooling.api.model.internal.DefaultAndroidLibraryData
import com.itsaky.androidide.tooling.api.model.internal.DefaultApiVersion
import com.itsaky.androidide.tooling.api.model.internal.DefaultArtifactDependencies
import com.itsaky.androidide.tooling.api.model.internal.DefaultBundleInfo
import com.itsaky.androidide.tooling.api.model.internal.DefaultCustomSourceDirectory
import com.itsaky.androidide.tooling.api.model.internal.DefaultGraphItem
import com.itsaky.androidide.tooling.api.model.internal.DefaultJavaArtifact
import com.itsaky.androidide.tooling.api.model.internal.DefaultJavaCompileOptions
import com.itsaky.androidide.tooling.api.model.internal.DefaultLibrary
import com.itsaky.androidide.tooling.api.model.internal.DefaultLibraryInfo
import com.itsaky.androidide.tooling.api.model.internal.DefaultModelSyncFile
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectInfo
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
import com.itsaky.androidide.tooling.api.model.internal.DefaultSourceProvider
import com.itsaky.androidide.tooling.api.model.internal.DefaultSourceSetContainer
import com.itsaky.androidide.tooling.api.model.internal.DefaultSyncIssue
import com.itsaky.androidide.tooling.api.model.internal.DefaultTestInfo
import com.itsaky.androidide.tooling.api.model.internal.DefaultTestedTargetVariant
import com.itsaky.androidide.tooling.api.model.internal.DefaultUnresolvedDependency
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariant
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariantDependencies
import com.itsaky.androidide.tooling.api.model.internal.DefaultViewBindingOptions
import com.itsaky.androidide.builder.model.DefaultAndroidArtifact
import com.itsaky.androidide.builder.model.DefaultAndroidGradlePluginProjectFlags
import com.itsaky.androidide.builder.model.DefaultAndroidLibraryData
import com.itsaky.androidide.builder.model.DefaultApiVersion
import com.itsaky.androidide.builder.model.DefaultArtifactDependencies
import com.itsaky.androidide.builder.model.DefaultBundleInfo
import com.itsaky.androidide.builder.model.DefaultCustomSourceDirectory
import com.itsaky.androidide.builder.model.DefaultGraphItem
import com.itsaky.androidide.builder.model.DefaultJavaArtifact
import com.itsaky.androidide.builder.model.DefaultJavaCompileOptions
import com.itsaky.androidide.builder.model.DefaultLibrary
import com.itsaky.androidide.builder.model.DefaultLibraryInfo
import com.itsaky.androidide.builder.model.DefaultModelSyncFile
import com.itsaky.androidide.builder.model.DefaultProjectInfo
import com.itsaky.androidide.builder.model.DefaultProjectSyncIssues
import com.itsaky.androidide.builder.model.DefaultSourceProvider
import com.itsaky.androidide.builder.model.DefaultSourceSetContainer
import com.itsaky.androidide.builder.model.DefaultSyncIssue
import com.itsaky.androidide.builder.model.DefaultTestInfo
import com.itsaky.androidide.builder.model.DefaultTestedTargetVariant
import com.itsaky.androidide.builder.model.DefaultUnresolvedDependency
import com.itsaky.androidide.builder.model.DefaultVariant
import com.itsaky.androidide.builder.model.DefaultVariantDependencies
import com.itsaky.androidide.builder.model.DefaultViewBindingOptions
import com.itsaky.androidide.utils.ILogger
/**
@@ -23,11 +23,11 @@ import com.itsaky.androidide.tooling.api.model.IdeGradleTask
import com.itsaky.androidide.tooling.api.model.IdeJavaModule
import com.itsaky.androidide.tooling.api.model.JavaContentRoot
import com.itsaky.androidide.tooling.api.model.JavaModuleDependency
import com.itsaky.androidide.tooling.api.model.internal.DefaultAndroidGradlePluginProjectFlags
import com.itsaky.androidide.tooling.api.model.internal.DefaultJavaCompileOptions
import com.itsaky.androidide.tooling.api.model.internal.DefaultModelSyncFile
import com.itsaky.androidide.tooling.api.model.internal.DefaultVariant
import com.itsaky.androidide.tooling.api.model.internal.DefaultViewBindingOptions
import com.itsaky.androidide.builder.model.DefaultAndroidGradlePluginProjectFlags
import com.itsaky.androidide.builder.model.DefaultJavaCompileOptions
import com.itsaky.androidide.builder.model.DefaultModelSyncFile
import com.itsaky.androidide.builder.model.DefaultVariant
import com.itsaky.androidide.builder.model.DefaultViewBindingOptions
import java.io.File
/**
@@ -18,7 +18,7 @@
package com.itsaky.androidide.tooling.api.messages.result
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.tooling.api.model.internal.DefaultProjectSyncIssues
import com.itsaky.androidide.builder.model.DefaultProjectSyncIssues
/**
* Result received after an initialize project request.
@@ -20,7 +20,7 @@ package com.itsaky.androidide.tooling.api.util;
import com.google.gson.GsonBuilder;
import com.itsaky.androidide.tooling.api.IToolingApiClient;
import com.itsaky.androidide.tooling.api.IToolingApiServer;
import com.itsaky.androidide.tooling.api.model.IProject;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.tooling.api.model.IdeAndroidModule;
import com.itsaky.androidide.tooling.api.model.IdeGradleProject;
import com.itsaky.androidide.tooling.api.model.IdeGradleTask;
@@ -86,10 +86,6 @@ import java.util.concurrent.Executors;
* @author Akash Yadav
*/
public class ToolingApiLauncher {
public static Launcher<IToolingApiServer> createClientLauncher(
IToolingApiClient client, InputStream in, OutputStream out) {
return createIOLauncher(client, IToolingApiServer.class, in, out);
}
public static <T> Launcher<T> createIOLauncher(
Object local, Class<T> remote, InputStream in, OutputStream out) {
@@ -265,9 +261,4 @@ public class ToolingApiLauncher {
return newIoLauncher(
new Object[] {server, project}, new Class[] {IToolingApiClient.class}, in, out);
}
public static Launcher<IToolingApiClient> createServerLauncher(
IToolingApiServer server, InputStream in, OutputStream out) {
return createIOLauncher(server, IToolingApiClient.class, in, out);
}
}
+1
View File
@@ -27,3 +27,4 @@ include ':build-tools:tooling-api-model'
include ':build-tools:xml-dom'
include ':build-tools:xml-formatter'
include ':build-tools:fuzzysearch'
include ':build-tools:builder-model-impl'