Skip to content

Commit

Permalink
implemented switch ui->backgr->ui using completableFuture
Browse files Browse the repository at this point in the history
Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish committed Jul 19, 2023
1 parent 3c6ab10 commit d3679b1
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,12 @@ import com.redhat.devtools.intellij.kubernetes.editor.util.getDocument
import com.redhat.devtools.intellij.kubernetes.editor.util.isKubernetesResource
import com.redhat.devtools.intellij.kubernetes.model.IResourceModel
import com.redhat.devtools.intellij.kubernetes.model.IResourceModelListener
import com.redhat.devtools.intellij.kubernetes.model.Notification
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
import com.redhat.devtools.intellij.kubernetes.model.util.KubernetesClientExceptionUtils.statusMessage
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
import com.redhat.devtools.intellij.kubernetes.model.util.toTitle
import com.redhat.devtools.intellij.kubernetes.model.util.trimWithEllipsis
import io.fabric8.kubernetes.api.model.HasMetadata
import java.util.concurrent.CompletableFuture

/**
* A Decorator for [FileEditor] instances that allows to push or pull the editor content to/from a remote cluster.
Expand Down Expand Up @@ -77,14 +75,14 @@ open class ResourceEditor(
private val getPsiDocumentManager: (Project) -> PsiDocumentManager = { PsiDocumentManager.getInstance(project) },
// for mocking purposes
@Suppress("NAME_SHADOWING")
private val getKubernetesResourceInfo: (VirtualFile?, Project) -> KubernetesResourceInfo? = {
file, project -> com.redhat.devtools.intellij.kubernetes.editor.util.getKubernetesResourceInfo(file,project)
private val getKubernetesResourceInfo: (VirtualFile?, Project) -> KubernetesResourceInfo? = { file, project ->
com.redhat.devtools.intellij.kubernetes.editor.util.getKubernetesResourceInfo(file, project)
},
// for mocking purposes
private val diff: ResourceDiff = ResourceDiff(project),
// for mocking purposes
protected val editorResources: EditorResources = EditorResources(resourceModel)
): Disposable {
) : Disposable {

init {
Disposer.register(editor, this)
Expand Down Expand Up @@ -112,14 +110,15 @@ open class ResourceEditor(
val resources = createResources(
getDocument(editor),
editor.file?.fileType,
resourceModel.getCurrentNamespace())
resourceModel.getCurrentNamespace()
)
val editorResources = editorResources.setResources(resources)

if (editorResources.size == 1) {
// show notification for 1 resource
val editorResource = editorResources.firstOrNull() ?: return@runAsync
showNotification(editorResource)
} else if (editorResources.size > 1){
} else if (editorResources.size > 1) {
// show notification for multiple resources
showNotification(editorResources)
}
Expand Down Expand Up @@ -155,6 +154,7 @@ open class ResourceEditor(
*/
is Modified ->
showPushNotification(true, listOf(editorResource))

else ->
runInUI {
hideNotifications()
Expand All @@ -170,7 +170,7 @@ open class ResourceEditor(
}
val inError = editorResources.filter(FILTER_ERROR)
if (inError.isNotEmpty()) {
showErrorNotification(inError)
showErrorNotification(inError)
} else {
runInUI {
hideNotifications()
Expand Down Expand Up @@ -300,43 +300,38 @@ open class ResourceEditor(
}
}

fun diff() {
val manager = getPsiDocumentManager.invoke(project)
val file = editor.file ?: return
var fileType: FileType? = null
var beforeDiff: String? = null
runInUI {
val document = getDocument.invoke(editor) ?: return@runInUI
fileType = getFileType(document, manager) ?: return@runInUI
beforeDiff = document.text
}
if (fileType == null
|| beforeDiff == null
) {
return
}
runAsync {
try {
open fun diff(): CompletableFuture<Unit> {
return CompletableFuture
.supplyAsync(
// UI thread required
{
val file = editor.file ?: throw ResourceException("Editor ${editor.name} has no file.")
val manager = getPsiDocumentManager.invoke(project)
val document = getDocument.invoke(editor) ?: throw ResourceException("Could not get document for editor ${editor.name}.")
val fileType = getFileType(document, manager) ?: throw ResourceException("Could not determine file type for editor ${editor.name}.")
DiffContext(file, fileType, document.text)
},
{ runInUI { it.run() } }
).thenApplyAsync { context ->
val resourcesOnCluster = editorResources.getAllResourcesOnCluster()
val serialized = serialize(resourcesOnCluster, fileType) ?: return@runAsync
runInUI {
diff.open(file, serialized) { onDiffClosed(beforeDiff) }
}
} catch(e: ResourceException) {
val message = trimWithEllipsis(e.message, 100)
val causeMessage = statusMessage(e.cause)
Notification()
.error("Could not open diff",
if (causeMessage == null) {
message ?: ""
} else if (message == null) {
causeMessage
} else {
"$message: $causeMessage"
}
)
}
}
val serialized = serialize(resourcesOnCluster, context.fileType) ?: throw ResourceException("Could not serialize cluster resources for editor ${editor.name}.")
context.clusterResources = serialized
context
}.thenApplyAsync(
// UI thread required
{ context ->
diff.open(context.file, context.clusterResources) { onDiffClosed(context.document) }
},
{ runInUI { it.run() } }
)
}

private class DiffContext(
val file: VirtualFile,
val fileType: FileType,
val document: String
) {
lateinit var clusterResources: String
}

/*
Expand Down Expand Up @@ -423,13 +418,14 @@ open class ResourceEditor(
}
}

override fun currentNamespaceChanged(new: IActiveContext<*,*>?, old: IActiveContext<*,*>?) {
override fun currentNamespaceChanged(new: IActiveContext<*, *>?, old: IActiveContext<*, *>?) {
// current namespace in same context has changed, recreate cluster resource
editorResources.disposeAll()
update()
}
}
}

/**
* Closes this instance and cleans up references to it.
* - Removes the resource model listener,
Expand All @@ -452,7 +448,9 @@ open class ResourceEditor(
protected open fun enableEditingNonProjectFile() {
if (editor.file == null
|| !isKubernetesResource(
getKubernetesResourceInfo.invoke(editor.file, project))){
getKubernetesResourceInfo.invoke(editor.file, project)
)
) {
return
}
createResourceFileForVirtual(editor.file)?.enableEditingNonProjectFile()
Expand All @@ -477,7 +475,7 @@ open class ResourceEditor(
}

/** for testing purposes */
protected open fun <R: Any> runReadCommand(runnable: () -> R?): R? {
protected open fun <R : Any> runReadCommand(runnable: () -> R?): R? {
return ReadAction.compute<R, Exception>(runnable)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.Progressive
import com.redhat.devtools.intellij.kubernetes.editor.ResourceEditor
import com.redhat.devtools.intellij.kubernetes.editor.ResourceEditorFactory
import com.redhat.devtools.intellij.kubernetes.editor.util.getSelectedFileEditor
import com.redhat.devtools.intellij.kubernetes.model.Notification
import com.redhat.devtools.intellij.kubernetes.model.util.KubernetesClientExceptionUtils
import com.redhat.devtools.intellij.kubernetes.model.util.trimWithEllipsis
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService

class DiffAction: AnAction() {
class DiffAction : AnAction() {

companion object {
const val ID = "com.redhat.devtools.intellij.kubernetes.editor.actions.DiffAction"
Expand All @@ -29,18 +32,39 @@ class DiffAction: AnAction() {
val project = e.project ?: return
val fileEditor = getSelectedFileEditor(project) ?: return
val telemetry = TelemetryService.instance.action(TelemetryService.NAME_PREFIX_EDITOR + "diff")
com.redhat.devtools.intellij.kubernetes.actions.run("Showing diff...", true,
com.redhat.devtools.intellij.kubernetes.actions.run(
"Showing diff...", true,
Progressive {
try {
val editor = ResourceEditorFactory.instance.getExistingOrCreate(fileEditor, project) ?: return@Progressive
editor.diff()
TelemetryService.sendTelemetry(editor.getResources(), telemetry)
} catch (e: Exception) {
logger<DiffAction>().warn("Could not show diff for resource: ${e.message}", e)
Notification().error("Error showing diff", "Could not show diff editor vs resource from cluster: ${e.message}")
telemetry.error(e).send()
}
val editor = ResourceEditorFactory.instance.getExistingOrCreate(fileEditor, project)
?: return@Progressive
editor.diff()
.thenApply {
TelemetryService.sendTelemetry(editor.getResources(), telemetry)
}
.exceptionally { completionException ->
val e = completionException.cause as? Exception
?: completionException as? Exception
?: return@exceptionally
logger<ResourceEditor>().warn("Could not open diff", e)
telemetry.error(e).send()
notify(e)
}
})
}

}
private fun notify(e: Exception) {
val message = trimWithEllipsis(e.message, 100)
val causeMessage = KubernetesClientExceptionUtils.statusMessage(e.cause)
Notification()
.error(
"Could not open diff",
if (causeMessage == null) {
message ?: ""
} else if (message == null) {
causeMessage
} else {
"$message: $causeMessage"
}
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import io.fabric8.kubernetes.api.model.PodBuilder
import io.fabric8.kubernetes.client.KubernetesClient
import io.fabric8.kubernetes.client.KubernetesClientException
import io.fabric8.kubernetes.client.utils.Serialization
import java.util.concurrent.CompletionException
import org.assertj.core.api.Assertions.assertThat
import org.jetbrains.yaml.YAMLFileType
import org.junit.Before
Expand Down Expand Up @@ -563,7 +564,7 @@ class ResourceEditorTest {
doReturn(JsonFileType.INSTANCE)
.whenever(psiFile).fileType
// when
editor.diff()
editor.diff().join()
// then
verify(serialize).invoke(any(), eq(JsonFileType.INSTANCE))
}
Expand All @@ -577,23 +578,22 @@ class ResourceEditorTest {
doReturn(YAMLFileType.YML)
.whenever(psiFile).fileType
// when
editor.diff()
editor.diff().join()
// then
verify(serialize).invoke(any(), eq(YAMLFileType.YML))
}

@Test
fun `#diff should NOT open diff if editor file type is null`() {
@Test(expected = CompletionException::class)
fun `#diff should throw if editor file type is null`() {
// given
givenResources(mapOf(GARGAMEL to NopEditorResourceState()))
doReturn(GARGAMEL_YAML)
.whenever(document).text
doReturn(null)
.whenever(psiFile).fileType
// when
editor.diff()
editor.diff().join()
// then
verify(diff, never()).open(any(), any(), any())
}

@Test
Expand Down

0 comments on commit d3679b1

Please sign in to comment.