Skip to content

Commit e07d0b7

Browse files
committed
implemented switch ui->backgr->ui using completableFuture
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 9813fe0 commit e07d0b7

File tree

3 files changed

+88
-66
lines changed

3 files changed

+88
-66
lines changed

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/editor/ResourceEditor.kt

+46-48
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,12 @@ import com.redhat.devtools.intellij.kubernetes.editor.util.getDocument
3535
import com.redhat.devtools.intellij.kubernetes.editor.util.isKubernetesResource
3636
import com.redhat.devtools.intellij.kubernetes.model.IResourceModel
3737
import com.redhat.devtools.intellij.kubernetes.model.IResourceModelListener
38-
import com.redhat.devtools.intellij.kubernetes.model.Notification
3938
import com.redhat.devtools.intellij.kubernetes.model.context.IActiveContext
40-
import com.redhat.devtools.intellij.kubernetes.model.util.KubernetesClientExceptionUtils.statusMessage
4139
import com.redhat.devtools.intellij.kubernetes.model.util.ResourceException
4240
import com.redhat.devtools.intellij.kubernetes.model.util.toMessage
4341
import com.redhat.devtools.intellij.kubernetes.model.util.toTitle
44-
import com.redhat.devtools.intellij.kubernetes.model.util.trimWithEllipsis
4542
import io.fabric8.kubernetes.api.model.HasMetadata
43+
import java.util.concurrent.CompletableFuture
4644

4745
/**
4846
* A Decorator for [FileEditor] instances that allows to push or pull the editor content to/from a remote cluster.
@@ -77,14 +75,14 @@ open class ResourceEditor(
7775
private val getPsiDocumentManager: (Project) -> PsiDocumentManager = { PsiDocumentManager.getInstance(project) },
7876
// for mocking purposes
7977
@Suppress("NAME_SHADOWING")
80-
private val getKubernetesResourceInfo: (VirtualFile?, Project) -> KubernetesResourceInfo? = {
81-
file, project -> com.redhat.devtools.intellij.kubernetes.editor.util.getKubernetesResourceInfo(file,project)
78+
private val getKubernetesResourceInfo: (VirtualFile?, Project) -> KubernetesResourceInfo? = { file, project ->
79+
com.redhat.devtools.intellij.kubernetes.editor.util.getKubernetesResourceInfo(file, project)
8280
},
8381
// for mocking purposes
8482
private val diff: ResourceDiff = ResourceDiff(project),
8583
// for mocking purposes
8684
protected val editorResources: EditorResources = EditorResources(resourceModel)
87-
): Disposable {
85+
) : Disposable {
8886

8987
init {
9088
Disposer.register(editor, this)
@@ -112,14 +110,15 @@ open class ResourceEditor(
112110
val resources = createResources(
113111
getDocument(editor),
114112
editor.file?.fileType,
115-
resourceModel.getCurrentNamespace())
113+
resourceModel.getCurrentNamespace()
114+
)
116115
val editorResources = editorResources.setResources(resources)
117116

118117
if (editorResources.size == 1) {
119118
// show notification for 1 resource
120119
val editorResource = editorResources.firstOrNull() ?: return@runAsync
121120
showNotification(editorResource)
122-
} else if (editorResources.size > 1){
121+
} else if (editorResources.size > 1) {
123122
// show notification for multiple resources
124123
showNotification(editorResources)
125124
}
@@ -155,6 +154,7 @@ open class ResourceEditor(
155154
*/
156155
is Modified ->
157156
showPushNotification(true, listOf(editorResource))
157+
158158
else ->
159159
runInUI {
160160
hideNotifications()
@@ -170,7 +170,7 @@ open class ResourceEditor(
170170
}
171171
val inError = editorResources.filter(FILTER_ERROR)
172172
if (inError.isNotEmpty()) {
173-
showErrorNotification(inError)
173+
showErrorNotification(inError)
174174
} else {
175175
runInUI {
176176
hideNotifications()
@@ -300,43 +300,38 @@ open class ResourceEditor(
300300
}
301301
}
302302

303-
fun diff() {
304-
val manager = getPsiDocumentManager.invoke(project)
305-
val file = editor.file ?: return
306-
var fileType: FileType? = null
307-
var beforeDiff: String? = null
308-
runInUI {
309-
val document = getDocument.invoke(editor) ?: return@runInUI
310-
fileType = getFileType(document, manager) ?: return@runInUI
311-
beforeDiff = document.text
312-
}
313-
if (fileType == null
314-
|| beforeDiff == null
315-
) {
316-
return
317-
}
318-
runAsync {
319-
try {
303+
open fun diff(): CompletableFuture<Unit> {
304+
return CompletableFuture
305+
.supplyAsync(
306+
// UI thread required
307+
{
308+
val file = editor.file ?: throw ResourceException("Editor ${editor.name} has no file.")
309+
val manager = getPsiDocumentManager.invoke(project)
310+
val document = getDocument.invoke(editor) ?: throw ResourceException("Could not get document for editor ${editor.name}.")
311+
val fileType = getFileType(document, manager) ?: throw ResourceException("Could not determine file type for editor ${editor.name}.")
312+
DiffContext(file, fileType, document.text)
313+
},
314+
{ runInUI { it.run() } }
315+
).thenApplyAsync { context ->
320316
val resourcesOnCluster = editorResources.getAllResourcesOnCluster()
321-
val serialized = serialize(resourcesOnCluster, fileType) ?: return@runAsync
322-
runInUI {
323-
diff.open(file, serialized) { onDiffClosed(beforeDiff) }
324-
}
325-
} catch(e: ResourceException) {
326-
val message = trimWithEllipsis(e.message, 100)
327-
val causeMessage = statusMessage(e.cause)
328-
Notification()
329-
.error("Could not open diff",
330-
if (causeMessage == null) {
331-
message ?: ""
332-
} else if (message == null) {
333-
causeMessage
334-
} else {
335-
"$message: $causeMessage"
336-
}
337-
)
338-
}
339-
}
317+
val serialized = serialize(resourcesOnCluster, context.fileType) ?: throw ResourceException("Could not serialize cluster resources for editor ${editor.name}.")
318+
context.clusterResources = serialized
319+
context
320+
}.thenApplyAsync(
321+
// UI thread required
322+
{ context ->
323+
diff.open(context.file, context.clusterResources) { onDiffClosed(context.document) }
324+
},
325+
{ runInUI { it.run() } }
326+
)
327+
}
328+
329+
private class DiffContext(
330+
val file: VirtualFile,
331+
val fileType: FileType,
332+
val document: String
333+
) {
334+
lateinit var clusterResources: String
340335
}
341336

342337
/*
@@ -423,13 +418,14 @@ open class ResourceEditor(
423418
}
424419
}
425420

426-
override fun currentNamespaceChanged(new: IActiveContext<*,*>?, old: IActiveContext<*,*>?) {
421+
override fun currentNamespaceChanged(new: IActiveContext<*, *>?, old: IActiveContext<*, *>?) {
427422
// current namespace in same context has changed, recreate cluster resource
428423
editorResources.disposeAll()
429424
update()
430425
}
431426
}
432427
}
428+
433429
/**
434430
* Closes this instance and cleans up references to it.
435431
* - Removes the resource model listener,
@@ -452,7 +448,9 @@ open class ResourceEditor(
452448
protected open fun enableEditingNonProjectFile() {
453449
if (editor.file == null
454450
|| !isKubernetesResource(
455-
getKubernetesResourceInfo.invoke(editor.file, project))){
451+
getKubernetesResourceInfo.invoke(editor.file, project)
452+
)
453+
) {
456454
return
457455
}
458456
createResourceFileForVirtual(editor.file)?.enableEditingNonProjectFile()
@@ -477,7 +475,7 @@ open class ResourceEditor(
477475
}
478476

479477
/** for testing purposes */
480-
protected open fun <R: Any> runReadCommand(runnable: () -> R?): R? {
478+
protected open fun <R : Any> runReadCommand(runnable: () -> R?): R? {
481479
return ReadAction.compute<R, Exception>(runnable)
482480
}
483481

src/main/kotlin/com/redhat/devtools/intellij/kubernetes/editor/actions/DiffAction.kt

+36-12
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@ import com.intellij.openapi.actionSystem.AnAction
1414
import com.intellij.openapi.actionSystem.AnActionEvent
1515
import com.intellij.openapi.diagnostic.logger
1616
import com.intellij.openapi.progress.Progressive
17+
import com.redhat.devtools.intellij.kubernetes.editor.ResourceEditor
1718
import com.redhat.devtools.intellij.kubernetes.editor.ResourceEditorFactory
1819
import com.redhat.devtools.intellij.kubernetes.editor.util.getSelectedFileEditor
1920
import com.redhat.devtools.intellij.kubernetes.model.Notification
21+
import com.redhat.devtools.intellij.kubernetes.model.util.KubernetesClientExceptionUtils
22+
import com.redhat.devtools.intellij.kubernetes.model.util.trimWithEllipsis
2023
import com.redhat.devtools.intellij.kubernetes.telemetry.TelemetryService
2124

22-
class DiffAction: AnAction() {
25+
class DiffAction : AnAction() {
2326

2427
companion object {
2528
const val ID = "com.redhat.devtools.intellij.kubernetes.editor.actions.DiffAction"
@@ -29,18 +32,39 @@ class DiffAction: AnAction() {
2932
val project = e.project ?: return
3033
val fileEditor = getSelectedFileEditor(project) ?: return
3134
val telemetry = TelemetryService.instance.action(TelemetryService.NAME_PREFIX_EDITOR + "diff")
32-
com.redhat.devtools.intellij.kubernetes.actions.run("Showing diff...", true,
35+
com.redhat.devtools.intellij.kubernetes.actions.run(
36+
"Showing diff...", true,
3337
Progressive {
34-
try {
35-
val editor = ResourceEditorFactory.instance.getExistingOrCreate(fileEditor, project) ?: return@Progressive
36-
editor.diff()
37-
TelemetryService.sendTelemetry(editor.getResources(), telemetry)
38-
} catch (e: Exception) {
39-
logger<DiffAction>().warn("Could not show diff for resource: ${e.message}", e)
40-
Notification().error("Error showing diff", "Could not show diff editor vs resource from cluster: ${e.message}")
41-
telemetry.error(e).send()
42-
}
38+
val editor = ResourceEditorFactory.instance.getExistingOrCreate(fileEditor, project)
39+
?: return@Progressive
40+
editor.diff()
41+
.thenApply {
42+
TelemetryService.sendTelemetry(editor.getResources(), telemetry)
43+
}
44+
.exceptionally { completionException ->
45+
val e = completionException.cause as? Exception
46+
?: completionException as? Exception
47+
?: return@exceptionally
48+
logger<ResourceEditor>().warn("Could not open diff", e)
49+
telemetry.error(e).send()
50+
notify(e)
51+
}
4352
})
4453
}
4554

46-
}
55+
private fun notify(e: Exception) {
56+
val message = trimWithEllipsis(e.message, 100)
57+
val causeMessage = KubernetesClientExceptionUtils.statusMessage(e.cause)
58+
Notification()
59+
.error(
60+
"Could not open diff",
61+
if (causeMessage == null) {
62+
message ?: ""
63+
} else if (message == null) {
64+
causeMessage
65+
} else {
66+
"$message: $causeMessage"
67+
}
68+
)
69+
}
70+
}

src/test/kotlin/com/redhat/devtools/intellij/kubernetes/editor/ResourceEditorTest.kt

+6-6
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import io.fabric8.kubernetes.api.model.PodBuilder
5050
import io.fabric8.kubernetes.client.KubernetesClient
5151
import io.fabric8.kubernetes.client.KubernetesClientException
5252
import io.fabric8.kubernetes.client.utils.Serialization
53+
import java.util.concurrent.CompletionException
5354
import org.assertj.core.api.Assertions.assertThat
5455
import org.jetbrains.yaml.YAMLFileType
5556
import org.junit.Before
@@ -563,7 +564,7 @@ class ResourceEditorTest {
563564
doReturn(JsonFileType.INSTANCE)
564565
.whenever(psiFile).fileType
565566
// when
566-
editor.diff()
567+
editor.diff().join()
567568
// then
568569
verify(serialize).invoke(any(), eq(JsonFileType.INSTANCE))
569570
}
@@ -577,23 +578,22 @@ class ResourceEditorTest {
577578
doReturn(YAMLFileType.YML)
578579
.whenever(psiFile).fileType
579580
// when
580-
editor.diff()
581+
editor.diff().join()
581582
// then
582583
verify(serialize).invoke(any(), eq(YAMLFileType.YML))
583584
}
584585

585-
@Test
586-
fun `#diff should NOT open diff if editor file type is null`() {
586+
@Test(expected = CompletionException::class)
587+
fun `#diff should throw if editor file type is null`() {
587588
// given
588589
givenResources(mapOf(GARGAMEL to NopEditorResourceState()))
589590
doReturn(GARGAMEL_YAML)
590591
.whenever(document).text
591592
doReturn(null)
592593
.whenever(psiFile).fileType
593594
// when
594-
editor.diff()
595+
editor.diff().join()
595596
// then
596-
verify(diff, never()).open(any(), any(), any())
597597
}
598598

599599
@Test

0 commit comments

Comments
 (0)