diff --git a/build.gradle b/build.gradle index f8fa8ee77..e9b80164c 100644 --- a/build.gradle +++ b/build.gradle @@ -140,7 +140,7 @@ dependencies { 'io.fabric8:openshift-client:6.12.0', 'org.apache.commons:commons-compress:1.26.1', 'org.apache.commons:commons-exec:1.4.0', - 'com.redhat.devtools.intellij:intellij-common:1.9.5', + 'com.redhat.devtools.intellij:intellij-common:1.9.6-SNAPSHOT', 'io.jsonwebtoken:jjwt-impl:0.12.5', 'io.jsonwebtoken:jjwt-jackson:0.12.5', 'org.keycloak:keycloak-installed-adapter:24.0.3', diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java index 630d4a899..58ab0731b 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/HelmAction.java @@ -45,7 +45,7 @@ public void actionPerformed(AnActionEvent anActionEvent, TreePath path, Object s protected Helm getHelm(AnActionEvent anActionEvent) { try { - return ActionUtils.getApplicationRootNode(anActionEvent).getHelm(true).getNow(null); + return ActionUtils.getApplicationRootNode(anActionEvent).getHelm(true); } catch (Exception e) { LOGGER.warn("Could not get helm: " + e.getMessage(), e); return null; diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/OdoAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/OdoAction.java index e51169a26..77c5b53fe 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/OdoAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/OdoAction.java @@ -47,7 +47,7 @@ public void actionPerformed(AnActionEvent anActionEvent, TreePath path, Object s protected Odo getOdo(AnActionEvent anActionEvent) { try { - return ActionUtils.getApplicationRootNode(anActionEvent).getOdo().getNow(null); + return ActionUtils.getApplicationRootNode(anActionEvent).getOdo(); } catch(Exception e) { LOGGER.warn("Could not get odo: " + e.getMessage(), e); return null; diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java index c0013e33f..1cb4b6500 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/component/CreateComponentAction.java @@ -51,7 +51,7 @@ public static void execute(ParentableNode node) { if (node == null) { return; } - Odo odo = node.getRoot().getOdo().getNow(null); + Odo odo = node.getRoot().getOdo(); if (odo == null) { return; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/component/ShowLogComponentAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/component/ShowLogComponentAction.java index 2fba7eed9..934dfbdbc 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/component/ShowLogComponentAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/component/ShowLogComponentAction.java @@ -42,7 +42,7 @@ public boolean isVisible(Object selected) { boolean visible = super.isVisible(selected); if (visible) { ComponentNode componentNode = (ComponentNode) selected; - Odo odo = componentNode.getRoot().getOdo().getNow(null); + Odo odo = componentNode.getRoot().getOdo(); if (odo == null) { return false; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/helm/OpenHelmChartsAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/helm/OpenHelmChartsAction.java index 97cb2f471..cd8093903 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/helm/OpenHelmChartsAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/helm/OpenHelmChartsAction.java @@ -32,7 +32,7 @@ public void actionPerformedOnSelectedObject(AnActionEvent anActionEvent, Object return; } ApplicationsRootNode rootNode = parentableNode.getRoot(); - Odo odo = rootNode.getOdo().getNow(null); + Odo odo = rootNode.getOdo(); if (odo == null) { return; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java index 26ce54e9d..330b9d2ba 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/ChangeActiveProjectAction.java @@ -46,7 +46,7 @@ public static void execute(ParentableNode node) { return; } ApplicationsRootNode rootNode = node.getRoot(); - Odo odo = rootNode.getOdo().getNow(null); + Odo odo = rootNode.getOdo(); if (odo == null) { return; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java index 0069b3ee2..76db91215 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/actions/project/CreateProjectAction.java @@ -40,7 +40,7 @@ public class CreateProjectAction extends LoggedInClusterAction { public static void execute(ApplicationsRootNode rootNode) { - Odo odo = rootNode.getOdo().getNow(null); + Odo odo = rootNode.getOdo(); if (odo == null) { return; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java index 04dd449fd..1e739041a 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsRootNode.java @@ -23,9 +23,18 @@ import com.redhat.devtools.intellij.common.utils.ConfigWatcher; import com.redhat.devtools.intellij.common.utils.ExecHelper; import io.fabric8.kubernetes.api.model.Config; +import java.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import org.jboss.tools.intellij.openshift.actions.NotificationUtils; import org.jboss.tools.intellij.openshift.utils.ProjectUtils; import org.jboss.tools.intellij.openshift.utils.ToolFactory; +import org.jboss.tools.intellij.openshift.utils.ToolFactory.Tool; import org.jboss.tools.intellij.openshift.utils.helm.Helm; import org.jboss.tools.intellij.openshift.utils.odo.ComponentDescriptor; import org.jboss.tools.intellij.openshift.utils.odo.Odo; @@ -34,15 +43,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiConsumer; - public class ApplicationsRootNode implements ModuleListener, ConfigWatcher.Listener, ProcessingNode, StructureAwareNode, ParentableNode, Disposable { @@ -51,8 +51,8 @@ public class ApplicationsRootNode private final ApplicationsTreeStructure structure; private final ProcessingNodeImpl processingNode = new ProcessingNodeImpl(); private final Map components = new HashMap<>(); - private CompletableFuture odoFuture; - private CompletableFuture helmFuture; + private CompletableFuture> odoFuture; + private CompletableFuture> helmFuture; private boolean logged; private Config config; private final OdoProcessHelper processHelper; @@ -81,39 +81,58 @@ public void setLogged(boolean logged) { this.logged = logged; } - private CompletableFuture getOdo(BiConsumer whenComplete) { + private CompletableFuture> getOdoTool(BiConsumer, Throwable> whenComplete) { if (odoFuture == null) { this.odoFuture = ToolFactory.getInstance() .createOdo(project) - .thenApply(odo -> (Odo) new ApplicationRootNodeOdo(odo, this, processHelper)) - .whenComplete((odo, err) -> loadProjectModel(odo, project)) + .whenComplete((tool, err) -> new ApplicationRootNodeOdo(tool.get(), this, processHelper)) + .whenComplete((tool, err) -> loadProjectModel(tool.get(), project)) .whenComplete(whenComplete); } return odoFuture; } - public CompletableFuture getOdo() { - return getOdo((odo, err) -> structure.fireModified(this)); + public CompletableFuture> getOdoTool() { + return getOdoTool((Tool tool, Throwable err) -> { + if (tool.isDownloaded()) { + structure.fireModified(this); + } + }); + } + + public Odo getOdo() { + Tool tool = getOdoTool().getNow(null); + if (tool == null) { + return null; + } + return tool.get(); } public void resetOdo() { this.odoFuture = null; } - public CompletableFuture getHelm(boolean notify) { + public CompletableFuture> getHelmTool(boolean notify) { if (helmFuture == null) { this.helmFuture = ToolFactory.getInstance() .createHelm(project) - .whenComplete((odo, err) -> { - if (notify) { + .whenComplete((tool, err) -> { + if (notify && tool.isDownloaded()) { structure.fireModified(this); } - } - ); + }); } return helmFuture; } + public Helm getHelm(boolean notify) { + Tool tool = getHelmTool(notify).getNow(null); + if (tool == null) { + return null; + } + return tool.get(); + } + public Project getProject() { return project; } @@ -141,7 +160,7 @@ protected void loadProjectModel(Odo odo, Project project) { @Override public void moduleAdded(@NotNull Project project, @NotNull Module module) { - addContext(getOdo().getNow(null), ProjectUtils.getModuleRoot(module)); + addContext(getOdo(), ProjectUtils.getModuleRoot(module)); } @Override @@ -159,10 +178,11 @@ private void addContextToSettings(String path, ComponentDescriptor descriptor) { } private void migrateOdo(ComponentDescriptor descriptor) { - getOdo() - .thenAccept(odo -> { - if (odo != null) { - odo.migrateComponent(descriptor.getName()); + getOdoTool() + .thenAccept(tool -> { + if (tool != null + && tool.get() != null) { + tool.get().migrateComponent(descriptor.getName()); } }) .thenRun(() -> @@ -192,7 +212,7 @@ private void addContext(Odo odo, VirtualFile modulePathFile) { public void addContext(String modulePath) { addContext( - getOdo().getNow(null), + getOdo(), LocalFileSystem.getInstance().refreshAndFindFileByPath(modulePath)); } @@ -228,7 +248,7 @@ public void onUpdate(ConfigWatcher source, Config config) { public synchronized void refresh() { resetOdo(); - getOdo((odo, err) -> structure.fireModified(ApplicationsRootNode.this)); + getOdoTool((odo, err) -> structure.fireModified(ApplicationsRootNode.this)); } @Override diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java index 9c41d9d03..d83bc7be9 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ApplicationsTreeStructure.java @@ -109,7 +109,7 @@ public Object getApplicationsRoot() { @NotNull private Object[] createComponentChildren(ComponentNode componentNode) { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return new Object[]{new MessageNode<>(root, componentNode, "Could not get components")}; } @@ -123,7 +123,7 @@ private Object[] createComponentChildren(ComponentNode componentNode) { @NotNull private Object[] createNamespaceChildren(@NotNull NamespaceNode namespaceNode) { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return new MessageNode[]{new MessageNode<>(root, namespaceNode, "Could not get project children")}; } @@ -143,7 +143,7 @@ private Object[] createNamespaceChildren(@NotNull NamespaceNode namespaceNode) { private Object getCurrentNamespace(ApplicationsRootNode element) { Object node; try { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return new Object[]{new MessageNode<>(element, element, "Could not get current namespace")}; } @@ -167,7 +167,7 @@ private Object getCurrentNamespace(ApplicationsRootNode element) { } private Object[] createHelmRepositoriesChildren(HelmRepositoriesNode parent) { - Helm helm = root.getHelm(true).getNow(null); + Helm helm = root.getHelm(true); if (helm == null) { return new Object[] { new MessageNode<>(root, parent, "Could not list repositories: Helm binary missing.") }; } @@ -226,7 +226,7 @@ private List> getServices(NamespaceNode namespaceNode, Odo odo) { } private List> getHelmReleases(NamespaceNode namespaceNode) { - Helm helm = namespaceNode.getRoot().getHelm(true).getNow(null); + Helm helm = namespaceNode.getRoot().getHelm(true); if (helm == null) { return List.of(new MessageNode<>(root, namespaceNode, "Could not get chart releases")); } @@ -248,7 +248,7 @@ private List> load(Callable>> callable, NamespaceNo private List getURLs(ComponentNode element) { List results = new ArrayList<>(); - Odo odo = element.getRoot().getOdo().getNow(null); + Odo odo = element.getRoot().getOdo(); if (odo == null) { return Collections.emptyList(); } @@ -277,7 +277,7 @@ private List getBindings(ComponentNode element, @NotNull Odo odo) { } private Object[] getRegistries(ApplicationsRootNode root) { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return new Object[]{new MessageNode<>(root, root, "Could not get registries")}; } @@ -293,7 +293,7 @@ private Object[] getRegistries(ApplicationsRootNode root) { } private Object[] getRegistryComponentTypes(DevfileRegistryNode registryNode) { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return new Object[]{new MessageNode<>(root, registryNode, "Could not get registry component types")}; } @@ -308,7 +308,7 @@ private Object[] getRegistryComponentTypes(DevfileRegistryNode registryNode) { } private Object[] getRegistryComponentTypeStarters(DevfileRegistryComponentTypeNode componentTypeNode) { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return new Object[]{new MessageNode<>(root, componentTypeNode, "Could not get registry component starters")}; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ChangeActiveProjectLinkNode.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ChangeActiveProjectLinkNode.java index 1dd3d24e0..3b4b4d198 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ChangeActiveProjectLinkNode.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/ChangeActiveProjectLinkNode.java @@ -26,7 +26,7 @@ public void execute() { } private static String getLabel(ApplicationsRootNode root) { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); String label = "Missing %s, choose or create a different one"; if (odo == null) { return String.format(label, "project/namespace"); diff --git a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java index 064896931..8db02aaae 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/tree/application/DescriptorFactory.java @@ -55,7 +55,7 @@ public class DescriptorFactory { root, () -> { try { - Odo odo = root.getOdo().getNow(null); + Odo odo = root.getOdo(); if (odo == null) { return "Loading..."; } diff --git a/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java b/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java index cebb98224..8dd687a5f 100644 --- a/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java +++ b/src/main/java/org/jboss/tools/intellij/openshift/utils/ToolFactory.java @@ -12,17 +12,16 @@ import com.intellij.openapi.project.Project; import com.redhat.devtools.intellij.common.utils.DownloadHelper; +import java.net.URL; +import java.util.concurrent.CompletableFuture; +import java.util.function.BiFunction; import org.jboss.tools.intellij.openshift.utils.helm.Helm; import org.jboss.tools.intellij.openshift.utils.helm.HelmCli; import org.jboss.tools.intellij.openshift.utils.odo.Odo; import org.jboss.tools.intellij.openshift.utils.odo.OdoCli; -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; - public class ToolFactory { - private static final String TOOLS_JSON = "/tools.json"; private static ToolFactory INSTANCE; @@ -34,41 +33,60 @@ public static ToolFactory getInstance() { return INSTANCE; } - private final Tool odo = new Tool<>("odo", OdoCli::new); - private final Tool helm = new Tool<>("helm", (project, command) -> new HelmCli(command)); + private final Factory odo = new Factory<>("odo", OdoCli::new); + private final Factory helm = new Factory<>("helm", (project, command) -> new HelmCli(command)); private ToolFactory() { } - public CompletableFuture createOdo(Project project) { + public CompletableFuture> createOdo(Project project) { return odo.create(project); } - public CompletableFuture createHelm(Project project) { + public CompletableFuture> createHelm(Project project) { return helm.create(project); } - private static class Tool { + public static class Tool { + private final T tool; + private final boolean isDownloaded; + + private Tool(T tool, boolean isDownloaded) { + this.tool = tool; + this.isDownloaded = isDownloaded; + } + + public T get() { + return tool; + } + + public boolean isDownloaded() { + return isDownloaded; + } + } + + private static class Factory { private final String name; + private final URL url = ToolFactory.class.getResource(TOOLS_JSON); private final BiFunction toolFactory; - private Tool(String name, BiFunction toolFactory) { + private Factory(String name, BiFunction toolFactory) { this.name = name; this.toolFactory = toolFactory; } - private CompletableFuture create(Project project) { + private CompletableFuture> create(Project project) { return create(name, toolFactory, project); } - private CompletableFuture create(String name, BiFunction toolFactory, Project project) { + private CompletableFuture> create(String name, BiFunction toolFactory, Project project) { return DownloadHelper.getInstance() - .downloadIfRequiredAsync(name, ToolFactory.class.getResource(TOOLS_JSON)) - .thenApply(command -> { - if (command != null) { - return toolFactory.apply(project, command); + .downloadIfRequiredAsync(name, url) + .thenApply(toolInstance -> { + if (toolInstance != null) { + return new Tool<>(toolFactory.apply(project, toolInstance.getCommand()), toolInstance.isDownloaded()); } else { return null; } diff --git a/src/test/java/org/jboss/tools/intellij/openshift/actions/ActionTest.java b/src/test/java/org/jboss/tools/intellij/openshift/actions/ActionTest.java index 15c89edba..7032f9f6d 100644 --- a/src/test/java/org/jboss/tools/intellij/openshift/actions/ActionTest.java +++ b/src/test/java/org/jboss/tools/intellij/openshift/actions/ActionTest.java @@ -16,6 +16,9 @@ import com.intellij.openapi.actionSystem.Presentation; import com.intellij.testFramework.fixtures.BasePlatformTestCase; import com.intellij.ui.treeStructure.Tree; +import java.util.concurrent.CompletableFuture; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; import org.jboss.tools.intellij.openshift.Constants; import org.jboss.tools.intellij.openshift.tree.application.ApplicationsRootNode; import org.jboss.tools.intellij.openshift.tree.application.ApplicationsTreeStructure; @@ -26,6 +29,7 @@ import org.jboss.tools.intellij.openshift.tree.application.NamespaceNode; import org.jboss.tools.intellij.openshift.tree.application.ServiceNode; import org.jboss.tools.intellij.openshift.tree.application.URLNode; +import org.jboss.tools.intellij.openshift.utils.ToolFactory; import org.jboss.tools.intellij.openshift.utils.odo.Component; import org.jboss.tools.intellij.openshift.utils.odo.ComponentFeature; import org.jboss.tools.intellij.openshift.utils.odo.ComponentFeatures; @@ -35,10 +39,6 @@ import org.jboss.tools.intellij.openshift.utils.odo.URL; import org.jetbrains.annotations.NotNull; -import javax.swing.tree.TreePath; -import javax.swing.tree.TreeSelectionModel; -import java.util.concurrent.CompletableFuture; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -60,7 +60,7 @@ public AnActionEvent createEvent(Object selected) { if (selected instanceof ApplicationsRootNode) { when(structure.getApplicationsRoot()).thenReturn(selected); } else { - CompletableFuture odoFuture = createOdoFuture(false); + CompletableFuture> odoFuture = createOdoFuture(false); ApplicationsRootNode applicationRootNode = createApplicationRootNode(odoFuture); when(structure.getApplicationsRoot()).thenReturn(applicationRootNode); } @@ -78,7 +78,7 @@ public void testActionOnLoggedInKubeCluster() { testActionOnLoggedInCluster(createOdoFuture(false)); } - private void testActionOnLoggedInCluster(CompletableFuture odoFuture) { + private void testActionOnLoggedInCluster(CompletableFuture> odoFuture) { ApplicationsRootNode applicationsRootNode = createApplicationRootNode(odoFuture); AnActionEvent event = createEvent(applicationsRootNode); AnAction action = getAction(); @@ -104,20 +104,23 @@ protected void verifyLoggedOutCluster(boolean visible) { } @NotNull - protected static ApplicationsRootNode createApplicationRootNode(CompletableFuture odoFuture) { + protected static ApplicationsRootNode createApplicationRootNode(CompletableFuture> odoFuture) { ApplicationsRootNode applicationsRootNode = mock(ApplicationsRootNode.class); when(applicationsRootNode.isLogged()).thenReturn(true); when(applicationsRootNode.getRoot()).thenReturn(applicationsRootNode); - when(applicationsRootNode.getOdo()).thenReturn(odoFuture); + when(applicationsRootNode.getOdoTool()).thenReturn(odoFuture); return applicationsRootNode; } @NotNull - protected static CompletableFuture createOdoFuture(boolean isOpenShift) { + protected static CompletableFuture> createOdoFuture(boolean isOpenShift) { Odo odo = mock(Odo.class); when(odo.isOpenShift()).thenReturn(isOpenShift); - CompletableFuture odoFuture = mock(CompletableFuture.class); - when(odoFuture.getNow(any())).thenReturn(odo); + ToolFactory.Tool tool = mock(ToolFactory.Tool.class); + when(tool.get()) + .thenReturn(odo); + CompletableFuture> odoFuture = mock(CompletableFuture.class); + when(odoFuture.getNow(any())).thenReturn(tool); return odoFuture; }