mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix: project initialization error is not handled properly
This commit is contained in:
+24
-10
@@ -80,9 +80,12 @@ abstract class ProjectHandlerActivity : BaseEditorActivity(), IProjectHandler {
|
||||
protected val mBuildEventListener = EditorBuildEventListener()
|
||||
|
||||
companion object {
|
||||
|
||||
const val STATE_KEY_FROM_SAVED_INSTANACE = "ide.editor.isFromSavedInstance"
|
||||
const val STATE_KEY_SHOULD_INITIALIZE = "ide.editor.isInitializing"
|
||||
@JvmStatic private val buildServiceConnection = GradleBuildServiceConnnection()
|
||||
|
||||
@JvmStatic
|
||||
private val buildServiceConnection = GradleBuildServiceConnnection()
|
||||
}
|
||||
|
||||
abstract fun doCloseAll(runAfter: () -> Unit)
|
||||
@@ -258,9 +261,11 @@ abstract class ProjectHandlerActivity : BaseEditorActivity(), IProjectHandler {
|
||||
this.initializingFuture!!.whenCompleteAsync { result, error ->
|
||||
releaseServerListener()
|
||||
|
||||
if (result == null || error != null) {
|
||||
if (result == null || !result.isSuccessful || error != null) {
|
||||
log.error("An error occurred initializing the project with Tooling API", error)
|
||||
setStatus(getString(string.msg_project_initialization_failed))
|
||||
ThreadUtils.runOnUiThread {
|
||||
postProjectInit(false)
|
||||
}
|
||||
return@whenCompleteAsync
|
||||
}
|
||||
|
||||
@@ -306,7 +311,7 @@ abstract class ProjectHandlerActivity : BaseEditorActivity(), IProjectHandler {
|
||||
cachedInitResult = result
|
||||
setupProject()
|
||||
notifyProjectUpdate()
|
||||
ThreadUtils.runOnUiThread { postProjectInit() }
|
||||
ThreadUtils.runOnUiThread { postProjectInit(true) }
|
||||
}
|
||||
|
||||
protected open fun preProjectInit() {
|
||||
@@ -314,7 +319,15 @@ abstract class ProjectHandlerActivity : BaseEditorActivity(), IProjectHandler {
|
||||
viewModel.isInitializing = true
|
||||
}
|
||||
|
||||
protected open fun postProjectInit() {
|
||||
protected open fun postProjectInit(isSuccessful: Boolean) {
|
||||
if (!isSuccessful) {
|
||||
setStatus(getString(string.msg_project_initialization_failed))
|
||||
flashError(string.msg_project_initialization_failed)
|
||||
viewModel.isInitializing = false
|
||||
projectInitialized = false
|
||||
return
|
||||
}
|
||||
|
||||
initialSetup()
|
||||
setStatus(getString(string.msg_project_initialized))
|
||||
viewModel.isInitializing = false
|
||||
@@ -336,7 +349,8 @@ abstract class ProjectHandlerActivity : BaseEditorActivity(), IProjectHandler {
|
||||
|
||||
val moduleDirs =
|
||||
try {
|
||||
rootProject!!.subProjects.stream().map(GradleProject::projectDir).collect(Collectors.toList())
|
||||
rootProject!!.subProjects.stream().map(GradleProject::projectDir)
|
||||
.collect(Collectors.toList())
|
||||
} catch (e: Throwable) {
|
||||
flashError(getString(string.msg_no_modules))
|
||||
emptyList()
|
||||
@@ -392,10 +406,10 @@ abstract class ProjectHandlerActivity : BaseEditorActivity(), IProjectHandler {
|
||||
if (extensions.isNotEmpty()) {
|
||||
if (extensions.contains("|")) {
|
||||
for (str in
|
||||
extensions
|
||||
.split(Pattern.quote("|").toRegex())
|
||||
.dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()) {
|
||||
extensions
|
||||
.split(Pattern.quote("|").toRegex())
|
||||
.dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()) {
|
||||
if (str.trim().isEmpty()) {
|
||||
continue
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.impl
|
||||
|
||||
/**
|
||||
* Exception thrown when the project fails to sync/initialize.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ProjectInitializationExeption(reason: String = "", cause: Throwable? = null) :
|
||||
RuntimeException("Failed to initialize project: $reason", cause)
|
||||
+26
-25
@@ -43,7 +43,6 @@ import com.itsaky.androidide.tooling.impl.sync.ModelBuilderException
|
||||
import com.itsaky.androidide.tooling.impl.sync.RootModelBuilder
|
||||
import com.itsaky.androidide.tooling.impl.util.StopWatch
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import org.eclipse.lsp4j.jsonrpc.CompletableFutures
|
||||
import org.gradle.tooling.BuildCancelledException
|
||||
import org.gradle.tooling.BuildException
|
||||
import org.gradle.tooling.CancellationTokenSource
|
||||
@@ -71,7 +70,7 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||
|
||||
override fun initialize(params: InitializeProjectMessage): CompletableFuture<InitializeResult> {
|
||||
return CompletableFutures.computeAsync {
|
||||
return CompletableFuture.supplyAsync {
|
||||
try {
|
||||
if (initialized && connector != null) {
|
||||
connector?.disconnect()
|
||||
@@ -91,11 +90,8 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
stopWatch.lap("Connector created")
|
||||
|
||||
if (this.connector == null) {
|
||||
throw CompletionException(
|
||||
RuntimeException(
|
||||
"Unable to create gradle connector for project directory: ${params.directory}"
|
||||
)
|
||||
)
|
||||
throw IllegalStateException(
|
||||
"Unable to create gradle connector for project directory: ${params.directory}")
|
||||
}
|
||||
|
||||
notifyBeforeBuild(BuildInfo(emptyList()))
|
||||
@@ -103,11 +99,17 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
val connection = this.connector!!.connect()
|
||||
stopWatch.lapFromLast("Project connection established")
|
||||
|
||||
val project = RootModelBuilder.build(connection to "debug") as? ProjectImpl?
|
||||
project ?: throw ModelBuilderException("Failed to build project model")
|
||||
stopWatch.lapFromLast("Project read successful")
|
||||
val project = try {
|
||||
val impl = RootModelBuilder.build(connection to "debug") as? ProjectImpl?
|
||||
?: throw ModelBuilderException("Failed to build project model")
|
||||
impl
|
||||
} catch (err: Throwable) {
|
||||
throw err
|
||||
} finally {
|
||||
connection.close()
|
||||
}
|
||||
|
||||
connection.close()
|
||||
stopWatch.lapFromLast("Project read successful")
|
||||
stopWatch.log()
|
||||
|
||||
this.project.rootProject = project.rootProject
|
||||
@@ -115,13 +117,12 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
initialized = true
|
||||
|
||||
notifyBuildSuccess(emptyList())
|
||||
return@computeAsync InitializeResult(emptyMap())
|
||||
return@supplyAsync InitializeResult(true)
|
||||
} catch (err: Throwable) {
|
||||
log.error(err)
|
||||
log.error("Failed to initialize project", err)
|
||||
notifyBuildFailure(emptyList())
|
||||
return@supplyAsync InitializeResult(false)
|
||||
}
|
||||
|
||||
return@computeAsync InitializeResult(emptyMap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,14 +131,14 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
}
|
||||
|
||||
override fun getRootProject(): CompletableFuture<IProject> {
|
||||
return CompletableFutures.computeAsync {
|
||||
return CompletableFuture.supplyAsync {
|
||||
assertProjectInitialized()
|
||||
return@computeAsync this.project
|
||||
return@supplyAsync this.project
|
||||
}
|
||||
}
|
||||
|
||||
override fun executeTasks(message: TaskExecutionMessage): CompletableFuture<TaskExecutionResult> {
|
||||
return CompletableFutures.computeAsync {
|
||||
return CompletableFuture.supplyAsync {
|
||||
assertProjectInitialized()
|
||||
|
||||
log.debug("Received request to run tasks.", message)
|
||||
@@ -177,10 +178,10 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
builder.run()
|
||||
this.buildCancellationToken = null
|
||||
notifyBuildSuccess(message.tasks)
|
||||
return@computeAsync TaskExecutionResult(true, null)
|
||||
return@supplyAsync TaskExecutionResult(true, null)
|
||||
} catch (error: Throwable) {
|
||||
notifyBuildFailure(message.tasks)
|
||||
return@computeAsync TaskExecutionResult(false, getTaskFailureType(error))
|
||||
return@supplyAsync TaskExecutionResult(false, getTaskFailureType(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,9 +223,9 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
}
|
||||
|
||||
override fun cancelCurrentBuild(): CompletableFuture<BuildCancellationRequestResult> {
|
||||
return CompletableFutures.computeAsync {
|
||||
return CompletableFuture.supplyAsync {
|
||||
if (this.buildCancellationToken == null) {
|
||||
return@computeAsync BuildCancellationRequestResult(
|
||||
return@supplyAsync BuildCancellationRequestResult(
|
||||
false,
|
||||
BuildCancellationRequestResult.Reason.NO_RUNNING_BUILD
|
||||
)
|
||||
@@ -235,10 +236,10 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
} catch (e: Exception) {
|
||||
val failureReason = CANCELLATION_ERROR
|
||||
failureReason.message = "${failureReason.message}: ${e.message}"
|
||||
return@computeAsync BuildCancellationRequestResult(false, failureReason)
|
||||
return@supplyAsync BuildCancellationRequestResult(false, failureReason)
|
||||
}
|
||||
|
||||
return@computeAsync BuildCancellationRequestResult(true, null)
|
||||
return@supplyAsync BuildCancellationRequestResult(true, null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +271,7 @@ internal class ToolingApiServerImpl(private val project: ProjectImpl) :
|
||||
}
|
||||
|
||||
private fun assertProjectInitialized() {
|
||||
if (!isServerInitialized().get() || project == null) {
|
||||
if (!isServerInitialized().get()) {
|
||||
throw CompletionException(IllegalStateException("Project is not initialized!"))
|
||||
}
|
||||
}
|
||||
|
||||
+2
-6
@@ -17,14 +17,10 @@
|
||||
|
||||
package com.itsaky.androidide.tooling.api.messages.result
|
||||
|
||||
import com.itsaky.androidide.builder.model.DefaultProjectSyncIssues
|
||||
|
||||
/**
|
||||
* Result received after an initialize project request.
|
||||
*
|
||||
* @param project The initialized project model.
|
||||
* @param syncIssues The issues reported by the Android Gradle Plugin during the project sync.
|
||||
*
|
||||
* @param isSuccessful Whether the project initialization was successful.
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
data class InitializeResult(val syncIssues: Map<String, DefaultProjectSyncIssues>)
|
||||
class InitializeResult(val isSuccessful: Boolean)
|
||||
|
||||
Reference in New Issue
Block a user