From b1bf728adfb2652f8aa6ed85554c78c599f50cf7 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 5 Nov 2024 17:07:32 +0100 Subject: [PATCH 1/4] [NETBEANS-7467] Fixing synchronization in TokenList.resetToIndex --- .../java/editor/base/semantic/TokenList.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/TokenList.java b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/TokenList.java index 41c7f75323db..3e592fd4ebb4 100644 --- a/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/TokenList.java +++ b/java/java.editor.base/src/org/netbeans/modules/java/editor/base/semantic/TokenList.java @@ -365,12 +365,23 @@ public int index() { } public void resetToIndex(int index) { - if (ts == null) { - return ; - } + doc.render(() -> { + if (cancel.get()) { + return ; + } + + if (ts == null) { + return ; + } + + if (!ts.isValid()) { + cancel.set(true); + return ; + } - ts.moveIndex(index); - ts.moveNext(); + ts.moveIndex(index); + ts.moveNext(); + }); } private static List> embeddedTokenSequences(TokenHierarchy th, int offset) { From 4fe26a784e921effd00b09f4a02c512e9bdef61f Mon Sep 17 00:00:00 2001 From: Jan Horvath Date: Thu, 31 Oct 2024 17:25:07 +0100 Subject: [PATCH 2/4] Validation before adding items into CloudAssets --- .../cloud/oracle/assets/CloudAssets.java | 15 ++++- .../oracle/assets/PropertiesGenerator.java | 1 + .../cloud/oracle/assets/Validator.java | 58 +++++++++++++++++++ .../oracle/compute/ComputeInstanceItem.java | 24 +++++++- 4 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Validator.java diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java index b8b149a5ef93..38e490be0fb9 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CloudAssets.java @@ -139,17 +139,28 @@ public static synchronized CloudAssets getDefault() { return instance; } - public synchronized void addItem(OCIItem newItem) { + public synchronized boolean addItem(OCIItem newItem) { Parameters.notNull("newItem cannot be null", newItem); long presentCount = items.stream() .filter(i -> i.getKey().getPath().equals(newItem.getKey().getPath())) .count(); if (newItem.maxInProject() > presentCount && isTenancyCompatible(newItem, true)) { + if (newItem instanceof Validator) { + Validator.Result result = ((Validator) newItem).validate(); + if (result.status == Validator.ValidationStatus.WARNING) { + showWarningMessage(result.message); + } + if (result.status == Validator.ValidationStatus.ERROR) { + showWarningMessage(result.message); + return false; + } + } items.add(newItem); newItem.addChangeListener(itemsListener); update(); storeAssets(); } + return true; } synchronized void removeItem(OCIItem item) { @@ -184,7 +195,7 @@ public synchronized boolean isTenancyCompatible(OCIItem toCheck) { } public synchronized boolean isTenancyCompatible(OCIItem toCheck, boolean showWarning) { - List itemsMissingInfo = new ArrayList(); + List itemsMissingInfo = new ArrayList<> (); for(OCIItem item: items) { if (item != null && item.getTenancyId() == null) { itemsMissingInfo.add(item); diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java index f5a21520695c..319d8214da0b 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/PropertiesGenerator.java @@ -139,6 +139,7 @@ public PropertiesGenerator(boolean local) { } if (vault != null) { bootstrap.put("oci.vault.config.enabled", "true"); // NOI18N + bootstrap.put("micronaut.config-client.enabled", "true"); // NOI18N bootstrap.put("oci.vault.vaults[0].ocid", vault.getKey().getValue()); //NOI18N bootstrap.put("oci.vault.vaults[0].compartment-ocid", vault.getCompartmentId()); //NOI18N } diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Validator.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Validator.java new file mode 100644 index 000000000000..03231342f21c --- /dev/null +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/Validator.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.netbeans.modules.cloud.oracle.assets; + +/** + * Validates if the implementing class is suitable for adding to {@link CloudAssets}. + * The validation result is represented by {@link Result}, which includes a {@link ValidationStatus} + * indicating the outcome of the validation. + * + *

The possible validation states are: + *

    + *
  • {@link ValidationStatus#OK} - Indicates that the item is suitable for adding to {@link CloudAssets} + * without any warnings or restrictions.
  • + *
  • {@link ValidationStatus#WARNING} - Indicates that the item may be added to {@link CloudAssets}, + * but with a warning message to notify the user of potential issues.
  • + *
  • {@link ValidationStatus#ERROR} - Indicates that the item cannot be added to {@link CloudAssets}. + * A warning message will be shown, and the addition process will be blocked.
  • + *
+ * + * @author Jan Horvath + */ +public interface Validator { + + enum ValidationStatus { + OK, WARNING, ERROR + }; + + public class Result { + + public final ValidationStatus status; + public final String message; + + public Result(ValidationStatus status, String message) { + this.status = status; + this.message = message; + } + + } + + public Result validate(); + +} diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/compute/ComputeInstanceItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/compute/ComputeInstanceItem.java index 8bf09cd44169..c0d471535377 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/compute/ComputeInstanceItem.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/compute/ComputeInstanceItem.java @@ -26,12 +26,19 @@ import org.netbeans.modules.cloud.oracle.items.OCID; import org.netbeans.modules.cloud.oracle.items.OCIItem; import org.openide.util.Exceptions; +import org.openide.util.NbBundle; +import org.netbeans.modules.cloud.oracle.assets.Validator; /** * * @author Jan Horvath */ -public final class ComputeInstanceItem extends OCIItem implements URLProvider { +@NbBundle.Messages({ + "SuggestAmpere=The Compute Instance has a different architecture than the local machine. Container images built on the local machine may not be compatible with this Compute Instance. Please consider creating a Compute Instance with an AmpereĀ® shape.", + "SuggestIntel=The Compute Instance has a different architecture than the local machine. Container images built on the local machine may not be compatible with this Compute Instance. Please consider creating a Compute Instance with an AMD or IntelĀ® shape." +}) +public final class ComputeInstanceItem extends OCIItem implements URLProvider, Validator { + private final String AARCH = "aarch64"; private String publicIp = null; private String processorDescription; private String username; @@ -88,4 +95,19 @@ public URL getURL() { } return null; } + + @Override + public Result validate() { + String osArch = System.getProperty("os.arch"); //NOI18N + String shapeDesc = getProcessorDescription(); + boolean os_arm = AARCH.equals(osArch); + boolean shape_arm = shapeDesc != null && shapeDesc.contains("Ampere"); //NOI18N + if (os_arm == shape_arm) { + return new Result(ValidationStatus.OK, null); + } else if (os_arm && !shape_arm) { + return new Result(ValidationStatus.WARNING, Bundle.SuggestAmpere()); + } + return new Result(ValidationStatus.WARNING, Bundle.SuggestIntel()); + } + } From 13a03d23ca3fe60a9e9c514c9b7091ea85b4e535 Mon Sep 17 00:00:00 2001 From: Jan Horvath Date: Wed, 6 Nov 2024 17:33:57 +0100 Subject: [PATCH 3/4] Improve how the docker image is executed in the oci compute instance --- .../oracle/actions/ConfigMapUploader.java | 12 +++-- .../oracle/assets/CreateConfigCommand.java | 4 +- .../developer/ContainerRepositoryItem.java | 21 +++++++- .../oracle/developer/ContainerTagItem.java | 21 +++++++- java/java.lsp.server/vscode/src/extension.ts | 48 ++++++++++++++++--- 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/ConfigMapUploader.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/ConfigMapUploader.java index d9e58d7a8d5a..5354503cbd76 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/ConfigMapUploader.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/actions/ConfigMapUploader.java @@ -23,6 +23,7 @@ import org.netbeans.api.project.ProjectInformation; import org.netbeans.api.project.ProjectUtils; import static org.netbeans.modules.cloud.oracle.NotificationUtils.showMessage; +import org.netbeans.modules.cloud.oracle.assets.CloudAssets; import org.netbeans.modules.cloud.oracle.assets.ConfigMapProvider; import org.netbeans.modules.cloud.oracle.assets.Steps; import org.netbeans.modules.cloud.oracle.compute.ClusterItem; @@ -40,22 +41,25 @@ * @author Dusan Petrovic */ @NbBundle.Messages({ - "SuggestRerun=The changes will take place only after restarting the application" + "SuggestRerun=The changes will take place only after restarting the application", + "ClusterNotPresent=Please add the OKE Cluster first" }) public class ConfigMapUploader { public static void uploadConfigMap(CompletableFuture future) { + ClusterItem cluster = CloudAssets.getDefault().getItem(ClusterItem.class); + if (cluster == null) { + showMessage(Bundle.ClusterNotPresent()); + return; + } Steps.NextStepProvider nsProvider = Steps.NextStepProvider.builder() .stepForClass(ProjectStep.class, (s) -> new TenancyStep()) - .stepForClass(TenancyStep.class, (s) -> new CompartmentStep()) - .stepForClass(CompartmentStep.class, (s) -> new SuggestedStep("Cluster")) .build(); Lookup lookup = Lookups.fixed(nsProvider); Steps.getDefault().executeMultistep(new ProjectStep(), lookup) .thenAccept(values -> { Project project = values.getValueForStep(ProjectStep.class); - ClusterItem cluster = (ClusterItem) values.getValueForStep(SuggestedStep.class); ProjectInformation projectInfo = ProjectUtils.getInformation(project); ConfigMapProvider configMapProvider = new ConfigMapProvider(projectInfo.getDisplayName(), cluster); configMapProvider.createConfigMap(); diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CreateConfigCommand.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CreateConfigCommand.java index 1bb01e12dd0c..4b0087d94f2a 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CreateConfigCommand.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/CreateConfigCommand.java @@ -40,7 +40,7 @@ public class CreateConfigCommand implements CommandProvider { private static final String COMMAND_UPLOAD_TO_CONFIGMAP_WITHIN_DEVOPS = "nbls.cloud.assets.configmap.devops.upload"; //NOI18N private static final String COMMAND_UPLOAD_TO_CONFIGMAP = "nbls.cloud.assets.configmap.upload"; //NOI18N - private static final Set COMMANDS = new HashSet<>(Arrays.asList( + private static final Set COMMANDS = new HashSet<>(Arrays.asList( COMMAND_CREATE_CONFIG, COMMAND_UPLOAD_TO_CONFIGMAP_WITHIN_DEVOPS, COMMAND_UPLOAD_TO_CONFIGMAP @@ -53,7 +53,7 @@ public Set getCommands() { @Override public CompletableFuture runCommand(String command, List arguments) { - CompletableFuture future = new CompletableFuture(); + CompletableFuture future = new CompletableFuture<>(); if (COMMAND_CREATE_CONFIG.equals(command)) { PropertiesGenerator propGen = new PropertiesGenerator(false); ApplicationPropertiesGenerator appPropGen = new ApplicationPropertiesGenerator(propGen); diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerRepositoryItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerRepositoryItem.java index 3d9cf7183530..df7c6754c215 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerRepositoryItem.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerRepositoryItem.java @@ -18,14 +18,20 @@ */ package org.netbeans.modules.cloud.oracle.developer; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import org.netbeans.modules.cloud.oracle.adm.URLProvider; import org.netbeans.modules.cloud.oracle.items.OCID; import org.netbeans.modules.cloud.oracle.items.OCIItem; +import org.openide.util.Exceptions; /** * * @author Jan Horvath */ -public final class ContainerRepositoryItem extends OCIItem { +public final class ContainerRepositoryItem extends OCIItem implements URLProvider { private Boolean isPublic; private Integer imageCount; @@ -65,5 +71,18 @@ public String getUrl() { public String getRegistry() { return String.format("%s.ocir.io", getRegionCode()); } + + @Override + public URL getURL() { + if (getKey().getValue() != null && getRegion() != null) { + try { + URI uri = new URI(String.format("https://cloud.oracle.com/compute/registry/containers?region=%s", getRegion())); + return uri.toURL(); + } catch (MalformedURLException | URISyntaxException ex) { + Exceptions.printStackTrace(ex); + } + } + return null; + } } diff --git a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerTagItem.java b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerTagItem.java index a0cf49e195a1..434c39fb203a 100644 --- a/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerTagItem.java +++ b/enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/developer/ContainerTagItem.java @@ -18,14 +18,20 @@ */ package org.netbeans.modules.cloud.oracle.developer; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import org.netbeans.modules.cloud.oracle.adm.URLProvider; import org.netbeans.modules.cloud.oracle.items.OCID; import org.netbeans.modules.cloud.oracle.items.OCIItem; +import org.openide.util.Exceptions; /** * * @author Jan Horvath */ -public final class ContainerTagItem extends OCIItem { +public final class ContainerTagItem extends OCIItem implements URLProvider { private String digest; private String version; @@ -61,5 +67,18 @@ public String getVersion() { } return version; } + + @Override + public URL getURL() { + if (getKey().getValue() != null && getRegion() != null) { + try { + URI uri = new URI(String.format("https://cloud.oracle.com/compute/registry/containers?region=%s", getRegion())); + return uri.toURL(); + } catch (MalformedURLException | URISyntaxException ex) { + Exceptions.printStackTrace(ex); + } + } + return null; + } } diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index b378f9c549a9..8db683de5091 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -1035,12 +1035,22 @@ function activateWithJDK(specifiedJDK: string | null, context: ExtensionContext, function runCommandInTerminal(command: string, name: string) { const isWindows = process.platform === 'win32'; + const shell = process.env.SHELL || '/bin/bash'; + const shellName = shell.split('/').pop(); + const isZsh = shellName === 'zsh'; + const defaultShell = isWindows ? process.env.ComSpec || 'cmd.exe' - : process.env.SHELL || '/bin/bash'; + : shell; + + const pauseCommand = isWindows + ? 'pause' + : 'echo "Press any key to close..."; ' + (isZsh + ? 'read -rs -k1' + : 'read -rsn1'); + + const commandWithPause = `${command} && ${pauseCommand}`; - const pauseCommand = 'echo "Press any key to close..."; node -e "process.stdin.setRawMode(true); process.stdin.resume(); process.stdin.on(\'data\', process.exit.bind(process, 0));"'; - const commandWithPause = `${command} 2>&1; ${pauseCommand}`; const terminal = vscode.window.createTerminal({ name: name, shellPath: defaultShell, @@ -1098,13 +1108,37 @@ async function runDockerSSH(username: string, host: string, dockerImage: string, micronautConfigFilesEnv += `${bootstrapProperties ? "," : ""}${applicationPropertiesContainerPath}`; } - let dockerPullCommand = ""; + let script = `#!/bin/sh\n`; + script += `set -e\n`; + script += `CONTAINER_ID_FILE="/home/${username}/.vscode.container.id"\n`; + script += `if [ -f "$CONTAINER_ID_FILE" ]; then\n`; + script += ` CONTAINER_ID=$(cat "$CONTAINER_ID_FILE")\n`; + script += ` if [ ! -z "$CONTAINER_ID" ] && docker ps -q --filter "id=$CONTAINER_ID" | grep -q .; then\n`; + script += ` echo "Stopping existing container with ID $CONTAINER_ID..."\n`; + script += ` docker stop "$CONTAINER_ID"\n`; + script += ` fi\n`; + script += ` rm -f "$CONTAINER_ID_FILE"\n`; + script += `fi\n`; + if (isRepositoryPrivate) { - dockerPullCommand = `cat ${bearerTokenRemotePath} | docker login --username=BEARER_TOKEN --password-stdin ${ocirServer} && `; + script += `cat ${bearerTokenRemotePath} | docker login --username=BEARER_TOKEN --password-stdin ${ocirServer} \n`; } - dockerPullCommand += `docker pull ${dockerImage} && `; + script += `docker pull ${dockerImage} \n`; - sshCommand += `ssh ${username}@${host} "${dockerPullCommand} docker run -p 8080:8080 ${mountVolume} -e MICRONAUT_CONFIG_FILES=${micronautConfigFilesEnv} -it ${dockerImage}"`; + script += `NEW_CONTAINER_ID=$(docker run -p 8080:8080 ${mountVolume} -e MICRONAUT_CONFIG_FILES=${micronautConfigFilesEnv} -d ${dockerImage})\n`; + + script += `if [ -n "$NEW_CONTAINER_ID" ]; then\n` + script += ` echo $NEW_CONTAINER_ID > $CONTAINER_ID_FILE\n` + script += `fi\n` + script += `docker logs -f "$NEW_CONTAINER_ID"\n` + + const tempDir = process.env.TEMP || process.env.TMP || '/tmp'; + const runContainerScript = path.join(tempDir, `run-container-${Date.now()}.sh`); + fs.writeFileSync(runContainerScript, script); + + sshCommand += `scp "${runContainerScript}" ${username}@${host}:run-container.sh && ` + + sshCommand += `ssh ${username}@${host} "chmod +x run-container.sh && ./run-container.sh" ` runCommandInTerminal(sshCommand, `Container: ${username}@${host}`) } From 206da8ef3cedde2740eedcfe55a6a14a3ed09196 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Sun, 10 Nov 2024 14:28:52 +0100 Subject: [PATCH 4/4] OutputWindow: text selection can start at index 0. --- .../src/org/netbeans/core/output2/ui/AbstractOutputPane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputPane.java b/platform/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputPane.java index 918e473ab39f..06b715d24e04 100644 --- a/platform/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputPane.java +++ b/platform/core.output2/src/org/netbeans/core/output2/ui/AbstractOutputPane.java @@ -198,7 +198,7 @@ public String getSelectedText() { int start = getSelectionStart(); int end = getSelectionEnd(); String str = null; - if (start > 0 && end > start) { + if (start >= 0 && end > start) { try { str = getDocument().getText(start, end - start); } catch (BadLocationException ex) {