diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 00767e2c7b5c..732bb4a5817e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -593,6 +593,9 @@ jobs: - name: ide/docker.api run: ant $OPTS -f ide/docker.api test + - name: ide/dlight.nativeexecution + run: ant $OPTS -f ide/dlight.nativeexecution test + - name: ide/docker.ui run: ant $OPTS -f ide/docker.ui test diff --git a/ide/dlight.nativeexecution/nbproject/project.properties b/ide/dlight.nativeexecution/nbproject/project.properties index c1201be5879e..8b5997bdd373 100644 --- a/ide/dlight.nativeexecution/nbproject/project.properties +++ b/ide/dlight.nativeexecution/nbproject/project.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. is.autoload=true -javac.release=11 +javac.release=17 javac.compilerargs=-Xlint -Xlint:-serial javadoc.arch=${basedir}/arch.xml project.license=apache20-asf diff --git a/ide/dlight.nativeexecution/nbproject/project.xml b/ide/dlight.nativeexecution/nbproject/project.xml index db4cb912f50f..faf986b514a9 100644 --- a/ide/dlight.nativeexecution/nbproject/project.xml +++ b/ide/dlight.nativeexecution/nbproject/project.xml @@ -68,6 +68,15 @@ 2.1 + + org.netbeans.libs.jna.platform + + + + 2 + 2.22 + + org.netbeans.modules.extexecution diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/NbNativeProcess.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/NbNativeProcess.java index 3cc55a2b04bc..93a4f77ff9ec 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/NbNativeProcess.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/NbNativeProcess.java @@ -18,6 +18,7 @@ */ package org.netbeans.modules.nativeexecution; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -31,6 +32,7 @@ import org.netbeans.modules.nativeexecution.api.util.MacroMap; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils.ExitStatus; +import org.netbeans.modules.nativeexecution.api.util.Shell; import org.netbeans.modules.nativeexecution.api.util.Signal; import org.netbeans.modules.nativeexecution.api.util.UnbufferSupport; import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; @@ -51,11 +53,14 @@ public abstract class NbNativeProcess extends AbstractNativeProcess { private final String nbStartPath; private volatile ProcessStatusEx statusEx; + @SuppressWarnings("this-escape") public NbNativeProcess(final NativeProcessInfo info) { super(new NativeProcessInfo(info, true)); String _nbStartPath = null; try { - _nbStartPath = NbStartUtility.getInstance().getPath(getExecutionEnvironment()); + _nbStartPath = NbStartUtility + .getInstance(getExecutionEnvironment().isLocal()) + .getPath(getExecutionEnvironment()); } catch (IOException ex) { } finally { nbStartPath = _nbStartPath; @@ -71,12 +76,27 @@ protected final void create() throws Throwable { private List getCommand() { List command = new ArrayList<>(); - command.add(nbStartPath); + File wslPath = new File(System.getenv("windir"), "system32/wsl.exe"); + Shell activeShell = null; + if(isWindows()) { + activeShell = WindowsSupport.getInstance().getActiveShell(); + } + if (activeShell != null && activeShell.type == Shell.ShellType.WSL) { + command.add(wslPath.getAbsolutePath()); + command.add(WindowsSupport.getInstance().convertToWSL(nbStartPath)); + } else { + command.add(nbStartPath); + } + String wdir = info.getWorkingDirectory(true); if (wdir != null && !wdir.isEmpty()) { command.add("--dir"); // NOI18N - command.add(fixForWindows(wdir)); + if (activeShell != null && activeShell.type == Shell.ShellType.WSL) { + command.add(WindowsSupport.getInstance().convertToWSL(wdir)); + } else { + command.add(fixForWindows(wdir)); + } } if (!info.isPtyMode()) { @@ -127,13 +147,26 @@ private List getCommand() { Map userDefinedMap = userEnv.getUserDefinedMap(); for (Map.Entry entry : userDefinedMap.entrySet()) { - if (isWindows() && entry.getKey().equalsIgnoreCase("PATH")) { // NOI18N + if (isWindows() && entry.getKey().equalsIgnoreCase("PATH") && WindowsSupport.getInstance().getActiveShell().type != Shell.ShellType.WSL) { // NOI18N command.add("--env"); // NOI18N command.add(entry.getKey() + "=" + WindowsSupport.getInstance().convertToAllShellPaths(entry.getValue())); // NOI18N continue; } command.add("--env"); // NOI18N - command.add(entry.getKey() + "=" + entry.getValue()); // NOI18N + String setCall = entry.getKey() + "=" + entry.getValue(); + if (isWindows() && WindowsSupport.getInstance().getActiveShell().type == Shell.ShellType.WSL) { + // the environment must be escaped so that it is passed + // to the inner shell + command.add( + "\"" + + setCall + .replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("$", "\\$") + + "\""); // NOI18N + } else { + command.add(setCall); + } } } @@ -150,9 +183,7 @@ private List getCommand() { } private void readProcessInfo(InputStream fromProcessStream) throws IOException { - String line; - - while (!(line = readLine(fromProcessStream).trim()).isEmpty()) { + for(String line = readLine(fromProcessStream); ! line.isBlank(); line = readLine(fromProcessStream)) { addProcessInfo(line); } @@ -160,13 +191,13 @@ private void readProcessInfo(InputStream fromProcessStream) throws IOException { if (pidProperty == null) { InputStream error = getErrorStream(); - while (!(line = readLine(error).trim()).isEmpty()) { + for(String line = readLine(error); ! line.isBlank(); line = readLine(error)) { LOG.info(line); } throw new InternalError("Failed to get process PID"); // NOI18N } - setPID(Integer.parseInt(pidProperty)); // NOI18N + setPID(Integer.parseInt(pidProperty)); // NOI18N } @Override @@ -240,7 +271,11 @@ protected boolean isWindows() { } protected String fixForWindows(String path) { - return isWindows() ? WindowsSupport.getInstance().convertToCygwinPath(path) : path; + if(isWindows() && WindowsSupport.getInstance().getActiveShell().type == Shell.ShellType.CYGWIN) { + return WindowsSupport.getInstance().convertToCygwinPath(path); + } else { + return path; + } } private boolean destroyed() { diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/PtyNativeProcess.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/PtyNativeProcess.java index 2f249996047b..5b125c67e20f 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/PtyNativeProcess.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/PtyNativeProcess.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -50,6 +49,7 @@ public PtyNativeProcess(final NativeProcessInfo info) { } @Override + @SuppressWarnings({"deprecation", "AssignmentToForLoopParameter"}) protected void create() throws Throwable { ExecutionEnvironment env = info.getExecutionEnvironment(); Pty pty = info.getPty(); @@ -116,7 +116,7 @@ protected void create() throws Throwable { info.setCommandLine(null); final String path = PtyUtility.getInstance().getPath(env); info.setExecutable(path); - info.setArguments(newArgs.toArray(new String[0])); + info.setArguments(newArgs.toArray(String[]::new)); // no need to preload unbuffer in case of running in internal terminal info.setUnbuffer(false); @@ -145,9 +145,8 @@ protected void create() throws Throwable { String pidLine = null; String ttyLine = null; - String line; - while ((line = readLine(inputStream)) != null) { + for(String line = readLine(inputStream); line != null; line = readLine(inputStream)) { line = line.trim(); if (line.isEmpty()) { break; diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessBuilder.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessBuilder.java index ff06c3d58310..7e479d7e9705 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessBuilder.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessBuilder.java @@ -123,7 +123,7 @@ public NativeProcessBuilder setCommandLine(String commandLine) { } /** - * Register passed NativeProcess.Listener. + * Register passed {@code NativeProcess.Listener}. * * @param listener NativeProcess.Listener to be registered to receive * process's state change events. @@ -170,11 +170,8 @@ public NativeProcess call() throws IOException { throw new UserQuestionException("No connection to " + execEnv.getDisplayName()) {// NOI18N @Override public void confirmed() throws IOException { - RequestProcessor.getDefault().post(new Runnable() { - @Override - public void run() { - ConnectionManager.getInstance().connect(execEnv); - } + RequestProcessor.getDefault().post(() -> { + ConnectionManager.getInstance().connect(execEnv); }); } @@ -185,7 +182,7 @@ public String getLocalizedMessage() { }; } - if (externalTerminal == null && NbStartUtility.getInstance().isSupported(info.getExecutionEnvironment())) { + if (externalTerminal == null && NbStartUtility.getInstance(info.getExecutionEnvironment().isLocal()).isSupported(info.getExecutionEnvironment())) { if (info.getExecutionEnvironment().isLocal()) { process = new NbLocalNativeProcess(info); } else { @@ -199,21 +196,17 @@ public String getLocalizedMessage() { process = new RemoteNativeProcess(info); } else { if (externalTerminal != null) { - boolean canProceed = true; boolean available = externalTerminal.isAvailable(info.getExecutionEnvironment()); if (!available) { if (Boolean.getBoolean("nativeexecution.mode.unittest") || "true".equals(System.getProperty("cnd.command.line.utility"))) { // NOI18N System.err.println(loc("NativeProcessBuilder.processCreation.NoTermianl.text")); } else { - NativeExecutionUserNotification.getDefault().notify(loc("NativeProcessBuilder.processCreation.NoTermianl.text"), // NOI18N - NativeExecutionUserNotification.Descriptor.WARNING); -// DialogDisplayer.getDefault().notify( -// new NotifyDescriptor.Message(loc("NativeProcessBuilder.processCreation.NoTermianl.text"), // NOI18N -// NotifyDescriptor.WARNING_MESSAGE)); + NativeExecutionUserNotification.getDefault().notify(loc("NativeProcessBuilder.processCreation.NoTermianl.text"), // NOI18N + NativeExecutionUserNotification.Descriptor.WARNING); } - canProceed = false; } else { + boolean canProceed = true; if (Utilities.isWindows()) { Shell shell = WindowsSupport.getInstance().getActiveShell(); if (shell == null) { @@ -222,9 +215,6 @@ public String getLocalizedMessage() { } else { NativeExecutionUserNotification.getDefault().notify(loc("NativeProcessBuilder.processCreation.NoShell.text"), // NOI18N NativeExecutionUserNotification.Descriptor.WARNING); -// DialogDisplayer.getDefault().notify( -// new NotifyDescriptor.Message(loc("NativeProcessBuilder.processCreation.NoShell.text"), // NOI18N -// NotifyDescriptor.WARNING_MESSAGE)); } canProceed = false; } else { diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessExecutionService.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessExecutionService.java index 4688196500e5..de62c9034d19 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessExecutionService.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/NativeProcessExecutionService.java @@ -34,6 +34,7 @@ * This is a very light-weigth version of ExecutionService from org.netbeans.api.extexecution * @author ak119685 */ +@SuppressWarnings("deprecation") // org.netbeans.api.extexecution.input.LineProcessor is API public final class NativeProcessExecutionService { private final ExecutionTask task; @@ -79,6 +80,7 @@ public ExecutionTask(NativeProcessBuilder npb, LineProcessor outProcessor, LineP this.descr = descr; } + @Override public synchronized Integer call() throws Exception { if (process != null) { throw new IllegalThreadStateException("Already started!"); // NOI18N @@ -86,10 +88,6 @@ public synchronized Integer call() throws Exception { int result = -1; - InputStream is = null; - BufferedReader br = null; - Future errorProcessingDone = null; - try { if (outProcessor != null) { outProcessor.reset(); @@ -101,32 +99,26 @@ public synchronized Integer call() throws Exception { process = npb.call(); - errorProcessingDone = NativeTaskExecutorService.submit(new Callable() { - @Override - public Boolean call() throws Exception { - InputStream is = process.getErrorStream(); - BufferedReader br = new BufferedReader(new InputStreamReader(is)); - String line; - while ((line = br.readLine()) != null) { - if (errProcessor != null) { - errProcessor.processLine(line); - } else { - ProcessUtils.logError(Level.FINE, log, process); - } + Future errorProcessingDone = NativeTaskExecutorService.submit(() -> { + InputStream is = process.getErrorStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + for (String line = br.readLine(); line != null; line = br.readLine()) { + if (errProcessor != null) { + errProcessor.processLine(line); + } else { + ProcessUtils.logError(Level.FINE, log, process); } - return true; } + return true; }, "reading process err"); //NOI18N - is = process.getInputStream(); + InputStream is = process.getInputStream(); if (is != null) { // LATER: shouldn't it use ProcessUtils.getReader? - br = new BufferedReader(new InputStreamReader(is)); - String line; - try { - while ((line = br.readLine()) != null) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) { + for (String line = br.readLine(); line != null; line = br.readLine()) { if (outProcessor != null) { outProcessor.processLine(line); } @@ -136,6 +128,7 @@ public Boolean call() throws Exception { Thread.interrupted(); } } + errorProcessingDone.get(); // just to wait until error processing is done } catch (Throwable th) { log.log(Level.FINE, descr, th.getMessage()); @@ -148,10 +141,6 @@ public Boolean call() throws Exception { log.log(Level.FINE, descr, th.getMessage()); } - if (br != null) { - br.close(); - } - if (process != null) { try { result = process.exitValue(); diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/execution/NativeExecutionService.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/execution/NativeExecutionService.java index ff3780db8273..cb4db214fb9f 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/execution/NativeExecutionService.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/execution/NativeExecutionService.java @@ -137,7 +137,7 @@ private Future runTerm() { // Allows user to use his favorite one. processBuilder.getEnvironment().put("TERM", termType); // NOI18N } else { - processBuilder.getEnvironment().put("TERM", "xterm" /*IOEmulation.getEmulation(descriptor.inputOutput)*/); // NOI18N + processBuilder.getEnvironment().put("TERM", "xterm-256color" /*IOEmulation.getEmulation(descriptor.inputOutput)*/); // NOI18N } } else { processBuilder.getEnvironment().put("TERM", "dumb"); // NOI18N diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/pty/PtySupport.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/pty/PtySupport.java index 8848070d7fd7..ffb591f34889 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/pty/PtySupport.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/pty/PtySupport.java @@ -32,7 +32,6 @@ import org.netbeans.modules.nativeexecution.pty.IOConnector; import org.netbeans.modules.nativeexecution.pty.PtyAllocator; import org.netbeans.modules.nativeexecution.pty.SttySupport; -import org.netbeans.modules.nativeexecution.support.Logger; import org.openide.util.Exceptions; import org.openide.windows.InputOutput; @@ -43,8 +42,6 @@ */ public final class PtySupport { - private static final java.util.logging.Logger log = Logger.getInstance(); - private PtySupport() { } @@ -53,12 +50,12 @@ private PtySupport() { * (if any). * * @param process - process to get pty of - * @return Pty that is currently associated with the process or null + * @return Pty that is currently associated with the process or {@code null} * if ptocess was started in non-pty mode. */ public static String getTTY(NativeProcess process) { - if (process instanceof ExProcessInfoProvider) { - return ((ExProcessInfoProvider) process).getTTY(); + if (process instanceof ExProcessInfoProvider exProcessInfoProvider) { + return exProcessInfoProvider.getTTY(); } return null; @@ -66,37 +63,38 @@ public static String getTTY(NativeProcess process) { /** * Connects process' IO streams with the specified InputOutput. - * - * @param io - InputOutput to connect process' IO with + * + * @param io - {@code InputOutput} to connect process' IO with * @param process - the process which should be connected with the io * - * @return true if operation was successfull. false otherwise. + * @return {@code true} if operation was successfull. {@code false} otherwise. */ public static boolean connect(InputOutput io, NativeProcess process) { return IOConnector.getInstance().connect(io, process); } - + /** * Connects process' IO streams with the specified InputOutput. - * - * @param io - InputOutput to connect process' IO with - * @param process - the process which should be connected with the io * - * @return true if operation was successfull. false otherwise. + * @param io {@link InputOutput} to connect process' IO with + * @param process the process which should be connected with the io + * @param postConnectRunnabel the task to be executed *after* the connection is established + * + * @return {@code true} if operation was successfull. {@code false} otherwise. */ public static boolean connect(InputOutput io, NativeProcess process, Runnable postConnectRunnabel) { return IOConnector.getInstance().connect(io, process, postConnectRunnabel); - } - + } + /** - * Connects pty's IO streams (master side) with the specified InputOutput. + * Connects pty's IO streams (master side) with the specified {@link InputOutput}. * So that IO of the process that will do input/output to the specified pty' - * slave will go to the specified InputOutput. + * slave will go to the specified {@link InputOutput}. * - * @param io - InputOutput to connect pty's IO with - * @param pty - the pty to connect InputOutput with + * @param io {@link InputOutput} to connect pty's IO with + * @param pty the pty to connect InputOutput with * - * @return true if operation was successfull. false otherwise. + * @return {@code true} if operation was successfull. {@code false} otherwise. */ public static boolean connect(InputOutput io, Pty pty) { return IOConnector.getInstance().connect(io, pty); @@ -104,8 +102,9 @@ public static boolean connect(InputOutput io, Pty pty) { /** * Allocates a new 'unconnected' pty - * @param env - environmant in which a pty should be allocated - * @return newly allocated pty or null if allocation failed + * @param env environmant in which a pty should be allocated + * @return newly allocated pty or {@code null} if allocation failed + * @throws java.io.IOException */ public static Pty allocate(ExecutionEnvironment env) throws IOException { if (!ConnectionManager.getInstance().isConnectedTo(env)) { @@ -124,8 +123,8 @@ public static void deallocate(Pty pty) throws IOException { * @param env - environmant in which a tty is used * @param tty - tty name */ - public static void disableEcho(ExecutionEnvironment exEnv, String tty) { - SttySupport.apply(exEnv, tty, "-echo"); //NOI18N + public static void disableEcho(ExecutionEnvironment env, String tty) { + SttySupport.apply(env, tty, "-echo"); //NOI18N } /** @@ -139,6 +138,9 @@ public static void disableEcho(ExecutionEnvironment exEnv, String tty) { * * There is an option in pty utility - --set-erase-key that could be used to * achieve needed effect. + * + * @param exEnv + * @param tty */ @Deprecated public static void setBackspaceAsEraseChar(ExecutionEnvironment exEnv, String tty) { @@ -154,28 +156,34 @@ public static boolean isSupportedFor(ExecutionEnvironment executionEnvironment) HostInfo hostInfo = HostInfoUtils.getHostInfo(executionEnvironment); switch (hostInfo.getOSFamily()) { - case WINDOWS: + case WINDOWS -> { // for now pty mode only supported with Cygwin Shell shell = WindowsSupport.getInstance().getActiveShell(); if (shell == null) { return false; } - - return shell.type == Shell.ShellType.CYGWIN; - case MACOSX: + + return shell.type == Shell.ShellType.CYGWIN || shell.type == Shell.ShellType.WSL; + } + case MACOSX -> { return true; - case LINUX: - return hostInfo.getCpuFamily().equals(CpuFamily.X86) + } + case LINUX -> { + return hostInfo.getCpuFamily().equals(CpuFamily.X86) || hostInfo.getCpuFamily().equals(CpuFamily.SPARC) || (hostInfo.getCpuFamily().equals(CpuFamily.ARM) && Boolean.getBoolean("cnd.pty.arm.support")) || hostInfo.getCpuFamily().equals(CpuFamily.AARCH64); - case SUNOS: + } + case SUNOS -> { return true; - case FREEBSD: + } + case FREEBSD -> { return false; - default: + } + default -> { return false; + } } } catch (IOException ex) { Exceptions.printStackTrace(ex); diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Authentication.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Authentication.java index 0fbf5795de48..99bdc67b6ec3 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Authentication.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Authentication.java @@ -38,18 +38,18 @@ public final class Authentication { public static final MethodList PASSWORD_METHODS = - new MethodList( + new MethodList(List.of( Pair.of(Method.GssapiWithMic, true), Pair.of(Method.PublicKey, false), Pair.of(Method.KeyboardInteractive, true), - Pair.of(Method.Password, true)); + Pair.of(Method.Password, true))); public static final MethodList SSH_KEY_METHODS = - new MethodList( + new MethodList(List.of( Pair.of(Method.GssapiWithMic, true), Pair.of(Method.PublicKey, true), Pair.of(Method.KeyboardInteractive, true), - Pair.of(Method.Password, true)); + Pair.of(Method.Password, true))); public static final MethodList DEFAULT_METHODS = PASSWORD_METHODS; @@ -317,6 +317,12 @@ public MethodList(List> pairs) { } } + /** + * @param pairs + * @deprecated use {@link #MethodList(java.util.List)} + */ + @Deprecated + @SuppressWarnings("unchecked") public MethodList(Pair ... pairs) { this.methods = new Method[pairs.length]; this.enabled = new boolean[pairs.length]; diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManager.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManager.java index 152e3a1e4f27..bcf1a4ab5e08 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManager.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManager.java @@ -38,7 +38,6 @@ import java.util.prefs.Preferences; import javax.swing.AbstractAction; import javax.swing.Action; -//import javax.swing.Action; import javax.swing.SwingUtilities; import org.netbeans.modules.nativeexecution.ConnectionManagerAccessor; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; @@ -48,14 +47,9 @@ import org.netbeans.modules.nativeexecution.jsch.JSchConnectionTask; import org.netbeans.modules.nativeexecution.spi.support.JSchAccess; import org.netbeans.modules.nativeexecution.spi.support.NativeExecutionUserNotification; -; import org.netbeans.modules.nativeexecution.support.Logger; import org.netbeans.modules.nativeexecution.support.MiscUtils; import org.netbeans.modules.nativeexecution.support.NativeTaskExecutorService; -//import org.openide.awt.StatusDisplayer; -//import org.openide.DialogDisplayer; -//import org.openide.NotifyDescriptor; -//import org.openide.awt.StatusDisplayer; import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; @@ -94,22 +88,17 @@ public CancellationException(String message) { private final ConnectionWatcher connectionWatcher; final int connectionWatcherInterval; - + private final SlowListenerDetector slowConnectionListenerDetector; static { ConnectionManagerAccessor.setDefault(new ConnectionManagerAccessorImpl()); - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - shutdown(); - } - })); + Runtime.getRuntime().addShutdownHook(new Thread(ConnectionManager::shutdown)); } private ConnectionManager() { - + int timeout = Integer.getInteger( "nativeexecution.slow.connection.listener.timeout", 500); //NOI18N Level level; @@ -184,10 +173,10 @@ public void removeConnectionListener(ConnectionListener listener) { // No need to lock - use thread-safe collection connectionListeners.remove(listener); } - + /** * Remove a connection from list of recent connections. Any stored settings will be removed - * @param execEnv environment + * @param execEnv environment */ public void deleteConnectionFromRecentConnections(ExecutionEnvironment execEnv) { synchronized (recentConnections) { @@ -196,11 +185,11 @@ public void deleteConnectionFromRecentConnections(ExecutionEnvironment execEnv) storeRecentConnectionsList(true); } } - - + + /** * Add a connection to a recent connection list. - * @param execEnv environment + * @param execEnv environment * @return true if a connection was added to a list */ public boolean addConnectionToRecentConnections(ExecutionEnvironment execEnv) { @@ -215,7 +204,7 @@ public boolean addConnectionToRecentConnections(ExecutionEnvironment execEnv) { storeRecentConnectionsList(false); return true; } - } + } public List getRecentConnections() { synchronized (recentConnections) { @@ -232,7 +221,7 @@ public List getRecentConnections() { } /** - * Store recent connection list. + * Store recent connection list. * @param clear true if settings is cleared before stored */ /*package-local for test purposes*/ void storeRecentConnectionsList(boolean clear) { @@ -314,7 +303,7 @@ private void fireDisconnected(ExecutionEnvironment execEnv) { } /** - * Tests whether the connection with the execEnv is established or + * Tests whether the connection with the {@code execEnv} is established or * not. * * @param execEnv execution environment to test connection with. @@ -411,7 +400,7 @@ private boolean connect(final ExecutionEnvironment env, final ConnectionContinua * This method does nothing if connection is already established. * * @param env - environment to initiate connection with - * @return true if host is connected when return from the method. + * @return {@code true} if host is connected when return from the method. */ public boolean connect(final ExecutionEnvironment env) { return connect(env, DEFAULT_CC); @@ -419,7 +408,7 @@ public boolean connect(final ExecutionEnvironment env) { /** * - * @param env ExecutionEnvironment to connect to. + * @param env {@code ExecutionEnvironment} to connect to. * @throws IOException * @throws CancellationException */ @@ -508,9 +497,10 @@ private void initiateConnection(final ExecutionEnvironment env, final JSch jsch) } else { JSchConnectionTask.Problem problem = connectionTask.getProblem(); switch (problem.type) { - case CONNECTION_CANCELLED: + case CONNECTION_CANCELLED -> { throw new CancellationException("Connection cancelled for " + env); // NOI18N - default: + } + default -> { // Note that AUTH_FAIL is generated not only on bad password, // but on socket timeout as well. These cases are // indistinguishable based on information from JSch. @@ -518,6 +508,7 @@ private void initiateConnection(final ExecutionEnvironment env, final JSch jsch) log.log(Level.INFO, "Error when connecting " + env, problem.cause); //NOI18N } throw new IOException(problem.type.name()+" "+env, problem.cause); //NOI18N + } } } @@ -550,7 +541,7 @@ public static ConnectionManager getInstance() { * @param execEnv - {@link ExecutionEnvironment} to connect to. * @param onConnect - Runnable that is executed when connection is * established. - * @return action to be used to connect to the execEnv. + * @return action to be used to connect to the {@code execEnv}. * @see Action */ public synchronized AsynchronousAction getConnectToAction( @@ -639,14 +630,11 @@ private ConnectToAction(ExecutionEnvironment execEnv, Runnable onConnect) { @Override public void actionPerformed(ActionEvent e) { - NativeTaskExecutorService.submit(new Runnable() { - @Override - public void run() { - try { - invoke(); - } catch (Throwable ex) { - log.warning(ex.getMessage()); - } + NativeTaskExecutorService.submit(() -> { + try { + invoke(); + } catch (Throwable ex) { + log.warning(ex.getMessage()); } }, "Connecting to " + env.toString()); // NOI18N } @@ -722,12 +710,13 @@ public void changeAuth(ExecutionEnvironment env, Authentication auth) { } switch (auth.getType()) { - case SSH_KEY: + case SSH_KEY -> { try { jsch.addIdentity(auth.getSSHKeyFile()); } catch (JSchException ex) { Exceptions.printStackTrace(ex); } + } } } } @@ -846,6 +835,7 @@ private class ConnectionWatcher implements Runnable { private final RequestProcessor.Task myTask; + @SuppressWarnings("LeakingThisInConstructor") public ConnectionWatcher() { myTask = new RequestProcessor("Connection Watcher", 1).create(this); //NOI18N } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/HelperUtility.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/HelperUtility.java index 618a771834b1..2cbb26c4a90c 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/HelperUtility.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/HelperUtility.java @@ -31,7 +31,6 @@ import java.util.HashMap; import java.util.MissingResourceException; import java.util.logging.Level; -import javax.imageio.IIOException; import org.netbeans.modules.nativeexecution.ConnectionManagerAccessor; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory; @@ -43,7 +42,6 @@ import org.netbeans.modules.nativeexecution.support.Logger; import org.netbeans.modules.nativeexecution.support.MiscUtils; import org.openide.modules.InstalledFileLocator; -import org.openide.util.Exceptions; /** * @@ -112,7 +110,7 @@ Also the code below and comment (see 235998:3c427e2d4185) says that we can be he if (result == null) { try { - File localFile = getLocalFileFromSysProp(hinfo); + File localFile = getLocalFileFromSysProp(hinfo, env.isLocal()); if (localFile == null) { localFile = getLocalFile(hinfo); @@ -207,8 +205,8 @@ Also the code below and comment (see 235998:3c427e2d4185) says that we can be he throw new IOException(ex); } } catch (ParseException | InterruptedException ex) { - if (ex.getCause() instanceof IOException) { - throw (IOException) ex.getCause(); + if (ex.getCause() instanceof IOException ioException) { + throw ioException; } throw new IOException(ex); } @@ -218,6 +216,10 @@ Also the code below and comment (see 235998:3c427e2d4185) says that we can be he return result; } + protected File getLocalFile(final ExecutionEnvironment env, final HostInfo hinfo) throws MissingResourceException { + return null; + } + protected File getLocalFile(final HostInfo hinfo) throws MissingResourceException { return null; } @@ -273,8 +275,14 @@ private static void copyFile(final File srcFile, final File dstFile) throws IOEx } } - private File getLocalFileFromSysProp(HostInfo hostInfo) { + private File getLocalFileFromSysProp(HostInfo hostInfo, boolean local) { String osname = hostInfo.getOS().getFamily().cname(); + if (local) { + Shell activeShell = WindowsSupport.getInstance().getActiveShell(); + if (activeShell != null && activeShell.type == Shell.ShellType.WSL) { + osname = "Linux"; + } + } String platform = hostInfo.getCpuFamily().name().toLowerCase(); String bitness = hostInfo.getOS().getBitness() == HostInfo.Bitness._64 ? "_64" : ""; // NOI18N StringBuilder propName = new StringBuilder(getClass().getSimpleName()); diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/MacroExpanderFactory.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/MacroExpanderFactory.java index c1779546c770..9d490bd80739 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/MacroExpanderFactory.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/MacroExpanderFactory.java @@ -53,7 +53,7 @@ public static MacroExpander getExpander(ExecutionEnvironment execEnv, boolean co } public static MacroExpander getExpander( - ExecutionEnvironment execEnv, ExpanderStyle style) { + ExecutionEnvironment execEnv, ExpanderStyle style) { return getExpander(execEnv, style, true); } @@ -69,33 +69,33 @@ public static MacroExpander getExpander( String key = ExecutionEnvironmentFactory.toUniqueID(execEnv) + '_' + style; MacroExpander result = expanderCache.get(key); - + if (result != null) { return result; } - HostInfo hostInfo = null; + HostInfo hostInfo = null; try { if (connectIfNeed || HostInfoUtils.isHostInfoAvailable(execEnv)) { hostInfo = HostInfoUtils.getHostInfo(execEnv); - } + } } catch (IOException ex) { - // ideally, the method should throw IOException, + // ideally, the method should throw IOException, // but it's to dangerous to change signature right now ex.printStackTrace(System.err); } catch (CancellationException ex) { - // ideally, the method should throw CancellationException, + // ideally, the method should throw CancellationException, // but it's to dangerous to change signature right now } - result = new MacroExpanderImpl(hostInfo, style); + result = new MacroExpanderImpl(hostInfo, style, execEnv.isLocal()); if (hostInfo != null) { MacroExpander existing = expanderCache.putIfAbsent(key, result); if (existing != null) { result = existing; } } - + return result; } @@ -118,11 +118,13 @@ private static class MacroExpanderImpl implements MacroExpander { {7, 3, 3, 3, 8, 8} }; protected final Map predefinedMacros = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap<>()); protected final HostInfo hostInfo; + private final boolean local; - public MacroExpanderImpl(final HostInfo hostInfo, final ExpanderStyle style) { + public MacroExpanderImpl(final HostInfo hostInfo, final ExpanderStyle style, final boolean local) { this.hostInfo = hostInfo; + this.local = local; setupPredefined(style); } @@ -181,57 +183,54 @@ public final String expandMacros( c = chars[pos]; switch (ttable[state][getCharClass(c)]) { - case 0: + case 0 -> { if (c != 0) { res.append(c); } - break; - case 1: + } + case 1 -> { mpos = pos; buf.setLength(0); state = 1; - break; - case 2: + } + case 2 -> { buf.append(c); state = 2; - break; - case 3: + } + case 3 -> { res.append(string.substring(mpos, pos + (c == 0 ? 0 : 1))); buf.setLength(0); state = 0; - break; - case 4: - state = 4; - break; - case 5: + } + case 4 -> state = 4; + case 5 -> { res.append(valueOf(buf.toString().trim(), map)); pos--; buf.setLength(0); state = 0; - break; - case 6: + } + case 6 -> { res.append(valueOf(buf.toString().trim(), map)); mpos = pos; buf.setLength(0); state = 1; - break; - case 7: + } + case 7 -> { buf.append(c); state = 3; - break; - case 8: - throw new ParseException("Bad substitution", pos); // NOI18N - case 9: + } + case 8 -> throw new ParseException("Bad substitution", pos); // NOI18N + case 9 -> { res.append(valueOf(buf.toString().trim(), map)); buf.setLength(0); state = 0; - break; - case 10: + } + case 10 -> { res.append(string.substring(mpos, pos)); pos--; buf.setLength(0); state = 0; - break; + } } pos++; } @@ -246,36 +245,42 @@ protected final void setupPredefined(ExpanderStyle style) { String soext; String osname; switch (hostInfo.getOSFamily()) { - case WINDOWS: + case WINDOWS -> { soext = "dll"; // NOI18N osname = "Windows"; // NOI18N - break; - case MACOSX: + } + case MACOSX -> { soext = "dylib"; // NOI18N osname = "MacOSX"; // NOI18N - break; - case SUNOS: + } + case SUNOS -> { soext = "so"; // NOI18N osname = "SunOS"; // NOI18N - break; - case LINUX: + } + case LINUX -> { soext = "so"; // NOI18N osname = "Linux"; // NOI18N - break; - case FREEBSD: + } + case FREEBSD -> { soext = "so"; // NOI18N osname = "FreeBSD"; // NOI18N - break; - default: + } + default -> { osname = hostInfo.getOSFamily().name(); soext = "so"; // NOI18N + } } OS os = hostInfo.getOS(); predefinedMacros.put("hostname", hostInfo.getHostname().toLowerCase()); // NOI18N predefinedMacros.put("soext", soext); // NOI18N - predefinedMacros.put("osname", osname); // NOI18N + Shell activeShell = WindowsSupport.getInstance().getActiveShell(); + if(local && activeShell != null && activeShell.type == Shell.ShellType.WSL) { + predefinedMacros.put("osname", "Linux"); // NOI18N + } else { + predefinedMacros.put("osname", osname); // NOI18N + } predefinedMacros.put("isa", os.getBitness().toString()); // NOI18N predefinedMacros.put("_isa", os.getBitness() == HostInfo.Bitness._64 && hostInfo.getCpuFamily() != HostInfo.CpuFamily.AARCH64 ? "_64" : ""); // NOI18N String platform = hostInfo.getCpuFamily().name().toLowerCase(); diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ProcessUtils.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ProcessUtils.java index 4c9e2489c915..b1c84624bd9b 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ProcessUtils.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ProcessUtils.java @@ -32,12 +32,11 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.Callable; -import org.netbeans.api.extexecution.input.LineProcessor; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; +import org.netbeans.api.extexecution.input.LineProcessor; import org.netbeans.modules.nativeexecution.NbRemoteNativeProcess; import org.netbeans.modules.nativeexecution.RemoteNativeProcess; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; @@ -52,21 +51,21 @@ public final class ProcessUtils { private static final RequestProcessor RP = new RequestProcessor("ProcessUtils", 1); // NOI18N + private static final String REMOTE_CHAR_SET = System.getProperty("cnd.remote.charset", "UTF-8"); // NOI18N private ProcessUtils() { } - private static final String remoteCharSet = System.getProperty("cnd.remote.charset", "UTF-8"); // NOI18N public static String getRemoteCharSet() { - return remoteCharSet; + return REMOTE_CHAR_SET; } public static boolean isAlive(Process p) { - if (p instanceof RemoteNativeProcess) { - RemoteNativeProcess rnp = (RemoteNativeProcess) p; + if (p == null) { + return false; + } else if (p instanceof RemoteNativeProcess rnp) { return rnp.isAlive(); - } else if (p instanceof NbRemoteNativeProcess) { - NbRemoteNativeProcess rnp = (NbRemoteNativeProcess) p; + } else if (p instanceof NbRemoteNativeProcess rnp) { return rnp.isAlive(); } else { try { @@ -137,8 +136,8 @@ public static String readProcessOutputLine(final Process p) throws IOException { } private static boolean isRemote(Process process) { - if (process instanceof NativeProcess) { - return ((NativeProcess) process).getExecutionEnvironment().isRemote(); + if (process instanceof NativeProcess nativeProcess) { + return nativeProcess.getExecutionEnvironment().isRemote(); } return false; } @@ -166,48 +165,41 @@ private static void logErrorImpl(final Level logLevel, final Logger log, List { + try { + readProcessStreamImpl(process.getInputStream(), isRemote(process), lineProcessor); + } catch (IOException ex) { + // nothing } }, "reading process output"); // NOI18N } public static Future> readProcessOutputAsync(final Process process) { - return NativeTaskExecutorService.submit(new Callable>() { - @Override - public List call() throws Exception { - return readProcessStreamImpl(process.getInputStream(), isRemote(process)); - } + return NativeTaskExecutorService.submit(() -> { + return readProcessStreamImpl(process.getInputStream(), isRemote(process)); }, "reading process output"); // NOI18N } + @SuppressWarnings("deprecation") // org.netbeans.api.extexecution.input.LineProcessor is API public static void readProcessErrorAsync(final Process process, final LineProcessor lineProcessor) { - NativeTaskExecutorService.submit(new Runnable() { - @Override - public void run() { - try { - readProcessStreamImpl(process.getErrorStream(), isRemote(process), lineProcessor); - } catch (IOException ex) { - // nothing - } + NativeTaskExecutorService.submit(() -> { + try { + readProcessStreamImpl(process.getErrorStream(), isRemote(process), lineProcessor); + } catch (IOException ex) { + // nothing } }, "reading process error"); // NOI18N } public static Future> readProcessErrorAsync(final Process process) { - return NativeTaskExecutorService.submit(new Callable>() { - @Override - public List call() throws Exception { - return readProcessStreamImpl(process.getErrorStream(), isRemote(process)); - } + return NativeTaskExecutorService.submit(() -> { + return readProcessStreamImpl(process.getErrorStream(), isRemote(process)); }, "reading process error"); // NOI18N } @@ -236,8 +228,7 @@ private static List readProcessStreamImpl(final InputStream stream, bool final BufferedReader br = getReader(stream, remoteStream); try { - String line; - while ((line = br.readLine()) != null) { + for(String line = br.readLine(); line != null; line = br.readLine()) { result.add(line); } } finally { @@ -249,28 +240,24 @@ private static List readProcessStreamImpl(final InputStream stream, bool return result; } - private static void readProcessStreamImpl(final InputStream stream, boolean remoteStream, final LineProcessor lineProcessor) throws IOException { + private static void readProcessStreamImpl(final InputStream stream, boolean remoteStream, @SuppressWarnings("deprecation") final LineProcessor lineProcessor) throws IOException { if (stream == null) { - lineProcessor.reset(); - lineProcessor.close(); + try (lineProcessor) { + lineProcessor.reset(); + } } else { lineProcessor.reset(); - final BufferedReader br = getReader(stream, remoteStream); - try { - String line; - while ((line = br.readLine()) != null) { + try (lineProcessor; + BufferedReader br = getReader(stream, remoteStream)) { + for(String line = br.readLine(); line != null; line = br.readLine()) { lineProcessor.processLine(line); } - } finally { - lineProcessor.close(); - if (br != null) { - br.close(); - } } } } + @SuppressWarnings("NestedAssignment") private static String readProcessStreamLine(final InputStream stream, boolean remoteStream) throws IOException { if (stream == null) { return ""; // NOI18N @@ -280,10 +267,9 @@ private static String readProcessStreamLine(final InputStream stream, boolean re final BufferedReader br = getReader(stream, remoteStream); try { - String line; boolean first = true; - while ((line = br.readLine()) != null) { + for(String line = br.readLine(); line != null; line = br.readLine()) { if (!first) { result.append('\n'); } @@ -303,7 +289,9 @@ private static String readProcessStreamLine(final InputStream stream, boolean re * Just a conveniency shortcut for calling both methods * ignoreProcessOutput() * ignoreProcessError() + * @param * @param p + * @return */ public static T ignoreProcessOutputAndError(final T p) { ignoreProcessOutput(p); @@ -315,17 +303,16 @@ public static T ignoreProcessOutputAndError(final T p) { * Even if you ignore process error stream, it should be read, * otherwise other processes can hang - this is a jsch related issue. * This method reads and ignores process error stream + * @param * @param p process + * @return */ public static T ignoreProcessError(final T p) { if (p != null) { - NativeTaskExecutorService.submit(new Runnable() { - @Override - public void run() { - try { - readAndIgnoreProcessStream(p.getErrorStream()); - } catch (IOException ex) { - } + NativeTaskExecutorService.submit(() -> { + try { + readAndIgnoreProcessStream(p.getErrorStream()); + } catch (IOException ex) { } }, "Reading process error " + p); // NOI18N } @@ -336,23 +323,23 @@ public void run() { * Even if you ignore process output stream, it should be read, * otherwise other processes can hang - this is a jsch related issue. * This method reads and ignores process output stream + * @param * @param p process + * @return */ public static T ignoreProcessOutput(final T p) { if (p != null) { - NativeTaskExecutorService.submit(new Runnable() { - @Override - public void run() { - try { - readAndIgnoreProcessStream(p.getInputStream()); - } catch (IOException ex) { - } + NativeTaskExecutorService.submit(() -> { + try { + readAndIgnoreProcessStream(p.getInputStream()); + } catch (IOException ex) { } }, "Reading process output " + p); // NOI18N } return p; } + @SuppressWarnings("deprecation") // org.netbeans.api.extexecution.input.LineProcessor is API public static void writeError(final Writer error, Process p) throws IOException { class MyLineProcessor implements LineProcessor { private IOException writeEx = null; @@ -372,7 +359,7 @@ public void reset() {} @Override public void close() {} - }; + } MyLineProcessor myLProcessor = new MyLineProcessor(); readProcessStreamImpl(p.getErrorStream(), isRemote(p), myLProcessor); if (myLProcessor.writeEx != null) { @@ -405,8 +392,8 @@ public static void destroy(Process process) { ExecutionEnvironment execEnv; - if (process instanceof NativeProcess) { - execEnv = ((NativeProcess) process).getExecutionEnvironment(); + if (process instanceof NativeProcess nativeProcess) { + execEnv = nativeProcess.getExecutionEnvironment(); } else { execEnv = ExecutionEnvironmentFactory.getLocal(); } @@ -416,8 +403,7 @@ public static void destroy(Process process) { if (pid > 0) { try { CommonTasksSupport.sendSignal(execEnv, pid, Signal.SIGKILL, null).get(); - } catch (InterruptedException ex) { - } catch (ExecutionException ex) { + } catch (InterruptedException | ExecutionException ex) { } } } @@ -426,9 +412,9 @@ private static int getPID(Process process) { int pid = -1; try { - if (process instanceof NativeProcess) { - pid = ((NativeProcess) process).getPID(); - } else { + if (process instanceof NativeProcess nativeProcess) { + pid = nativeProcess.getPID(); + } else if (process != null) { String className = process.getClass().getName(); // TODO: windows?... if ("java.lang.UNIXProcess".equals(className)) { // NOI18N @@ -445,13 +431,13 @@ private static int getPID(Process process) { } /** - * Starts executable and returns immediately. + * Starts executable and returns immediately. * @param execEnv - target execution environment - * @param rp - RequestProcessor that is used for running the task. + * @param rp - RequestProcessor that is used for running the task. * Could be NULL. In this case default (private) processor is used. * Note that default (private) processor has throughput == 1 - * @param postExecutor - once process is done, passed postExecutor will be - * notified. Call of postExecutor's method is performed in the same thread + * @param postExecutor - once process is done, passed postExecutor will be + * notified. Call of postExecutor's method is performed in the same thread * as invocation of the executable (i.e. in rp (see above)). * @param executable - full path to executable to run. * @param args - list of arguments to pass to executable @@ -459,26 +445,21 @@ private static int getPID(Process process) { */ public static Future execute(final ExecutionEnvironment execEnv, final RequestProcessor rp, final PostExecutor postExecutor, final String executable, final String... args) { final RequestProcessor processor = (rp == null) ? RP : rp; - return processor.submit(new Callable() { - - @Override - public ExitStatus call() throws Exception { + return processor.submit(() -> { + ExitStatus status = null; + String error = null; - ExitStatus status = null; - String error = null; - - try { - status = execute(execEnv, executable, args); - } catch (Throwable t) { - error = t.getMessage(); - } finally { - if (postExecutor != null) { - postExecutor.processFinished(error == null ? status : new ExitStatus(1, null, Arrays.asList(error.split("\n")))); // NOI18N - } + try { + status = execute(execEnv, executable, args); + } catch (Throwable t) { + error = t.getMessage(); + } finally { + if (postExecutor != null) { + postExecutor.processFinished(error == null ? status : new ExitStatus(1, null, Arrays.asList(error.split("\n")))); // NOI18N } - - return status; } + + return status; }); } @@ -506,7 +487,7 @@ public static ExitStatus executeWithoutMacroExpansion(final String workingDir, f * ExitStatus status = ProcessUtils.execute( * NativeProcessBuilder.newProcessBuilder(execEnv). * setExecutable("/bin/ls").setArguments("/home")); - * + * * if (status.isOK()) { * do something... * } else { @@ -518,7 +499,7 @@ public static ExitStatus executeWithoutMacroExpansion(final String workingDir, f * - initial suspend will be switched off * - unbuffering will be switched off * - usage of external terminal will be switched off - * + * * @param processBuilder * @since 1.13.0 * @return @@ -546,20 +527,12 @@ public static ExitStatus execute(final NativeProcessBuilder processBuilder, byte if (processBuilder.redirectErrorStream()) { error = null; } else { - error = NativeTaskExecutorService.submit(new Callable>() { - - @Override - public List call() throws Exception { - return readProcessError(process); - } + error = NativeTaskExecutorService.submit(() -> { + return readProcessError(process); }, "e"); // NOI18N } - output = NativeTaskExecutorService.submit(new Callable>() { - - @Override - public List call() throws Exception { - return readProcessOutput(process); - } + output = NativeTaskExecutorService.submit(() -> { + return readProcessOutput(process); }, "o"); // NOI18N if (input != null && input.length > 0) { process.getOutputStream().write(input); @@ -583,7 +556,7 @@ public List call() throws Exception { * Usage pattern: * ExitStatus status = ProcessUtils.execute( * new ProcessBuilder("/bin/ls")); - * + * * if (status.isOK()) { * do something... * } else { @@ -612,20 +585,12 @@ public static ExitStatus execute(final ProcessBuilder processBuilder, byte[] inp if (processBuilder.redirectErrorStream() || processBuilder.redirectError() != ProcessBuilder.Redirect.PIPE) { error = null; } else { - error = NativeTaskExecutorService.submit(new Callable>() { - - @Override - public List call() throws Exception { - return readProcessError(process); - } + error = NativeTaskExecutorService.submit(() -> { + return readProcessError(process); }, "e"); // NOI18N } - output = NativeTaskExecutorService.submit(new Callable>() { - - @Override - public List call() throws Exception { - return readProcessOutput(process); - } + output = NativeTaskExecutorService.submit(() -> { + return readProcessOutput(process); }, "o"); // NOI18N if (input != null && input.length > 0) { process.getOutputStream().write(input); @@ -641,7 +606,7 @@ public List call() throws Exception { return result; } - + public static final class ExitStatus { public final int exitCode; @@ -687,7 +652,11 @@ public String toString() { return "ExitStatus " + "exitCode=" + exitCode + "\nerror=" + getErrorString() + "\noutput=" + getOutputString(); // NOI18N } - /** This method may be ineffective. Consider using getOutputLines() */ + /** + * This method may be ineffective. Consider using getOutputLines() + * + * @return + */ public String getOutputString() { return output; } @@ -696,7 +665,11 @@ public List getOutputLines() { return outputLines; } - /** This method may be ineffective. Consider using getErrorLines() */ + /** + * This method may be ineffective. Consider using getErrorLines() + * + * @return + */ public String getErrorString() { return error; } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Shell.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Shell.java index 598c97b9aec2..ebd9fb2a9aee 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Shell.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/Shell.java @@ -48,26 +48,25 @@ public synchronized ShellValidationStatus getValidationStatus() { if (validationStatus == null) { validationStatus = ShellValidationSupport.getValidationStatus(this); } - + return validationStatus; } - + public enum ShellType { NO_SHELL, CYGWIN, MSYS, - UNKNOWN; + UNKNOWN, + WSL; public PathType toPathType() { - switch (this) { - case CYGWIN: - return PathType.CYGWIN; - case MSYS: - return PathType.MSYS; - default: - return null; - } + return switch (this) { + case CYGWIN -> PathType.CYGWIN; + case MSYS -> PathType.MSYS; + case WSL -> PathType.WSL; + default -> null; + }; } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellScriptRunner.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellScriptRunner.java index 781bc972e51a..da788a9b84e5 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellScriptRunner.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellScriptRunner.java @@ -49,6 +49,7 @@ * * @author ak119685 */ +@SuppressWarnings("deprecation") // API public final class ShellScriptRunner { private static final Logger log = org.netbeans.modules.nativeexecution.support.Logger.getInstance(); @@ -57,7 +58,7 @@ public final class ShellScriptRunner { private final ExecutionEnvironment env; private final String script; private final URI scriptURI; - private LineProcessor outputProcessor; + private final LineProcessor outputProcessor; private LineProcessor errorProcessor; private CountDownLatch countdown; private NativeProcess shellProcess; @@ -135,42 +136,26 @@ public synchronized int execute() throws IOException, CancellationException { RequestProcessor rp = new RequestProcessor("Shell runner", 3); // NOI18N countdown = new CountDownLatch(3); - Callable scriptWriter = new Callable() { - @Override - public Integer call() throws Exception { - BufferedWriter scriptWriter = null; - try { - scriptWriter = new BufferedWriter(new OutputStreamWriter(shellProcess.getOutputStream(), scriptCS)); - if (script != null) { - scriptWriter.write(script); - scriptWriter.write('\n'); - } else { - BufferedReader scriptReader = null; - try { - scriptReader = new BufferedReader(new InputStreamReader(scriptURI.toURL().openStream(), scriptCS)); - String scriptLine; - - while ((scriptLine = scriptReader.readLine()) != null) { - scriptWriter.write(scriptLine); - scriptWriter.write('\n'); - } - } finally { - if (scriptReader != null) { - scriptReader.close(); - } + Callable scriptWriter = () -> { + try (BufferedWriter scriptWriter1 = new BufferedWriter(new OutputStreamWriter(shellProcess.getOutputStream(), scriptCS))) { + if (script != null) { + scriptWriter1.write(script); + scriptWriter1.write('\n'); + } else { + try (BufferedReader scriptReader = new BufferedReader(new InputStreamReader(scriptURI.toURL().openStream(), scriptCS))) { + for( String scriptLine = scriptReader.readLine(); + scriptLine != null; + scriptLine = scriptReader.readLine()) { + scriptWriter1.write(scriptLine); + scriptWriter1.write('\n'); } } - scriptWriter.flush(); - } finally { - if (scriptWriter != null) { - scriptWriter.close(); - } - - countdown.countDown(); } - - return 0; + scriptWriter1.flush(); + } finally { + countdown.countDown(); } + return 0; }; ProcessOutputReader outReader = new ProcessOutputReader(shellProcess.getInputStream(), outputProcessor); @@ -252,19 +237,13 @@ private class ProcessOutputReader implements Callable { @Override public Integer call() throws Exception { - BufferedReader reader = null; - try { - reader = new BufferedReader(new InputStreamReader(in)); - String line; - while ((line = reader.readLine()) != null) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + for(String line = reader.readLine(); line != null; line = reader.readLine()) { if (lineProcessor != null) { lineProcessor.processLine(line); } } } finally { - if (reader != null) { - reader.close(); - } if (lineProcessor != null) { lineProcessor.close(); } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellValidationSupport.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellValidationSupport.java index 888aa36eab43..0259b6fd659e 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellValidationSupport.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/ShellValidationSupport.java @@ -27,10 +27,6 @@ import java.util.regex.Pattern; import org.netbeans.modules.nativeexecution.api.util.Shell.ShellType; import org.netbeans.modules.nativeexecution.spi.support.NativeExecutionUserNotification; -//import org.netbeans.modules.dlight.nativeexecution.ui.ShellValidationStatusPanel; -//import org.openide.DialogDescriptor; -//import org.openide.DialogDisplayer; -//import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; @@ -39,7 +35,7 @@ * @author ak119685 */ public final class ShellValidationSupport { - + protected static final ShellValidationStatus NOSHELL = new ShellValidationStatus(null, Arrays.asList("No shell"), null); // NOI18N protected static final ShellValidationStatus VALID = new ShellValidationStatus(null, null, null); @@ -50,15 +46,28 @@ public static ShellValidationStatus getValidationStatus(final Shell shell) { if (shell == null) { return NOSHELL; - } - - if (shell.type == ShellType.CYGWIN) { + } else if (shell.type == ShellType.CYGWIN) { return validateCygwinShell(shell); + } else if (shell.type == ShellType.WSL) { + return validateWslShell(shell); } return VALID; } + private static ShellValidationStatus validateWslShell(final Shell shell) { + assert shell != null && shell.type == ShellType.WSL; + File wslPath = new File(System.getenv("windir"), "system32/wsl.exe"); + ProcessUtils.ExitStatus exitStatus = ProcessUtils.execute(new ProcessBuilder(wslPath.getPath(), shell.shell, "-c", "echo 'Works'")); // NOI18N + if (! exitStatus.isOK()) { + return new ShellValidationStatus(shell, Arrays.asList("Failed to execute smoke test for shell (WSL) " + shell.shell + ", exit status: " + exitStatus), null); + } + if(! exitStatus.getOutputString().startsWith("Works")) { + return new ShellValidationStatus(shell, Arrays.asList("Smoke test for shell did not yield expected result: " + exitStatus.getOutputString()), null); + } + return VALID; + } + private static ShellValidationStatus validateCygwinShell(final Shell shell) { assert shell != null && shell.type == ShellType.CYGWIN; @@ -131,7 +140,6 @@ private static ShellValidationStatus validateCygwinShell(final Shell shell) { if (!p2.startsWith(p1)) { validationWarnings.add(loc("ShellValidationSupport.ValidationError.wrongMountPoint", winpath, cygpath)); // NOI18N - continue; } } } @@ -148,6 +156,7 @@ public static boolean confirm(final ShellValidationStatus status) { return confirm(null, null, status); } + @SuppressWarnings("AccessingNonPublicFieldOfAnotherObject") public static boolean confirm(final String header, final String footer, final ShellValidationStatus status) { if (status == null || status == NOSHELL) { if (Boolean.getBoolean("nativeexecution.mode.unittest") || "true".equals(System.getProperty("cnd.command.line.utility"))) { // NOI18N @@ -174,7 +183,6 @@ public static boolean confirm(final String header, final String footer, final Sh return true; } - Object response = null; if (Boolean.getBoolean("nativeexecution.mode.unittest")) { System.err.println(loc("ShellValidationSupport.ValidationError.ErrorDialogTitle", "cygwin")); System.err.println(header); @@ -187,45 +195,7 @@ public static boolean confirm(final String header, final String footer, final Sh return NativeExecutionUserNotification.getDefault().confirmShellStatusValiation( loc("ShellValidationSupport.ValidationError.ErrorDialogTitle", "cygwin"),//NOI18N header, footer, status.shell); -// final ShellValidationStatusPanel errorPanel = new ShellValidationStatusPanel(header, footer, status.shell); -// -// final JButton noButton = new JButton("No"); // NOI18N -// errorPanel.setActionListener(new ActionListener() { -// -// @Override -// public void actionPerformed(ActionEvent e) { -// noButton.setEnabled(!errorPanel.isRememberDecision()); -// } -// }); -// -// DialogDescriptor dd = new DialogDescriptor(errorPanel, -// loc("ShellValidationSupport.ValidationError.ErrorDialogTitle", "cygwin"), // NOI18N -// true, -// new Object[]{DialogDescriptor.YES_OPTION, noButton}, -// noButton, -// DialogDescriptor.DEFAULT_ALIGN, null, null); -// -// Dialog dialog = DialogDisplayer.getDefault().createDialog(dd); -// -// try { -// dialog.setVisible(true); -// } catch (Throwable th) { -// if (!(th.getCause() instanceof InterruptedException)) { -// throw new RuntimeException(th); -// } -// dd.setValue(DialogDescriptor.CANCEL_OPTION); -// } finally { -// dialog.dispose(); -// } -// -// response = dd.getValue(); -// -// if (response == DialogDescriptor.YES_OPTION && errorPanel.isRememberDecision()) { -// NbPreferences.forModule(WindowsSupport.class).put(key, "yes"); // NOI18N -// } } - - // return (response == DialogDescriptor.YES_OPTION); } public static class ShellValidationStatus { diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupport.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupport.java index d90c60003e70..b91ce0954118 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupport.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupport.java @@ -18,9 +18,9 @@ */ package org.netbeans.modules.nativeexecution.api.util; -import java.security.acl.NotOwnerException; import java.util.Collection; import java.util.List; +import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; /** @@ -45,9 +45,8 @@ public interface SolarisPrivilegesSupport { /** * Retrieves a list of currently effective execution privileges in the - * ExecutionEnvironment + * {@link ExecutionEnvironment} * - * @param execEnv ExecutionEnvironment to get privileges list from * @return a list of currently effective execution privileges */ public List getExecutionPrivileges(); @@ -61,12 +60,12 @@ public boolean requestPrivileges( String user, char[] passwd) throws NotOwnerException, InterruptedException, CancellationException; /** - * Tests whether the ExecutionEnvironment has all needed + * Tests whether the {@link ExecutionEnvironment} has all needed * execution privileges. - * @param execEnv - ExecutionEnvironment to be tested - * @param privs - list of priveleges to be tested - * @return true if execEnv has all execution privileges listed in - * privs + * + * @param privs list of priveleges to be tested + * @return true if {@link ExecutionEnvironment} has all execution privileges + * listed in {@code privs} */ public boolean hasPrivileges(Collection privs); @@ -74,11 +73,10 @@ public boolean requestPrivileges( * Returns {@link Action javax.swing.Action} that can be invoked in order * to request needed execution privileges * - * @param execEnv ExecutionEnvironment where to request privileges * @param requestedPrivileges a list of execution privileges to request * @param onPrivilegesGranted Runnable that is executed on successful * privileges gain - * @return Action that can be invoked in order + * @return {@link AsynchronousAction} that can be invoked in order * to request needed execution privileges */ public AsynchronousAction getRequestPrivilegesAction( @@ -88,4 +86,7 @@ public AsynchronousAction getRequestPrivilegesAction( * This method is invoked when connection to the ExecutionEnviroment is lost */ public void invalidate(); + + public class NotOwnerException extends Exception { + } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupportProvider.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupportProvider.java index aa21b3dd33c4..de3198450c30 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupportProvider.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/SolarisPrivilegesSupportProvider.java @@ -28,6 +28,7 @@ import org.netbeans.modules.nativeexecution.support.Logger; @Deprecated(forRemoval = true) +@SuppressWarnings("removal") public final class SolarisPrivilegesSupportProvider { private static final ConcurrentHashMap instances = diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/WindowsSupport.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/WindowsSupport.java index 55301aec6c85..0459d9db4ca9 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/WindowsSupport.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/api/util/WindowsSupport.java @@ -18,6 +18,8 @@ */ package org.netbeans.modules.nativeexecution.api.util; +import com.sun.jna.platform.win32.Advapi32Util; +import com.sun.jna.platform.win32.WinReg; import java.io.File; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @@ -43,11 +45,13 @@ public final class WindowsSupport { private static final java.util.logging.Logger log = Logger.getInstance(); private static final Object initLock = new Object(); + private static final String SHELL_PROVIDER = System.getProperty("org.netbeans.modules.nativeexecution.api.util.WindowsSupport.shellProvider", null); + private static final String WSL_REG_BASE = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Lxss"; private static WindowsSupport instance; private boolean initialized = false; private Shell activeShell = null; private PathConverter pathConverter = null; - private AtomicReference pathKeyRef = new AtomicReference<>(); + private final AtomicReference pathKeyRef = new AtomicReference<>(); private Charset charset; private WindowsSupport() { @@ -94,47 +98,76 @@ public void init(String searchDir) { } } + private boolean isCheckShellProvider(ShellType shellType) { + if (shellType == null) { + return true; + } + return SHELL_PROVIDER == null || SHELL_PROVIDER.trim().isEmpty() || shellType.name().equals(SHELL_PROVIDER); + } + private Shell findShell(String searchDir) { Shell shell; Shell candidate = null; + // 0. Try wsl + + if (isWslAvailable() && isCheckShellProvider(ShellType.WSL)) { + File distributionPath = getWslDefaulDistributionFile(); + if (distributionPath != null) { + for (String s : new String[]{"/usr/bin/bash", "/bin/bash"}) { + File wslShell = new File(distributionPath, s); + if (wslShell.exists()) { + candidate = new Shell(ShellType.WSL, s, wslShell.getParentFile()); + ShellValidationStatus validationStatus = ShellValidationSupport.getValidationStatus(candidate); + if (validationStatus.isValid() && !validationStatus.hasWarnings()) { + return candidate; + } + } + } + } + } + // 1. Try to find cygwin ... - String[][] cygwinRegKeys = new String[][]{ - new String[]{"SOFTWARE\\cygwin\\setup", "rootdir", ".*rootdir.*REG_SZ(.*)"}, // NOI18N - new String[]{"SOFTWARE\\Wow6432Node\\cygwin\\setup", "rootdir", ".*rootdir.*REG_SZ(.*)"}, // NOI18N - new String[]{"SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/", "native", ".*native.*REG_SZ(.*)"}, // NOI18N - new String[]{"SOFTWARE\\Wow6432Node\\Cygnus Solutions\\Cygwin\\mounts v2\\/", "native", ".*native.*REG_SZ(.*)"}, // NOI18N - }; - - for (String[] regKey : cygwinRegKeys) { - shell = initShell(ShellType.CYGWIN, queryWindowsRegistry( - regKey[0], regKey[1], regKey[2])); - - // If found cygwin in registry - it is assumed to be valid - - // just choose one - if (shell != null) { - return shell; + if (isCheckShellProvider(ShellType.CYGWIN)) { + String[][] cygwinRegKeys = new String[][]{ + new String[]{"SOFTWARE\\cygwin\\setup", "rootdir", ".*rootdir.*REG_SZ(.*)"}, // NOI18N + new String[]{"SOFTWARE\\Wow6432Node\\cygwin\\setup", "rootdir", ".*rootdir.*REG_SZ(.*)"}, // NOI18N + new String[]{"SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/", "native", ".*native.*REG_SZ(.*)"}, // NOI18N + new String[]{"SOFTWARE\\Wow6432Node\\Cygnus Solutions\\Cygwin\\mounts v2\\/", "native", ".*native.*REG_SZ(.*)"}, // NOI18N + }; + + for (String[] regKey : cygwinRegKeys) { + shell = initShell(ShellType.CYGWIN, queryWindowsRegistry( + regKey[0], regKey[1], regKey[2])); + + // If found cygwin in registry - it is assumed to be valid - + // just choose one + if (shell != null) { + return shell; + } } } // No cygwin in the registry... // try msys - String[] msysRegKeys = new String[]{ - "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS-1.0_is1", // NOI18N - "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS-1.0_is1", // NOI18N - }; - - for (String regKey : msysRegKeys) { - shell = initShell(ShellType.MSYS, queryWindowsRegistry( - regKey, - "Inno Setup: App Path", // NOI18N - ".*REG_SZ(.*)")); // NOI18N - - if (shell != null) { - // Again, if found one - use it - return shell; + if (isCheckShellProvider(ShellType.MSYS)) { + String[] msysRegKeys = new String[]{ + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS-1.0_is1", // NOI18N + "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS-1.0_is1", // NOI18N + }; + + for (String regKey : msysRegKeys) { + shell = initShell(ShellType.MSYS, queryWindowsRegistry( + regKey, + "Inno Setup: App Path", // NOI18N + ".*REG_SZ(.*)")); // NOI18N + + if (shell != null) { + // Again, if found one - use it + return shell; + } } } @@ -158,19 +191,19 @@ private Shell findShell(String searchDir) { if ("bin".equals(parent.getName())) { // NOI18N // Looks like we have found something... // An attempt to understand what exactly we have found - if (new File(parent, "msysinfo").exists()) { // NOI18N + if (new File(parent, "msysinfo").exists() && isCheckShellProvider(ShellType.MSYS)) { // NOI18N // Looks like this one is msys... // As no valid cygwin was found - use it return new Shell(ShellType.MSYS, sh.getAbsolutePath(), parent); - } else if (new File(parent, "msys-2.0.dll").exists()) { // NOI18N + } else if (new File(parent, "msys-2.0.dll").exists() && isCheckShellProvider(ShellType.MSYS)) { // NOI18N // Looks like this one is msys2... // As no valid cygwin was found - use it return new Shell(ShellType.MSYS, sh.getAbsolutePath(), parent); - } else if (new File(parent, "cygwin1.dll").exists()) { // NOI18N + } else if (new File(parent, "cygwin1.dll").exists() && isCheckShellProvider(ShellType.CYGWIN)) { // NOI18N // Looks like this one is sygwin... // As no valid cygwin was found - use it return new Shell(ShellType.CYGWIN, sh.getAbsolutePath(), parent); - } else if (new File(parent, "cygcheck.exe").exists()) { // NOI18N + } else if (new File(parent, "cygcheck.exe").exists() && isCheckShellProvider(ShellType.CYGWIN)) { // NOI18N // Well ... // The problem is that is is not in registry... // I.e. we will use it if on msys found on the system... @@ -187,6 +220,7 @@ private Shell findShell(String searchDir) { } } } + } } } @@ -211,14 +245,11 @@ public int getWinPID(int shellPID) { String psCommand = psFile.getAbsolutePath(); switch (activeShell.type) { - case CYGWIN: - pb = new ProcessBuilder(psCommand, "-W", "-p", Integer.toString(shellPID)); // NOI18N - break; - case MSYS: - pb = new ProcessBuilder(psCommand, "-W"); // NOI18N - break; - default: + case CYGWIN -> pb = new ProcessBuilder(psCommand, "-W", "-p", Integer.toString(shellPID)); // NOI18N + case MSYS -> pb = new ProcessBuilder(psCommand, "-W"); // NOI18N + default -> { return shellPID; + } } ExitStatus res = ProcessUtils.execute(pb); @@ -227,7 +258,7 @@ public int getWinPID(int shellPID) { for (String s : output) { Matcher m = pat.matcher(s); if (m.matches()) { - Integer pid = Integer.parseInt(m.group(1)); + int pid = Integer.parseInt(m.group(1)); if (pid == shellPID) { return Integer.parseInt(m.group(4)); } @@ -269,9 +300,16 @@ public String convertFromMSysPath(String msysPath) { return convert(PathType.MSYS, PathType.WINDOWS, msysPath, true); } + public String convertToWSL(String winPath) { + return convert(PathType.WINDOWS, PathType.WSL, winPath, true); + } + /** * Cygwin is preferrable shell (over msys). So it cygwin is installed we * will always use it's for shell + * + * @param path + * @return */ public String convertToShellPath(String path) { return activeShell == null ? null : convert(PathType.WINDOWS, activeShell.type.toPathType(), path, true); @@ -391,4 +429,28 @@ public String getPathKey() { } return pathKeyRef.get(); } + + private boolean isWslAvailable() { + return new File(System.getenv("windir"), "system32/wsl.exe").exists(); + } + + private String getWslDefaulDistributionName() { + if (Advapi32Util.registryValueExists(WinReg.HKEY_CURRENT_USER, WSL_REG_BASE, "DefaultDistribution")) { + String defaultDistribution = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, WSL_REG_BASE, "DefaultDistribution"); + if (Advapi32Util.registryValueExists(WinReg.HKEY_CURRENT_USER, WSL_REG_BASE + "\\" + defaultDistribution, "DistributionName")) { + String distributionName = Advapi32Util.registryGetStringValue(WinReg.HKEY_CURRENT_USER, WSL_REG_BASE + "\\" + defaultDistribution, "DistributionName"); + return distributionName; + } + } + return null; + } + + File getWslDefaulDistributionFile() { + String distributionName = getWslDefaulDistributionName(); + if(distributionName != null) { + return new File("\\\\wsl.localhost\\", distributionName); + } else { + return null; + } + } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/NbStartUtility.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/NbStartUtility.java index 15fbf4741dcb..454cfa2b120a 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/NbStartUtility.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/NbStartUtility.java @@ -26,6 +26,9 @@ import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; import org.netbeans.modules.nativeexecution.api.util.HelperUtility; import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils; +import org.netbeans.modules.nativeexecution.api.util.Shell; +import org.netbeans.modules.nativeexecution.api.util.Shell.ShellType; +import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; import org.netbeans.modules.nativeexecution.support.InstalledFileLocatorProvider; import org.openide.modules.InstalledFileLocator; @@ -36,19 +39,31 @@ public class NbStartUtility extends HelperUtility { private static final boolean ENABLED = Boolean.parseBoolean(System.getProperty("enable.nbstart", "true")); // NOI18N - private static final NbStartUtility instance = new NbStartUtility(); + private static final NbStartUtility instanceRemote = new NbStartUtility(false); + private static final NbStartUtility instanceLocal = new NbStartUtility(true); - public NbStartUtility() { + // Hack to be able to differentiate between local and remote execution + // getLocalFile(Hostinfo) needs this on Windows WSL. Implemented like this + // as HelperUtility is exported and Hostinfo can't be used to detect if + // execution is local + private final boolean local; + + public NbStartUtility(boolean local) { super("bin/nativeexecution/${osname}-${platform}${_isa}/pty"); // NOI18N + this.local = local; } - public static NbStartUtility getInstance() { - return instance; + public static NbStartUtility getInstance(boolean local) { + return local ? instanceLocal : instanceRemote; } @Override protected File getLocalFile(final HostInfo hostInfo) throws MissingResourceException { String osname = hostInfo.getOS().getFamily().cname(); + Shell activeShell = WindowsSupport.getInstance().getActiveShell(); + if(local && activeShell != null && activeShell.type == Shell.ShellType.WSL) { + osname = "Linux"; + } String platform = hostInfo.getCpuFamily().name().toLowerCase(); String bitness = hostInfo.getOS().getBitness() == HostInfo.Bitness._64 ? "_64" : ""; // NOI18N @@ -70,9 +85,7 @@ protected File getLocalFile(final HostInfo hostInfo) throws MissingResourceExcep public boolean isSupported(ExecutionEnvironment executionEnvironment) { try { return isSupported(HostInfoUtils.getHostInfo(executionEnvironment)); - } catch (IOException ex) { - return false; - } catch (CancellationException ex) { + } catch (IOException | CancellationException ex) { return false; } } @@ -84,16 +97,22 @@ public boolean isSupported(HostInfo hostInfo) { try { switch (hostInfo.getOS().getFamily()) { - case MACOSX: - case SUNOS: - case LINUX: + case MACOSX, SUNOS, LINUX -> { try { return getLocalFile(hostInfo) != null; } catch (MissingResourceException ex) { } return false; - case WINDOWS: - case FREEBSD: + } + case WINDOWS -> { + Shell shell = WindowsSupport.getInstance().getActiveShell(); + if(shell != null && shell.getValidationStatus().isValid() && shell.type == ShellType.WSL) { + return true; + } else { + return false; + } + } + case FREEBSD -> { // For now will disable it on Windows, as there are some // side-effects with paths (need deeper studying) // Shell activeShell = WindowsSupport.getInstance().getActiveShell(); @@ -102,8 +121,10 @@ public boolean isSupported(HostInfo hostInfo) { // } // return getPath(executionEnvironment) != null; return false; - default: + } + default -> { return false; + } } } catch (Exception ex) { return false; diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java index 69611ecaa064..c95f81d227a9 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java @@ -37,7 +37,6 @@ import org.netbeans.modules.nativeexecution.api.util.Shell; import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; import org.netbeans.modules.nativeexecution.pty.PtyOpenUtility.PtyInfo; -import org.openide.util.Exceptions; import org.openide.util.Utilities; /** @@ -82,12 +81,22 @@ public Pty allocate(final ExecutionEnvironment env) throws IOException { if (Utilities.isWindows()) { // Only works with cygwin... - if (hostInfo.getShell() == null || WindowsSupport.getInstance().getActiveShell().type != Shell.ShellType.CYGWIN) { - throw new IOException("terminal support requires Cygwin to be installed"); // NOI18N + if (hostInfo.getShell() == null + || (WindowsSupport.getInstance().getActiveShell().type != Shell.ShellType.CYGWIN + && WindowsSupport.getInstance().getActiveShell().type != Shell.ShellType.WSL) + ) { + throw new IOException("terminal support requires Cygwin/WSL to be installed"); // NOI18N + } + Shell activeShell = WindowsSupport.getInstance().getActiveShell(); + if( activeShell != null && activeShell.type != Shell.ShellType.CYGWIN) { + ptyOpenUtilityPath = WindowsSupport.getInstance().convertToCygwinPath(ptyOpenUtilityPath); + String path = MacroMap.forExecEnv(env).get("PATH"); // NOI18N + pb.environment().put("Path", path); // NOI18N + } else { + ptyOpenUtilityPath = WindowsSupport.getInstance().convertToWSL(ptyOpenUtilityPath); + String path = MacroMap.forExecEnv(env).get("PATH"); // NOI18N + pb.environment().put("Path", path); // NOI18N } - ptyOpenUtilityPath = WindowsSupport.getInstance().convertToCygwinPath(ptyOpenUtilityPath); - String path = MacroMap.forExecEnv(env).get("PATH"); // NOI18N - pb.environment().put("Path", path); // NOI18N } Process pty = pb.start(); // no ProcessUtils, streams are attached below @@ -109,17 +118,18 @@ public Pty allocate(final ExecutionEnvironment env) throws IOException { if (ptyInfo == null) { BufferedReader br = new BufferedReader(new InputStreamReader(streams.err)); - String errorLine; StringBuilder err_msg = new StringBuilder(); - while ((errorLine = br.readLine()) != null) { + for(String errorLine = br.readLine(); errorLine != null; errorLine = br.readLine()) { err_msg.append(errorLine).append('\n'); } throw new IOException(err_msg.toString()); } result = new PtyImplementation(env, ptyInfo.tty, ptyInfo.pid, streams); - } catch (Exception ex) { - throw (ex instanceof IOException) ? (IOException) ex : new IOException(ex); + } catch (IOException ex) { + throw ex; + } catch (JSchException | InterruptedException | RuntimeException ex) { + throw new IOException(ex); } finally { if (result == null && streams != null) { if (streams.in != null) { diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/impl/NbKillAllSignalSupport.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/impl/NbKillAllSignalSupport.java index 4fc872c76b76..ecb535c59817 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/impl/NbKillAllSignalSupport.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/signals/impl/NbKillAllSignalSupport.java @@ -56,26 +56,28 @@ public boolean isSupported(ExecutionEnvironment env, SIGNAL_SCOPE scope) { } switch (hostInfo.getOSFamily()) { - case LINUX: - case SUNOS: + case LINUX, SUNOS -> { return true; - case FREEBSD: + } + case FREEBSD -> { return false; - case WINDOWS: - if (scope == SIGNAL_SCOPE.SIGNAL_BY_ENV) { - return false; - } + } + case WINDOWS -> { Shell activeShell = WindowsSupport.getInstance().getActiveShell(); - return (activeShell != null && activeShell.type == Shell.ShellType.CYGWIN); - case MACOSX: - if (scope == SIGNAL_SCOPE.SIGQUEUE_PROCESS) { + if (scope == SIGNAL_SCOPE.SIGNAL_BY_ENV && (activeShell == null || activeShell.type != Shell.ShellType.WSL)) { return false; } - return true; - default: + return (activeShell != null && (activeShell.type == Shell.ShellType.CYGWIN || activeShell.type == Shell.ShellType.WSL)); + } + case MACOSX -> { + return scope != SIGNAL_SCOPE.SIGQUEUE_PROCESS; + } + + default -> { return false; + } } - } catch (Exception ex) { + } catch (IOException | ConnectionManager.CancellationException | RuntimeException ex) { return false; } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesAction.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesAction.java index 871f321435a1..58b7289f757f 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesAction.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesAction.java @@ -18,7 +18,6 @@ */ package org.netbeans.modules.nativeexecution.sps.impl; -import java.security.acl.NotOwnerException; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; @@ -26,6 +25,7 @@ import org.netbeans.modules.nativeexecution.support.ObservableAction; import org.openide.util.NbBundle; +@SuppressWarnings("removal") public final class RequestPrivilegesAction extends ObservableAction { @@ -65,9 +65,8 @@ public synchronized Boolean performAction() { try { support.requestPrivileges(requestedPrivileges, true); - } catch (CancellationException ex) { - return Boolean.FALSE; // TODO:CancellationException error processing - } catch (NotOwnerException ex) { + } catch (CancellationException | SolarisPrivilegesSupport.NotOwnerException ex) { + // TODO:CancellationException error processing return Boolean.FALSE; } return Boolean.TRUE; diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesTask.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesTask.java index 5ffa4f31bc05..50f5033633c1 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesTask.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/RequestPrivilegesTask.java @@ -19,24 +19,23 @@ package org.netbeans.modules.nativeexecution.sps.impl; import java.lang.ref.WeakReference; -import java.security.acl.NotOwnerException; import java.util.Arrays; import java.util.Collection; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.logging.Level; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils; +import org.netbeans.modules.nativeexecution.api.util.SolarisPrivilegesSupport; import org.netbeans.modules.nativeexecution.spi.support.GrantPrivilegesProvider; import org.netbeans.modules.nativeexecution.spi.support.GrantPrivilegesProviderFactory; import org.netbeans.modules.nativeexecution.sps.impl.RequestPrivilegesTask.RequestPrivilegesTaskParams; import org.netbeans.modules.nativeexecution.support.Computable; import org.netbeans.modules.nativeexecution.support.Logger; import org.netbeans.modules.nativeexecution.support.NativeTaskExecutorService; -//import org.netbeans.module.nativeexecution.ui.GrantPrivilegesDialog; -import org.openide.util.Cancellable; import org.openide.util.Lookup; import org.openide.util.NbBundle; @@ -45,24 +44,22 @@ public final class RequestPrivilegesTask implements Computable dialogRef = null; + @Override public Boolean compute(RequestPrivilegesTaskParams args) throws InterruptedException { final RequestPrivilegesTaskPerformer performer = new RequestPrivilegesTaskPerformer(args); final Future result = NativeTaskExecutorService.submit(performer, "RequestPrivilegesTask"); // NOI18N final ProgressHandle ph = ProgressHandle.createHandle( - loc("TaskPrivilegesSupport_Progress_RequestPrivileges"), new Cancellable() { // NOI18N - - public boolean cancel() { - return result.cancel(true); - } - }); + loc("TaskPrivilegesSupport_Progress_RequestPrivileges"), // NOI18N + () -> result.cancel(true) + ); ph.start(); try { return result.get(); } catch (ExecutionException ex) { - log.fine("ExecutionException in RequestPrivilegesTask : " + ex.toString()); // NOI18N + log.log(Level.FINE, "ExecutionException in RequestPrivilegesTask", ex); // NOI18N } catch (CancellationException ex) { // skip. Will return false } finally { @@ -91,7 +88,7 @@ public RequestPrivilegesTaskParams( this.requestedPrivileges = requestedPrivileges; this.askForPassword = askForPassword; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (String priv : requestedPrivileges) { sb.append(priv).append(","); // NOI18N @@ -131,6 +128,8 @@ public RequestPrivilegesTaskPerformer(RequestPrivilegesTaskParams args) { this.args = args; } + @Override + @SuppressWarnings({"AccessingNonPublicFieldOfAnotherObject", "removal"}) public Boolean call() throws Exception { // An attempt to grant privileges using pfexec NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(args.support.getExecEnv()); @@ -168,7 +167,7 @@ public Boolean call() throws Exception { Arrays.fill(clearPassword, (char) 0); provider.clearPassword(); return Boolean.TRUE; - } catch (NotOwnerException ex) { + } catch (SolarisPrivilegesSupport.NotOwnerException ex) { // wrong password or not enough privileges... // Continue with password requests... } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSCommonImpl.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSCommonImpl.java index 4d9cfe4bde74..5651e35af43d 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSCommonImpl.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSCommonImpl.java @@ -18,7 +18,6 @@ */ package org.netbeans.modules.nativeexecution.sps.impl; -import java.security.acl.NotOwnerException; import java.util.Collection; import java.util.List; import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; @@ -33,9 +32,9 @@ import org.netbeans.modules.nativeexecution.support.ObservableActionListener; import org.netbeans.modules.nativeexecution.support.TasksCachedProcessor; import org.openide.util.Exceptions; -import org.openide.util.NbBundle; import org.openide.util.WeakListeners; +@SuppressWarnings("removal") public abstract class SPSCommonImpl implements SolarisPrivilegesSupport { private static final TasksCachedProcessor> cachedPrivilegesFetcher = @@ -98,7 +97,7 @@ public void requestPrivileges( try { if (cachedPrivilegesRequestor.compute( - new RequestPrivilegesTaskParams(this, requestedPrivileges, askForPassword)).booleanValue() == true) { + new RequestPrivilegesTaskParams(this, requestedPrivileges, askForPassword))== true) { invalidateCache(); } else { throw new NotOwnerException(); @@ -172,7 +171,7 @@ public void actionStarted(Action source) { @Override public void actionCompleted(Action source, Boolean result) { - if (result != null && result.booleanValue() == true) { + if (result != null && result == true) { onPrivilegesGranted.run(); } } @@ -191,7 +190,4 @@ public void invalidate() { invalidateCache(); } - private static String loc(String key, String... params) { - return NbBundle.getMessage(SPSCommonImpl.class, key, params); - } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSLocalImpl.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSLocalImpl.java index a91820e1742f..9add40ad2f9a 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSLocalImpl.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSLocalImpl.java @@ -22,7 +22,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.security.SignatureException; -import java.security.acl.NotOwnerException; import java.text.ParseException; import java.util.Collection; import java.util.HashMap; @@ -60,7 +59,6 @@ private SPSLocalImpl(ExecutionEnvironment execEnv, String privp) { public static SPSLocalImpl getNewInstance(ExecutionEnvironment execEnv) throws SignatureException, MissingResourceException { - String privpCmd = null; MacroExpander macroExpander = MacroExpanderFactory.getExpander(execEnv); String path = "$osname-$platform"; // NOI18N @@ -69,7 +67,7 @@ public static SPSLocalImpl getNewInstance(ExecutionEnvironment execEnv) } catch (ParseException ex) { } - privpCmd = "bin/nativeexecution/" + path + "/privp"; // NOI18N + String privpCmd = "bin/nativeexecution/" + path + "/privp"; // NOI18N InstalledFileLocator fl = InstalledFileLocatorProvider.getDefault(); File file = fl.locate(privpCmd, "org.netbeans.modules.dlight.nativeexecution", false); //NOI18N @@ -88,9 +86,7 @@ public static SPSLocalImpl getNewInstance(ExecutionEnvironment execEnv) Future chmod = CommonTasksSupport.chmod(execEnv, privpCmd, 0755, null); try { chmod.get(); - } catch (ExecutionException ex) { - Exceptions.printStackTrace(ex); - } catch (InterruptedException ex) { + } catch (ExecutionException | InterruptedException ex) { Exceptions.printStackTrace(ex); } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSRemoteImpl.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSRemoteImpl.java index dea90177db13..ddbb23c9fff4 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSRemoteImpl.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/sps/impl/SPSRemoteImpl.java @@ -27,7 +27,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; -import java.security.acl.NotOwnerException; import java.util.Collection; import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; import java.util.logging.Level; @@ -38,8 +37,6 @@ import org.netbeans.modules.nativeexecution.spi.support.NativeExecutionUserNotification; import org.netbeans.modules.nativeexecution.support.Logger; import org.netbeans.modules.nativeexecution.support.MiscUtils; -//import org.openide.DialogDisplayer; -//import org.openide.NotifyDescriptor; import org.openide.util.NbBundle; public final class SPSRemoteImpl extends SPSCommonImpl { @@ -69,17 +66,16 @@ synchronized String getPID() { if (scriptRunner.execute() != 0) { throw new IOException("Unable to get sshd pid"); // NOI18N } - } catch (IOException ex) { + } catch (IOException | CancellationException ex) { + // TODO:CancellationException error processing Logger.getInstance().fine(ex.toString()); - } catch (CancellationException ex) { - Logger.getInstance().fine(ex.toString()); // TODO:CancellationException error processing } String pidCandidate = null; for (String line : blp.getBuffer()) { - line = line.trim(); - if (line.endsWith("sshd")) { // NOI18N + String trimmedLine = line.trim(); + if (trimmedLine.endsWith("sshd")) { // NOI18N try { pidCandidate = line.substring(0, line.indexOf(' ')); } catch (NumberFormatException ex) { @@ -118,12 +114,11 @@ public synchronized boolean requestPrivileges(Collection requestedPrivil cmd.append(user).append(" -c \""); // NOI18N cmd.append(script).append("\"; echo ExitStatus:$?\n"); // NOI18N - ChannelShell channel = null; PrintWriter w = null; int status = 1; try { - channel = (ChannelShell) ConnectionManagerAccessor.getDefault().openAndAcquireChannel(execEnv, "shell", true); // NOI18N+ + ChannelShell channel = (ChannelShell) ConnectionManagerAccessor.getDefault().openAndAcquireChannel(execEnv, "shell", true); // NOI18N+ if (channel == null) { return false; } @@ -164,11 +159,8 @@ public synchronized boolean requestPrivileges(Collection requestedPrivil if (status != 0) { if (!Boolean.getBoolean("nativeexecution.mode.unittest") && !"true".equals(System.getProperty("cnd.command.line.utility"))) { // NOI18N) NativeExecutionUserNotification.getDefault(). - notify(NbBundle.getMessage(SPSRemoteImpl.class, + notify(NbBundle.getMessage(SPSRemoteImpl.class, "TaskPrivilegesSupport_GrantPrivileges_Failed"));//NOI18N -// NotifyDescriptor dd = -// new NotifyDescriptor.Message(NbBundle.getMessage(SPSRemoteImpl.class, "TaskPrivilegesSupport_GrantPrivileges_Failed")); -// DialogDisplayer.getDefault().notify(dd); } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/InputRedirectorFactory.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/InputRedirectorFactory.java deleted file mode 100644 index 733d945a218d..000000000000 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/InputRedirectorFactory.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.nativeexecution.support; - -import java.io.Writer; -import org.netbeans.api.extexecution.ExecutionDescriptor; -import org.netbeans.api.extexecution.input.InputProcessor; -import org.netbeans.api.extexecution.input.InputProcessors; - - -/** - * - * @author ak119685 - */ -public class InputRedirectorFactory implements ExecutionDescriptor.InputProcessorFactory { - private final Writer writer; - - public InputRedirectorFactory(Writer writer) { - this.writer = writer; - } - - public InputProcessor newInputProcessor(InputProcessor defaultProcessor) { - return InputProcessors.copying(writer); - } - -} diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/filesearch/impl/LocalFileSearcherImpl.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/filesearch/impl/LocalFileSearcherImpl.java index 110361de30b1..7a3f7944ac08 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/filesearch/impl/LocalFileSearcherImpl.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/filesearch/impl/LocalFileSearcherImpl.java @@ -33,11 +33,11 @@ import org.netbeans.modules.nativeexecution.support.filesearch.FileSearcher; import org.openide.util.lookup.ServiceProvider; -@ServiceProvider(service = org.netbeans.modules.nativeexecution.support.filesearch.FileSearcher.class, position = 70) /** * In case of Windows use WINDOWS paths (c:\\mypath)... Also it requires exact * names (programm.exe and not just programm) */ +@ServiceProvider(service = org.netbeans.modules.nativeexecution.support.filesearch.FileSearcher.class, position = 70) public final class LocalFileSearcherImpl implements FileSearcher { private static final java.util.logging.Logger log = Logger.getInstance(); diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/UnixHostInfoProvider.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/UnixHostInfoProvider.java index 82b004149b8d..d73cd32a2a93 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/UnixHostInfoProvider.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/UnixHostInfoProvider.java @@ -61,21 +61,21 @@ public class UnixHostInfoProvider implements HostInfoProvider { private static final String PATH_VAR = "PATH"; // NOI18N private static final String PATH_TO_PREPEND = System.getProperty("hostinfo.prepend.path", null); // NOI18N private static final String ERROR_MESSAGE_PREFIX = "Error: TMPDIRBASE is not writable: "; // NOI18N - private static final java.util.logging.Logger log = Logger.getInstance(); - private static final File hostinfoScript; + private static final java.util.logging.Logger LOG = Logger.getInstance(); + private static final File HOSTINFO_SCRIPT; static { InstalledFileLocator fl = InstalledFileLocatorProvider.getDefault(); - hostinfoScript = fl.locate("bin/nativeexecution/hostinfo.sh", "org.netbeans.modules.dlight.nativeexecution", false); // NOI18N + HOSTINFO_SCRIPT = fl.locate("bin/nativeexecution/hostinfo.sh", "org.netbeans.modules.dlight.nativeexecution", false); // NOI18N - if (hostinfoScript == null) { - log.severe("Unable to find hostinfo.sh script!"); // NOI18N + if (HOSTINFO_SCRIPT == null) { + LOG.severe("Unable to find hostinfo.sh script!"); // NOI18N } } @Override public HostInfo getHostInfo(ExecutionEnvironment execEnv) throws IOException, InterruptedException { - if (hostinfoScript == null) { + if (HOSTINFO_SCRIPT == null) { return null; } @@ -94,7 +94,7 @@ public HostInfo getHostInfo(ExecutionEnvironment execEnv) throws IOException, In HostInfo result = HostInfoFactory.newHostInfo(execEnv, info, environment); if (execEnv.isLocal()) { - getLocalUserEnvironment(result, environment); + getLocalUserEnvironment(environment); } else { getRemoteUserEnvironment(execEnv, result, environment); } @@ -117,14 +117,14 @@ private Properties getLocalHostInfo() throws IOException { Properties hostInfo = new Properties(); ProcessBuilder pb = new ProcessBuilder("/bin/sh", // NOI18N - hostinfoScript.getAbsolutePath()); + HOSTINFO_SCRIPT.getAbsolutePath()); String tmpDirBase = null; if (TMPBASE != null) { if (pathIsOK(TMPBASE, false)) { tmpDirBase = TMPBASE; } else { - log.log(Level.WARNING, "Ignoring cnd.tmpbase property [{0}] as it contains illegal characters", TMPBASE); // NOI18N + LOG.log(Level.WARNING, "Ignoring cnd.tmpbase property [{0}] as it contains illegal characters", TMPBASE); // NOI18N } } @@ -148,7 +148,7 @@ private Properties getLocalHostInfo() throws IOException { int result = res.exitCode; for (String errLine : errorLines) { - log.log(Level.WARNING, "UnixHostInfoProvider: {0}", errLine); // NOI18N + LOG.log(Level.WARNING, "UnixHostInfoProvider: {0}", errLine); // NOI18N if (errLine.startsWith(ERROR_MESSAGE_PREFIX)) { String title = NbBundle.getMessage(UnixHostInfoProvider.class, "TITLE_PermissionDenied"); String shortMsg = NbBundle.getMessage(UnixHostInfoProvider.class, "SHORTMSG_PermissionDenied", tmpDirBase, "localhost"); @@ -158,7 +158,7 @@ private Properties getLocalHostInfo() throws IOException { } if (result != 0) { - throw new IOException(hostinfoScript + " rc == " + result); // NOI18N + throw new IOException(HOSTINFO_SCRIPT + " rc == " + result); // NOI18N } fillProperties(hostInfo, res.getOutputLines()); @@ -171,7 +171,7 @@ private Properties getRemoteHostInfo(final ExecutionEnvironment execEnv) throws ChannelStreams sh_channels = null; try { - log.log(Level.FINEST, "Getting remote host info for {0}", execEnv); // NOI18N + LOG.log(Level.FINEST, "Getting remote host info for {0}", execEnv); // NOI18N sh_channels = JschSupport.startCommand(execEnv, "/bin/sh -s", null); // NOI18N long localStartTime = System.currentTimeMillis(); @@ -186,41 +186,36 @@ private Properties getRemoteHostInfo(final ExecutionEnvironment execEnv) throws if (pathIsOK(TMPBASE, true)) { out.write(("TMPBASE=" + TMPBASE + '\n').getBytes()); // NOI18N } else { - log.log(Level.WARNING, "Ignoring cnd.tmpbase property [{0}] as it contains illegal characters", TMPBASE); // NOI18N + LOG.log(Level.WARNING, "Ignoring cnd.tmpbase property [{0}] as it contains illegal characters", TMPBASE); // NOI18N } } out.flush(); - BufferedReader scriptReader = new BufferedReader(new FileReader(hostinfoScript)); - String scriptLine = scriptReader.readLine(); + try (BufferedReader scriptReader = new BufferedReader(new FileReader(HOSTINFO_SCRIPT))) { + String scriptLine = scriptReader.readLine(); - while (scriptLine != null) { - out.write((scriptLine + '\n').getBytes()); - out.flush(); - scriptLine = scriptReader.readLine(); + while (scriptLine != null) { + out.write((scriptLine + '\n').getBytes()); + out.flush(); + scriptLine = scriptReader.readLine(); + } } - scriptReader.close(); - - NativeTaskExecutorService.submit(new Runnable() { - @Override - public void run() { - try { - BufferedReader errReader = new BufferedReader(new InputStreamReader(err)); - String errLine; - while ((errLine = errReader.readLine()) != null) { - log.log(Level.WARNING, "UnixHostInfoProvider: {0}", errLine); // NOI18N - if (errLine.startsWith(ERROR_MESSAGE_PREFIX)) { - errLine = errLine.replace(ERROR_MESSAGE_PREFIX, ""); - String title = NbBundle.getMessage(UnixHostInfoProvider.class, "TITLE_PermissionDenied"); - String shortMsg = NbBundle.getMessage(UnixHostInfoProvider.class, "SHORTMSG_PermissionDenied", errLine, execEnv); - String msg = NbBundle.getMessage(UnixHostInfoProvider.class, "MSG_PermissionDenied", errLine, execEnv); - MiscUtils.showNotification(title, shortMsg, msg); - } + NativeTaskExecutorService.submit(() -> { + try { + BufferedReader errReader = new BufferedReader(new InputStreamReader(err)); + for(String errLine = errReader.readLine(); errLine != null; errLine = errReader.readLine()) { + LOG.log(Level.WARNING, "UnixHostInfoProvider: {0}", errLine); // NOI18N + if (errLine.startsWith(ERROR_MESSAGE_PREFIX)) { + errLine = errLine.replace(ERROR_MESSAGE_PREFIX, ""); + String title = NbBundle.getMessage(UnixHostInfoProvider.class, "TITLE_PermissionDenied"); + String shortMsg = NbBundle.getMessage(UnixHostInfoProvider.class, "SHORTMSG_PermissionDenied", errLine, execEnv); + String msg = NbBundle.getMessage(UnixHostInfoProvider.class, "MSG_PermissionDenied", errLine, execEnv); + MiscUtils.showNotification(title, shortMsg, msg); } - } catch (IOException ex) { - ex.printStackTrace(System.err); } + } catch (IOException ex) { + ex.printStackTrace(System.err); } }, "reading hostInfo script error"); //NOPI18N // NOI18N @@ -228,7 +223,7 @@ public void run() { long localEndTime = System.currentTimeMillis(); - hostInfo.put("LOCALTIME", Long.valueOf((localStartTime + localEndTime) / 2)); // NOI18N + hostInfo.put("LOCALTIME", (localStartTime + localEndTime) / 2); // NOI18N } catch (JSchException ex) { throw new IOException("Exception while receiving HostInfo for " + execEnv.toString() + ": " + ex); // NOI18N } finally { @@ -265,9 +260,9 @@ private void getRemoteUserEnvironment(ExecutionEnvironment execEnv, HostInfo hos String nbstart = null; try { - nbstart = NbStartUtility.getInstance().getPath(execEnv, hostInfo); + nbstart = NbStartUtility.getInstance(execEnv.isLocal()).getPath(execEnv, hostInfo); } catch (IOException ex) { - log.log(Level.WARNING, "Failed to get remote path of NbStartUtility", ex); // NOI18N + LOG.log(Level.WARNING, "Failed to get remote path of NbStartUtility", ex); // NOI18N Exceptions.printStackTrace(ex); } @@ -295,7 +290,7 @@ private void getRemoteUserEnvironment(ExecutionEnvironment execEnv, HostInfo hos if (iex != null) { throw iex; } - log.log(Level.WARNING, "Failed to get getRemoteUserEnvironment for " + execEnv.getDisplayName(), ex); // NOI18N + LOG.log(Level.WARNING, "Failed to get getRemoteUserEnvironment for " + execEnv.getDisplayName(), ex); // NOI18N } finally { RemoteStatistics.stopChannelActivity(activityID); if (login_shell_channels != null) { @@ -311,16 +306,18 @@ private void getRemoteUserEnvironment(ExecutionEnvironment execEnv, HostInfo hos } InterruptedException toInterruptedException(Exception ex) { - if (ex instanceof InterruptedException) { - return (InterruptedException) ex; - } else if (ex.getCause() instanceof InterruptedException) { - return (InterruptedException) ex.getCause(); + if (ex == null) { + return null; + } else if (ex instanceof InterruptedException interruptedException) { + return interruptedException; + } else if (ex.getCause() instanceof InterruptedException interruptedException) { + return interruptedException; } InterruptedIOException iioe = null; - if (ex instanceof InterruptedIOException) { - iioe = (InterruptedIOException) ex; - } else if (ex.getCause() instanceof InterruptedIOException) { - iioe = (InterruptedIOException) ex.getCause(); + if (ex instanceof InterruptedIOException interruptedIOException) { + iioe = interruptedIOException; + } else if (ex.getCause() instanceof InterruptedIOException interruptedIOException) { + iioe = interruptedIOException; } if (iioe != null) { InterruptedException wrapper = new InterruptedException(ex.getMessage()); @@ -330,7 +327,7 @@ InterruptedException toInterruptedException(Exception ex) { return null; } - private void getLocalUserEnvironment(HostInfo hostInfo, Map environmentToFill) { + private void getLocalUserEnvironment(Map environmentToFill) { environmentToFill.putAll(System.getenv()); } @@ -366,18 +363,13 @@ private static List readProcessStream(final InputStream stream, boolean return Collections.emptyList(); } final List result = new LinkedList<>(); - final BufferedReader br = ProcessUtils.getReader(stream, remoteStream); - try { - String line; - while ((line = br.readLine()) != null) { + try (BufferedReader br = ProcessUtils.getReader(stream, remoteStream)) { + for(String line = br.readLine(); line != null; line = br.readLine()) { result.add(line); } - } finally { - if (br != null) { - br.close(); - } } + return result; } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/WindowsHostInfoProvider.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/WindowsHostInfoProvider.java index 9b6967682075..95b9e5fc9121 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/WindowsHostInfoProvider.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/hostinfo/impl/WindowsHostInfoProvider.java @@ -32,6 +32,7 @@ import org.netbeans.modules.nativeexecution.api.util.ProcessUtils; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils.ExitStatus; import org.netbeans.modules.nativeexecution.api.util.Shell; +import org.netbeans.modules.nativeexecution.api.util.Shell.ShellType; import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; import org.netbeans.modules.nativeexecution.pty.NbStartUtility; import org.netbeans.modules.nativeexecution.support.Logger; @@ -58,7 +59,7 @@ public HostInfo getHostInfo(ExecutionEnvironment execEnv) throws IOException, In Shell activeShell = WindowsSupport.getInstance().getActiveShell(); if (activeShell != null && Shell.ShellType.CYGWIN.equals(activeShell.type)) { - String nbstart = NbStartUtility.getInstance().getPath(execEnv, info); + String nbstart = NbStartUtility.getInstance(execEnv.isLocal()).getPath(execEnv, info); String envPath = info.getEnvironmentFile(); if (nbstart != null && envPath != null) { ProcessBuilder pb = new ProcessBuilder(nbstart, "--dumpenv", envPath); // NOI18N @@ -109,7 +110,7 @@ private static class HostInfoImpl implements HostInfo { try { _cpuNum = Integer.parseInt(env.get("NUMBER_OF_PROCESSORS")); // NOI18N - } catch (Exception ex) { + } catch (RuntimeException ex) { } cpuNum = _cpuNum; @@ -211,40 +212,10 @@ public void initTmpDirs() throws IOException { } public void initUserDirs() throws IOException { - File _userDirFile = null; - String _userDir = null; String ioUserDir = System.getProperty("user.home"); // NOI18N - /** - * Some magic with temp dir... In case of non-ascii chars in - * username use hashcode instead of plain name as in case of MinGW - * (without cygwin) execution may (will) fail... - */ - String username = environment.get("USERNAME"); // NOI18N - - if (username != null) { - for (int i = 0; i < username.length(); i++) { - char c = username.charAt(i); - - if (Character.isDigit(c) || c == '_') { - continue; - } - - if (c >= 'A' && c <= 'Z') { - continue; - } - - if (c >= 'a' && c <= 'z') { - continue; - } - - username = "" + username.hashCode(); // NOI18N - break; - } - } - - _userDirFile = new File(ioUserDir); // NOI18N - _userDir = _userDirFile.getAbsolutePath(); + File _userDirFile = new File(ioUserDir); + String _userDir = _userDirFile.getAbsolutePath(); if (shell != null) { _userDir = WindowsSupport.getInstance().convertToShellPath(_userDir); @@ -316,6 +287,7 @@ public long getClockSkew() { } @Override + @SuppressWarnings("ReturnOfCollectionOrArrayField") public Map getEnvironment() { return environment; } @@ -376,7 +348,12 @@ private boolean checkForNonLatin(String str) { @Override public String getEnvironmentFile() { - return getTempDir() + "/env"; // NOI18N + Shell activeShell = WindowsSupport.getInstance().getActiveShell(); + if(activeShell != null && activeShell.type == ShellType.WSL) { + return null; + } else { + return getTempDir() + "/env"; // NOI18N + } } } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/PathConverter.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/PathConverter.java index ccb0835128e7..f090bf4a1f7f 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/PathConverter.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/PathConverter.java @@ -32,6 +32,7 @@ public static enum PathType { CYGWIN, MSYS, - WINDOWS + WINDOWS, + WSL } } diff --git a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/SimpleConverter.java b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/SimpleConverter.java index 9dd2057010bd..60ecf6f45a85 100644 --- a/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/SimpleConverter.java +++ b/ide/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/windows/SimpleConverter.java @@ -19,14 +19,10 @@ package org.netbeans.modules.nativeexecution.support.windows; import java.io.File; -import java.io.IOException; -import java.util.logging.Level; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils; import org.netbeans.modules.nativeexecution.api.util.Shell; import org.netbeans.modules.nativeexecution.api.util.Shell.ShellType; import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; -import org.netbeans.modules.nativeexecution.support.Logger; -import org.openide.util.Exceptions; /** * @@ -52,7 +48,14 @@ public String convert(PathType srcType, PathType trgType, String path) { String result = path; if (trgType == PathType.WINDOWS) { - String prefix = srcType == PathType.CYGWIN ? cygwinPrefix : "/"; // NOI18N + String prefix; + if (srcType == PathType.CYGWIN) { + prefix = cygwinPrefix; + } else if (srcType == PathType.WSL) { + prefix = "/mnt/"; // NOI18N + } else { + prefix = "/"; // NOI18N + } int plen = prefix.length(); if (path.length() > plen && path.startsWith(prefix)) { result = path.charAt(plen) + ":"; // NOI18N @@ -63,10 +66,22 @@ public String convert(PathType srcType, PathType trgType, String path) { return result.replace('/', '\\'); // NOI18N } - String prefix = trgType == PathType.CYGWIN ? cygwinPrefix : "/"; // NOI18N + String prefix; + if (trgType == PathType.CYGWIN) { + prefix = cygwinPrefix; + } else if (trgType == PathType.WSL) { + prefix = "/mnt/"; // NOI18N + } else { + prefix = "/"; // NOI18N + } + // At least cygwin and wsl use lowercase directory names for drive + // mapping. While cygwin has case insensitive behavior, at least Ubuntu + // on WSL show case sensitve behavior. if (path.length() > 2 && path.charAt(1) == ':') { - result = prefix + result.replaceFirst(":", ""); // NOI18N + result = prefix + + path.substring(0, 1).toLowerCase() + + path.substring(2); } return result.replace('\\', '/'); // NOI18N diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/IZ182478.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/IZ182478.java index 99e085316311..e37e3e1497c3 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/IZ182478.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/IZ182478.java @@ -26,6 +26,7 @@ import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory; import org.netbeans.modules.nativeexecution.api.HostInfo; import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder; +import org.netbeans.modules.nativeexecution.api.util.ConnectionManager; import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils; import org.netbeans.modules.nativeexecution.api.util.ProcessUtils.ExitStatus; @@ -49,12 +50,14 @@ public void test_perform() { try { info = HostInfoUtils.getHostInfo(env); - } catch (Exception ex) { + } catch (IOException | ConnectionManager.CancellationException | RuntimeException ex) { Exceptions.printStackTrace(ex); } assertNotNull("HostInfo for localhost is unavailable", info); // NOI18N + assert info != null; + if (info.getOSFamily() != HostInfo.OSFamily.SUNOS) { System.out.println("Skip this test on " + info.getOSFamily().name()); return; @@ -102,24 +105,20 @@ private int countShells(String shell, String output) { return count; } + @SuppressWarnings("SleepWhileInLoop") private void startLoop() { int count = 30; RequestProcessor rp = new RequestProcessor("IZ182478", 1); for (int i = 0; i < count; i++) { - Future task = rp.submit(new Runnable() { - - @Override - public void run() { - NativeProcessBuilder npb = NativeProcessBuilder.newLocalProcessBuilder(); - npb.setExecutable("/bin/echo").setArguments("XXX"); - - try { - npb.call(); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } - + Future task = rp.submit(() -> { + NativeProcessBuilder npb = NativeProcessBuilder.newLocalProcessBuilder(); + npb.setExecutable("/bin/echo").setArguments("XXX"); + + try { + npb.call(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); } }); diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NativeTaskTest.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NativeTaskTest.java index 3d4e1091c60d..c7419d3a918b 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NativeTaskTest.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NativeTaskTest.java @@ -21,14 +21,10 @@ import org.netbeans.modules.nativeexecution.ConcurrentTasksSupport.Counters; import org.netbeans.modules.nativeexecution.test.NativeExecutionBaseTestCase; import java.io.IOException; -import java.io.Writer; import java.util.concurrent.CountDownLatch; import junit.framework.Test; import org.junit.AfterClass; import org.junit.BeforeClass; -import org.netbeans.api.extexecution.ExecutionDescriptor; -import org.netbeans.api.extexecution.input.InputProcessor; -import org.netbeans.api.extexecution.input.InputProcessors; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironmentFactory; import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder; @@ -72,29 +68,6 @@ public void tearDown() throws Exception { super.tearDown(); } -// public void testSimple() { -// ExternalTerminal term = ExternalTerminalProvider.getTerminal(ExecutionEnvironmentFactory.getLocal(), "gnome-terminal"); // NOI18N -// NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(ExecutionEnvironmentFactory.getLocal()); -// npb.setExecutable("/bin/ls").useExternalTerminal(term); // NOI18N -// StringWriter result = new StringWriter(); -// ExecutionDescriptor descriptor = new ExecutionDescriptor().inputOutput(InputOutput.NULL).outProcessorFactory(new InputRedirectorFactory(result)); -// ExecutionService execService = ExecutionService.newService( -// npb, descriptor, "Demangling function "); // NOI18N -// -// Future res = execService.run(); -// -// try { -// System.out.println("Result: " + res.get()); // NOI18N -// } catch (InterruptedException ex) { -// Exceptions.printStackTrace(ex); -// } catch (ExecutionException ex) { -// Exceptions.printStackTrace(ex); -// } -// -// System.out.println(result.toString()); -// } - -// @Test private static final String CNT_OUT_MATCH = "Output matches"; // NOI18N private static final String CNT_EXECUTION_SUCCESS = "Successful execution"; // NOI18N private static final String CNT_TASKS = "Tasks submitted"; // NOI18N @@ -140,7 +113,7 @@ private static final class Worker implements Runnable { private final CountDownLatch start; private final CountDownLatch latch; - private Counters counters; + private final Counters counters; public Worker(ConcurrentTasksSupport.Counters counters, CountDownLatch latch, CountDownLatch start) { this.start = start; @@ -178,6 +151,7 @@ private void doit() { } } + @Override public void run() { try { start.await(); @@ -191,17 +165,4 @@ public void run() { } } - private static class InputRedirectorFactory implements ExecutionDescriptor.InputProcessorFactory { - - private final Writer writer; - - public InputRedirectorFactory(Writer writer) { - this.writer = writer; - } - - public InputProcessor newInputProcessor(InputProcessor defaultProcessor) { - return InputProcessors.copying(writer); - } - } - } diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NbStartLocalTest.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NbStartLocalTest.java index 2a11a72eb3a4..cae4d796bf32 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NbStartLocalTest.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/NbStartLocalTest.java @@ -78,7 +78,7 @@ public void setUp() throws Exception { @Override public boolean canRun() { boolean res = super.canRun(); - res = res && NbStartUtility.getInstance().isSupported(env); + res = res && NbStartUtility.getInstance(true).isSupported(env); return res; } diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManagerTest.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManagerTest.java index 8e17b89ceaec..a6083355095d 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManagerTest.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ConnectionManagerTest.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.List; import org.junit.Test; +import org.junit.Ignore; import org.netbeans.junit.RandomlyFails; import org.netbeans.modules.nativeexecution.ConcurrentTasksSupport; import org.netbeans.modules.nativeexecution.ConcurrentTasksSupport.Counters; @@ -52,7 +53,7 @@ public ConnectionManagerTest(String name, ExecutionEnvironment testExecutionEnvi public static junit.framework.Test suite() { return new NativeExecutionBaseTestSuite(ConnectionManagerTest.class); } - + @Test public void testDeleteConnection() throws Exception { ExecutionEnvironment env = ExecutionEnvironmentFactory.createNew("test","127.0.0.1"); @@ -65,6 +66,7 @@ public void testDeleteConnection() throws Exception { } @Test + @Ignore("requires remote system") public void testGetRecentConnections() throws Exception { String section = "remote.platforms"; ExecutionEnvironment[] envs = NativeExecutionTestSupport.getTestExecutionEnvironmentsFromSection(section); @@ -119,6 +121,7 @@ public void testConnectDisconnect() throws Exception { } @Test + @Ignore("requires remote system") public void testGetConnectToAction() throws Exception { final int threadsNum = 10; RcFile rcFile = NativeExecutionTestSupport.getRcFile(); diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ParallelSftpTest.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ParallelSftpTest.java index 3c072eee1a09..d11d780a3d71 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ParallelSftpTest.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/api/util/ParallelSftpTest.java @@ -45,9 +45,9 @@ * @author Vladimir Kvashin */ public class ParallelSftpTest extends NativeExecutionBaseTestCase { - + private final Writer errorWriter = new PrintWriter(System.err); - + public ParallelSftpTest(String name, ExecutionEnvironment testExecutionEnvironment) { super(name, testExecutionEnvironment); } @@ -56,13 +56,13 @@ public ParallelSftpTest(String name, ExecutionEnvironment testExecutionEnvironme public void testMultipleDownload() throws Exception { int taskCount = 200; int concurrencyLevel = 10; - SftpSupport.testSetConcurrencyLevel(concurrencyLevel); + SftpSupport.testSetConcurrencyLevel(concurrencyLevel); ExecutionEnvironment env = getTestExecutionEnvironment(); ConnectionManager.getInstance().connectTo(env); File localTmpDir = createTempFile("parallel", "upload", true); long time = System.currentTimeMillis(); - try { - @SuppressWarnings("unchecked") + try { + @SuppressWarnings({"unchecked", "rawtypes"}) Future[] tasks = (Future[]) (new Future[taskCount]); File[] files = new File[taskCount]; for (int i = 0; i < taskCount; i++) { @@ -75,8 +75,8 @@ public void testMultipleDownload() throws Exception { } finally { time = System.currentTimeMillis() - time; removeDirectory(localTmpDir); - } - System.err.printf("%d downloads took %d seconds; declared concurrency level: %d; max. SFTP busy channels: %d\n", + } + System.err.printf("%d downloads took %d seconds; declared concurrency level: %d; max. SFTP busy channels: %d\n", taskCount, time/1000, concurrencyLevel, SftpSupport.getInstance(env).getMaxBusyChannels()); //System.err.printf("Max. SFTP busy channels: %d\n", SftpSupport.getInstance(env).getMaxBusyChannels()); } @@ -85,16 +85,16 @@ public void testMultipleDownload() throws Exception { private static StatInfo[] ls(ExecutionEnvironment env, String remoteDir) throws Exception { Future lsTask = FileInfoProvider.ls(env, remoteDir); StatInfo[] ls = lsTask.get(); - assertTrue("too few elements in ls /usr/include RC", ls.length > 10); + assertTrue("too few elements in ls /usr/include RC", ls.length > 10); List result = new ArrayList<>(ls.length); for (int i = 0; i < ls.length; i++) { if(!ls[i].isDirectory() && ! ls[i].isLink()) { result.add(ls[i]); - } + } } - return result.toArray(new StatInfo[0]); + return result.toArray(StatInfo[]::new); } - + @ForAllEnvironments(section = "remote.platforms") public void testParallelMultyDownload() throws Exception { final int threadCount = 10; @@ -105,45 +105,39 @@ public void testParallelMultyDownload() throws Exception { final File localTmpDir = createTempFile("parallel", "upload", true); final String remoteDir = "/usr/include"; final StatInfo[] ls = ls(env, remoteDir); - assertTrue("too few elements in ls /usr/include RC", ls.length > 10); + assertTrue("too few elements in ls /usr/include RC", ls.length > 10); long time = System.currentTimeMillis(); - try { - @SuppressWarnings("unchecked") + try { + @SuppressWarnings({"unchecked", "rawtypes"}) final Future[][] tasks = (Future[][]) (new Future[threadCount][ls.length]); - final File[][] files = new File[threadCount][ls.length]; + final File[][] files = new File[threadCount][ls.length]; final CyclicBarrier barrier = new CyclicBarrier(threadCount); Thread[] threads = new Thread[threadCount]; final Exception[] threadExceptions = new Exception[threadCount]; for (int i = 0; i < threadCount; i++) { final int currThread = i; final String threadName = "SFTP parallel download test thread #" + currThread; - threads[currThread] = new Thread(new Runnable() { - @Override - public void run() { + threads[currThread] = new Thread(() -> { + try { + System.err.printf("%s waiting on barrier\n", threadName); + barrier.await(); + System.err.printf("%s started\n", threadName); try { - System.err.printf("%s waiting on barrier\n", threadName); - barrier.await(); - System.err.printf("%s started\n", threadName); - try { - for (int currFile = 0; currFile < ls.length; currFile++ ) { - String name = ls[currFile].getName(); - files[currThread][currFile] = new File(localTmpDir, name + '.' + currThread); - tasks[currThread][currFile] = CommonTasksSupport.downloadFile(remoteDir + '/' + name, env, files[currThread][currFile], errorWriter); - } - } finally { - System.err.printf("%s finished\n", threadName); + for (int currFile = 0; currFile < ls.length; currFile++ ) { + String name = ls[currFile].getName(); + files[currThread][currFile] = new File(localTmpDir, name + '.' + currThread); + tasks[currThread][currFile] = CommonTasksSupport.downloadFile(remoteDir + '/' + name, env, files[currThread][currFile], errorWriter); } - } catch (InterruptedException ex) { - threadExceptions[currThread] = ex; - Exceptions.printStackTrace(ex); - } catch (BrokenBarrierException ex) { - threadExceptions[currThread] = ex; - Exceptions.printStackTrace(ex); + } finally { + System.err.printf("%s finished\n", threadName); } + } catch (InterruptedException | BrokenBarrierException ex) { + threadExceptions[currThread] = ex; + Exceptions.printStackTrace(ex); } }, threadName); } - + for (int i = 0; i < threadCount; i++) { threads[i].start(); } @@ -151,24 +145,24 @@ public void run() { for (int i = 0; i < threadCount; i++) { threads[i].join(); } - + for (int i = 0; i < threadCount; i++) { if (threadExceptions[i] != null) { throw threadExceptions[i]; } } - + for (int currLap = 0; currLap < threadCount; currLap++) { for (int currFile = 0; currFile < ls.length; currFile++ ) { assertEquals("RC for file " + files[currLap][currFile].getName() + " lap #" + currLap, 0, tasks[currLap][currFile].get().intValue()); } } - + } finally { time = System.currentTimeMillis() - time; removeDirectory(localTmpDir); - } - System.err.printf("Downloading from %s; %d threads %d files each took %d seconds; declared concurrency level: %d; max. SFTP busy channels: %d\n", + } + System.err.printf("Downloading from %s; %d threads %d files each took %d seconds; declared concurrency level: %d; max. SFTP busy channels: %d\n", remoteDir, threadCount, ls.length, time/1000, concurrencyLevel, SftpSupport.getInstance(env).getMaxBusyChannels()); //System.err.printf("Max. SFTP busy channels: %d\n", SftpSupport.getInstance(env).getMaxBusyChannels()); } @@ -184,32 +178,32 @@ private void gatherPlainFiles(File dir, Collection result, Set sho } } } - + private File[] getNetBeansPlatformPlainFiles() throws Exception { List result = new ArrayList<>(); File platformDir = getNetBeansPlatformDir(); assertNotNull("netbeans platform dir", platformDir); - gatherPlainFiles(platformDir, result, new TreeSet()); - return result.toArray(new File[0]); + gatherPlainFiles(platformDir, result, new TreeSet<>()); + return result.toArray(File[]::new); } - + @RandomlyFails @ForAllEnvironments(section = "remote.platforms") - public void testParallelUpload() throws Exception { + public void testParallelUpload() throws Exception { final int threadCount = 10; int concurrencyLevel = 10; - SftpSupport.testSetConcurrencyLevel(concurrencyLevel); + SftpSupport.testSetConcurrencyLevel(concurrencyLevel); final ExecutionEnvironment env = getTestExecutionEnvironment(); ConnectionManager.getInstance().connectTo(env); final File[] files = getNetBeansPlatformPlainFiles(); final String remoteDir = createRemoteTmpDir(); - long time = System.currentTimeMillis(); - try { - @SuppressWarnings("unchecked") + long time = System.currentTimeMillis(); + try { + @SuppressWarnings({"unchecked", "rawtypes"}) final Future[][] tasks = (Future[][]) (new Future[threadCount][files.length]); Thread[] threads = new Thread[threadCount]; final Exception[] threadExceptions = new Exception[threadCount]; - final CyclicBarrier barrier = new CyclicBarrier(threadCount); + final CyclicBarrier barrier = new CyclicBarrier(threadCount); for (int i = 0; i < threadCount; i++) { final int currThread = i; final String threadName = "SFTP parallel upload test thread #" + currThread; @@ -222,24 +216,21 @@ public void run() { System.err.printf("%s started\n", threadName); try { for (int currFile = 0; currFile < files.length; currFile++ ) { - String name = files[currFile].getName(); + String name = files[currFile].getName(); tasks[currThread][currFile] = CommonTasksSupport.uploadFile( files[currFile], env, remoteDir + '/' + name /*+ '.' + currLap*/, 0600); } } finally { System.err.printf("%s finished\n", threadName); } - } catch (InterruptedException ex) { - threadExceptions[currThread] = ex; - Exceptions.printStackTrace(ex); - } catch (BrokenBarrierException ex) { + } catch (InterruptedException | BrokenBarrierException ex) { threadExceptions[currThread] = ex; Exceptions.printStackTrace(ex); } } }, threadName); } - + for (int i = 0; i < threadCount; i++) { threads[i].start(); } @@ -247,17 +238,17 @@ public void run() { for (int i = 0; i < threadCount; i++) { threads[i].join(); } - + for (int i = 0; i < threadCount; i++) { if (threadExceptions[i] != null) { throw threadExceptions[i]; } } - + for (int currLap = 0; currLap < threadCount; currLap++) { for (int currFile = 0; currFile < files.length; currFile++ ) { UploadStatus res = tasks[currLap][currFile].get(); - assertEquals("RC for file " + files[currFile].getName() + " lap #" + currLap + " error:" + res.getError(), + assertEquals("RC for file " + files[currFile].getName() + " lap #" + currLap + " error:" + res.getError(), 0, res.getExitCode()); } } @@ -265,13 +256,13 @@ public void run() { time = System.currentTimeMillis() - time; runScript("rm -rf " + remoteDir); //runCommand("rm", "rf", remoteDir); - } - System.err.printf("Uploading to %s; %d threads %d files each took %d seconds; declared concurrency level: %d; max. SFTP busy channels: %d\n", + } + System.err.printf("Uploading to %s; %d threads %d files each took %d seconds; declared concurrency level: %d; max. SFTP busy channels: %d\n", remoteDir, threadCount, files.length, time/1000, concurrencyLevel, SftpSupport.getInstance(env).getMaxBusyChannels()); } - + @SuppressWarnings("unchecked") public static Test suite() { return new NativeExecutionBaseTestSuite(ParallelSftpTest.class); - } + } } diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestCase.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestCase.java index c0fe1200a40f..a4ba32678054 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestCase.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestCase.java @@ -18,24 +18,19 @@ */ package org.netbeans.modules.nativeexecution.test; -import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Writer; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; import java.net.ConnectException; import java.net.URISyntaxException; import java.nio.file.Files; @@ -69,38 +64,32 @@ import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; import org.netbeans.modules.nativeexecution.support.MiscUtils; import org.netbeans.modules.nativeexecution.test.RcFile.FormatException; -import org.openide.filesystems.FileAttributeEvent; -import org.openide.filesystems.FileChangeListener; -import org.openide.filesystems.FileEvent; import org.openide.filesystems.FileObject; -import org.openide.filesystems.FileRenameEvent; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.openide.util.Lookup; -import org.openide.util.NotImplementedException; +import org.openide.util.Utilities; public class NativeExecutionBaseTestCase extends NbTestCase { static { // Setting netbeans.dirs makes installedFileLocator work properly System.setProperty("netbeans.dirs", NbClustersInfoProvider.getClusters()); System.setProperty("remote.user.password.keep_in_memory", "true"); // NOI18N - System.setProperty("cnd.mode.unittest", "true"); + System.setProperty("cnd.mode.unittest", "true"); } - protected static class TestLogHandler extends Handler { + private static class TestLogHandler extends Handler { protected final Logger log; - @Deprecated - public TestLogHandler(Logger log) { + private TestLogHandler(Logger log) { this.log = log; } - + public static void attach(Logger log) { log.addHandler(new TestLogHandler((log))); } - - + @Override public void publish(LogRecord record) { // Log if parent cannot log the message ONLY. @@ -129,90 +118,14 @@ public void close() throws SecurityException { } - protected static class DumpingFileChangeListener implements FileChangeListener { - public static final String FILE_ATTRIBUTE_CHANGED = "fileAttributeChanged"; - public static final String FILE_CHANGED = "fileChanged"; - public static final String FILE_DATA_CREATED = "fileDataCreated"; - public static final String FILE_DELETED = "fileDeleted"; - public static final String FILE_FOLDER_CREATED = "fileFolderCreated"; - public static final String FILE_RENAMED = "fileRenamed"; - - private final String listenerName; - private final String prefixToStrip; - private final PrintStream out; - private final boolean checkExpected; - - public DumpingFileChangeListener(String name, String prefixToStrip, PrintStream out, boolean checkExpected) { - this.listenerName = name; - this.prefixToStrip = prefixToStrip; - this.out = out; - this.checkExpected = checkExpected; - } - - protected void register(String eventKind, FileEvent fe) { - String src = stripPrefix(((FileObject) fe.getSource()).getPath()); - String obj = stripPrefix(fe.getFile().getPath()); - String exp = checkExpected ? ("exp=" + Boolean.toString(fe.isExpected())) : ""; - String extra = ""; - if (fe instanceof FileRenameEvent) { - FileRenameEvent fre = (FileRenameEvent) fe; - extra = "oldName="+fre.getName()+" oldExt="+fre.getExt(); - } - out.printf("%-20s: %-20s SRC %-20s OBJ %-20s %s %s\n", listenerName, eventKind, src, obj, exp, extra); - } - - private String stripPrefix(String path) { - if (path.startsWith(prefixToStrip)) { - path = path.substring(prefixToStrip.length()); - if (path.startsWith("/")) { - path = path.substring(1); - } - } - if (path.length() == 0) { - path = "."; - } - return path; - } - - @Override - public void fileAttributeChanged(FileAttributeEvent fe) { - register(FILE_ATTRIBUTE_CHANGED, fe); - } - - @Override - public void fileChanged(FileEvent fe) { - register(FILE_CHANGED, fe); - } - - @Override - public void fileDataCreated(FileEvent fe) { - register(FILE_DATA_CREATED, fe); - } - - @Override - public void fileDeleted(FileEvent fe) { - register(FILE_DELETED, fe); - } - - @Override - public void fileFolderCreated(FileEvent fe) { - register(FILE_FOLDER_CREATED, fe); - } - - @Override - public void fileRenamed(FileRenameEvent fe) { - register(FILE_RENAMED, fe); - } - } - static { TestLogHandler.attach(org.netbeans.modules.nativeexecution.support.Logger.getInstance()); - + // the 3 lines below contain a workaround for some WinXP tests failure File tmpDir = new File(System.getProperty("java.io.tmpdir")); tmpDir = FileUtil.normalizeFile(tmpDir.getAbsoluteFile()); System.setProperty("java.io.tmpdir", tmpDir.getAbsolutePath()); - + Logger fsLogger = Logger.getLogger("org.netbeans.modules.masterfs.watcher.Watcher"); fsLogger.setLevel(Level.WARNING); } @@ -220,7 +133,8 @@ public void fileRenamed(FileRenameEvent fe) { private final ExecutionEnvironment testExecutionEnvironment; private String remoteTmpDir; private Level oldLevel = null; - + + @SuppressWarnings("this-escape") public NativeExecutionBaseTestCase(String name) { super(name); System.setProperty("nativeexecution.mode.unittest", "true"); @@ -234,12 +148,13 @@ public NativeExecutionBaseTestCase(String name) { * @param testExecutionEnvironment */ /*protected - feel free to make it public in the case you REALLY need this */ + @SuppressWarnings("this-escape") protected NativeExecutionBaseTestCase(String name, ExecutionEnvironment testExecutionEnvironment) { super(name); System.setProperty("nativeexecution.mode.unittest", "true"); this.testExecutionEnvironment = testExecutionEnvironment; assertNotNull(testExecutionEnvironment); - setupUserDir(); + setupUserDir(); } @Override @@ -254,11 +169,11 @@ protected void tearDown() throws Exception { super.tearDown(); setLoggers(false); } - + private void setLoggers(boolean setup) { if (setup) { if (NativeExecutionTestSupport.getBoolean("execution", "logging.finest") - || NativeExecutionTestSupport.getBoolean("execution", getClass().getName() + ".logging.finest")) { + || NativeExecutionTestSupport.getBoolean("execution", getClass().getName() + ".logging.finest")) { oldLevel = org.netbeans.modules.nativeexecution.support.Logger.getInstance().getLevel(); org.netbeans.modules.nativeexecution.support.Logger.getInstance().setLevel(Level.ALL); } @@ -292,7 +207,7 @@ private void setupProperties() throws IOException, FormatException { String value = rcFile.get(section, key); System.setProperty(key, value); } - } + } @Override protected int timeOut() { @@ -311,7 +226,7 @@ protected RcFile getLocalRcFile() throws IOException, RcFile.FormatException { return NativeExecutionTestSupport.getRcFile(); } - protected RcFile getRemoteRcFile() + protected RcFile getRemoteRcFile() throws IOException, RcFile.FormatException, ConnectException, ConnectionManager.CancellationException, InterruptedException, ExecutionException { return NativeExecutionTestSupport.getRemoteRcFile(getTestExecutionEnvironment()); @@ -332,15 +247,15 @@ public String getName() { return String.format("%s [%s]", name, env); } } - + private static boolean ignoreRandomFailures() { return Boolean.getBoolean("ignore.random.failures"); } - + private static boolean randomFailsOnly() { return Boolean.getBoolean("random.failures.only"); } - + private boolean isRandomFail() { if (getClass().isAnnotationPresent(RandomlyFails.class)) { return true; @@ -362,7 +277,7 @@ public boolean canRun() { if (randomFailsOnly()) { return isRandomFail(); } - + res = res && super.canRun(); if (!res) { return false; @@ -389,16 +304,16 @@ protected String runCommand(ExecutionEnvironment env, String command, String... protected String runCommandInDir(String dir, String command, String... args) throws Exception { return runCommandInDir(getTestExecutionEnvironment(), dir, command, args); - + } - + protected String runCommandInDir(ExecutionEnvironment env, String dir, String command, String... args) throws Exception { ProcessUtils.ExitStatus res = ProcessUtils.executeInDir(dir, env, command, args); assertTrue("Command \"" + command + ' ' + stringArrayToString(args) + "\" in dir " + dir + " failed", res.isOK()); return res.getOutputString(); } - + /** * Creates a directory structure described by parameters * @@ -418,6 +333,7 @@ protected String runCommandInDir(ExecutionEnvironment env, String dir, String co public static void createDirStructure(ExecutionEnvironment env, String baseDir, String[] creationData) throws Exception { createDirStructure(env, baseDir, creationData, true); } + @SuppressWarnings("AssignmentToMethodParameter") public static void createDirStructure(ExecutionEnvironment env, String baseDir, String[] creationData, boolean cleanOld) throws Exception { if (baseDir == null || baseDir.length() == 0 || baseDir.equals("/")) { throw new IllegalArgumentException("Illegal base dir: " + baseDir); @@ -448,28 +364,19 @@ public static void createDirStructure(ExecutionEnvironment env, String baseDir, } } switch (data.charAt(0)) { - case '-': - script.append("touch \"").append(path).append("\";\n"); - break; - case 'd': - script.append("mkdir -p \"").append(path).append("\";\n"); - break; - case 'l': + case '-' -> script.append("touch \"").append(path).append("\";\n"); + case 'd' -> script.append("mkdir -p \"").append(path).append("\";\n"); + case 'l' -> { String link = parts[2]; script.append("ln -s \"").append(path).append("\" \"").append(link).append("\";\n"); - break; - case 'R': - script.append("rm -rf \"").append(path).append("\";\n"); - break; - case 'T': - script.append("touch \"").append(path).append("\";\n"); - break; - case 'M': + } + case 'R' -> script.append("rm -rf \"").append(path).append("\";\n"); + case 'T' -> script.append("touch \"").append(path).append("\";\n"); + case 'M' -> { String dst = parts[2]; script.append("mv \"").append(path).append("\" \"").append(dst).append("\";\n"); - break; - default: - throw new IllegalArgumentException("Unexpected 1-st char: " + data); + } + default -> throw new IllegalArgumentException("Unexpected 1-st char: " + data); } } } catch (Throwable thr) { @@ -482,7 +389,7 @@ public static void createDirStructure(ExecutionEnvironment env, String baseDir, assertTrue("script failed at " + env.getDisplayName() + " rc=" + res.exitCode + " err=" + res.getErrorString(), false); } } - + private String stringArrayToString(String[] args) { StringBuilder sb = new StringBuilder(); for (String arg : args) { @@ -490,13 +397,14 @@ private String stringArrayToString(String[] args) { } return sb.toString(); } - + protected String runScript(String script) throws Exception { return runScript(getTestExecutionEnvironment(), script); } protected String runScript(ExecutionEnvironment env, String script) throws Exception { - final StringBuilder output = new StringBuilder(); + final StringBuilder output = new StringBuilder(); + @SuppressWarnings("deprecation") ShellScriptRunner scriptRunner = new ShellScriptRunner(env, script, new LineProcessor() { @Override public void processLine(String line) { @@ -512,7 +420,7 @@ public void close() {} assertEquals("Error running script", 0, rc); return output.toString(); } - + protected boolean canRead(ExecutionEnvironment env, String path) throws Exception { NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(env); npb.setExecutable("test").setArguments("-r", path); @@ -532,35 +440,23 @@ protected boolean canExecute(ExecutionEnvironment env, String path) throws Excep } public static void writeFile(File file, CharSequence content) throws IOException { - Writer writer = new FileWriter(file); - try { + try (Writer writer = new FileWriter(file)) { writer.write(content.toString()); - } finally { - writer.close(); } } - + protected static void writeFile(FileObject fo, CharSequence content) throws IOException { - BufferedWriter bw = null; - try { - bw = new BufferedWriter(new OutputStreamWriter(fo.getOutputStream())); + try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fo.getOutputStream()))) { bw.append(content); - } finally { - if (bw != null) { - bw.close(); - } } } public static void writeFile(File file, List lines) throws IOException { - Writer writer = new FileWriter(file); - try { + try (Writer writer = new FileWriter(file)) { for (CharSequence line : lines) { writer.write(line.toString()); writer.write('\n'); } - } finally { - writer.close(); } } @@ -569,35 +465,26 @@ public void sortFile(File file) throws IOException { Collections.sort(lines); writeFile(file, lines); } - + private List readFileLines(File file) throws IOException { - BufferedReader r = new BufferedReader(new FileReader(file)); - try { + try (BufferedReader r = new BufferedReader(new FileReader(file));) { List lines = new ArrayList<>(); - String line; - while ((line = r.readLine()) != null) { + for(String line = r.readLine(); line != null; line = r.readLine()) { lines.add(line); } return lines; - } finally { - if (r != null) { - try { - r.close(); - } catch (IOException e) {} - } } } public static String readStream(InputStream is) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); StringBuilder sb = new StringBuilder(); - char buf[] = new char[4096]; - int cnt = 0; - while ((cnt = reader.read(buf)) != -1) { - String text = String.valueOf(buf, 0, cnt); - sb.append(text); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + char buf[] = new char[4096]; + for(int cnt = reader.read(buf); cnt != -1; cnt = reader.read(buf)) { + String text = String.valueOf(buf, 0, cnt); + sb.append(text); + } } - reader.close(); return sb.toString(); } @@ -674,7 +561,7 @@ protected File getNetBeansPlatformDir() throws URISyntaxException { } protected File getIdeUtilJar() throws URISyntaxException { - return new File(Lookup.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + return Utilities.toFile(Lookup.class.getProtectionDomain().getCodeSource().getLocation().toURI()); } protected void copyDirectory(File srcDir, File dstDir) throws IOException { @@ -694,24 +581,22 @@ protected void copyDirectory(File srcDir, File dstDir) throws IOException { } protected static void printFile(File file, String prefix, PrintStream out) throws Exception { - BufferedReader rdr = new BufferedReader(new FileReader(file)); - try { - String line; - while ((line = rdr.readLine()) != null) { + try (BufferedReader rdr = new BufferedReader(new FileReader(file))) { + for(String line = rdr.readLine(); line != null; line = rdr.readLine()) { if (prefix == null) { out.printf("%s\n", line); } else { out.printf("%s: %s\n", prefix, line); } } - } finally { - if (rdr != null) { - rdr.close(); - } } } - - /** A convenience wrapper for Thread.sleep */ + + /** + * A convenience wrapper for Thread.sleep + * + * @param millis + */ protected static void sleep(int millis) { try { Thread.sleep(millis); @@ -726,14 +611,14 @@ protected String mkTemp(ExecutionEnvironment execEnv, boolean directory) throws protected String createRemoteTmpDir() throws Exception { String dir = getRemoteTmpDir(); - int rc = CommonTasksSupport.mkDir(getTestExecutionEnvironment(), dir, new PrintWriter(System.err)).get().intValue(); + int rc = CommonTasksSupport.mkDir(getTestExecutionEnvironment(), dir, new PrintWriter(System.err)).get(); assertEquals("Can not create directory " + dir, 0, rc); return dir; } protected void clearRemoteTmpDir() throws Exception { String dir = getRemoteTmpDir(); - int rc = CommonTasksSupport.rmDir(getTestExecutionEnvironment(), dir, true, new PrintWriter(System.err)).get().intValue(); + int rc = CommonTasksSupport.rmDir(getTestExecutionEnvironment(), dir, true, new PrintWriter(System.err)).get(); if (rc != 0) { System.err.printf("Can not delete directory %s\n", dir); } @@ -759,12 +644,12 @@ protected synchronized String getRemoteTmpDir() { } return remoteTmpDir; } - + protected static void threadsDump(String header, String footer) { NativeExecutionTestSupport.threadsDump(header, footer); } protected static boolean isDebugged() { return MiscUtils.isDebugged(); - } + } } diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestSuite.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestSuite.java index 84e062312aba..75314acc8c67 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestSuite.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionBaseTestSuite.java @@ -26,7 +26,6 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; @@ -64,17 +63,13 @@ public NativeExecutionBaseTestSuite(String name) { /** * Constructs an empty TestSuite. - * @param testClasses test classes to add. - * The is probably too strong - would be sufficient - * (the only check is the search for 2-parammeter constructor that takes String and ExecutinEnvironmant); - * the intention was rather to explain what it's used for than to restrict. + * @param testClass test classes to add. */ - public NativeExecutionBaseTestSuite(Class... testClasses) { + @SuppressWarnings("this-escape") + public NativeExecutionBaseTestSuite(Class testClass) { super(); this.defaultSection = null; - for (Class testClass : testClasses) { - addTest(testClass); - } + addTest(testClass); } /** @@ -91,18 +86,14 @@ public NativeExecutionBaseTestSuite(String name, String defaultSection) { * Constructs TestSuite that adds tests specified by classes parameters * @param name suite name * @param defaultSection default section for @ForAllEnvironments annotation - * @param testClasses test class to add. - * The is probably too strong - would be sufficient - * (the only check is the search for 2-parammeter constructor that takes String and ExecutinEnvironmant); - * the intention was rather to explain what it's used for than to restrict. + * @param testClass test class to add. */ - public NativeExecutionBaseTestSuite(String name, String defaultSection, - Class... testClasses) { + @SuppressWarnings("this-escape") + public NativeExecutionBaseTestSuite(String name, String defaultSection, + Class testClass) { this(name, defaultSection); - for (Class testClass : testClasses) { - addTest(testClass); - } + addTest(testClass); } /** @@ -113,7 +104,7 @@ public NativeExecutionBaseTestSuite(String name, String defaultSection, * the intention was rather to explain what it's used for than to restrict. */ protected final void addTest(Class testClass) { - + TestClassData testData = findTestData(testClass); sortTestData(testData); if (testData.testMethods.isEmpty()) { @@ -155,7 +146,7 @@ protected final void addTest(Class testCl } } } - + public void addWarningTest(String testName, String warningText) { addTest(warning(testName, warningText)); } @@ -184,7 +175,7 @@ private static class TestMethodData { /** The name of the method */ public final String name; - /** + /** * In the case the method is annotated with @ForAllEnvironments, contains it's section * (or default one in the case it isn't specified in the annotation); * if the method is not annotated with @ForAllEnvironments, contains null @@ -214,12 +205,12 @@ public boolean isForAllEnvironments() { } private static class TestClassData { - + // making fields public would be unsafe if this class wasn't private static :-) public List testMethods = new ArrayList<>(); public Constructor ordinaryConstructor = null; public Constructor forAllEnvConstructor = null; - + public boolean containsMethod(String name) { if (name != null) { for (TestMethodData md : testMethods) { @@ -280,17 +271,14 @@ private boolean checkConditionals(TestMethodData methodData, Class condition is false, that's it return false; - } catch (IOException ex) { - addWarningTest("Error getting condition for " + methodData.name + ": " + ex.getMessage()); - return false; - } catch (RcFile.FormatException ex) { + } catch (IOException | RcFile.FormatException ex) { addWarningTest("Error getting condition for " + methodData.name + ": " + ex.getMessage()); return false; } } /** - * Searches for + * Searches for * - test methods * - constructors * @@ -312,8 +300,8 @@ private TestClassData findTestData(Class testClass) { for (Method method : superClass.getDeclaredMethods()) { if (!result.containsMethod(method.getName())) { ForAllEnvironments forAllEnvAnnotation = method.getAnnotation(ForAllEnvironments.class); - - if (method.getName().startsWith("test") + + if (method.getName().startsWith("test") || method.getAnnotation(org.junit.Test.class) != null || forAllEnvAnnotation != null) { if (!Modifier.isPublic(method.getModifiers())) { @@ -365,14 +353,9 @@ private TestClassData findTestData(Class testClass) { return result; } - + private static void sortTestData(TestClassData data) { - data.testMethods.sort(new Comparator() { - @Override - public int compare(TestMethodData d1, TestMethodData d2) { - return d1.name.compareTo(d2.name); - } - }); + data.testMethods.sort((TestMethodData d1, TestMethodData d2) -> d1.name.compareTo(d2.name)); } protected static Test warning(String testName, final String message) { diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionTestFrameworkTestCase.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionTestFrameworkTestCase.java index 21c7c6749180..5bfcbe853258 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionTestFrameworkTestCase.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/test/NativeExecutionTestFrameworkTestCase.java @@ -101,9 +101,9 @@ public void testIfdefAndIf() { } public static junit.framework.Test suite() { - Class testClass = NativeExecutionTestFrameworkTestCase.class; + Class testClass = NativeExecutionTestFrameworkTestCase.class; return new NativeExecutionBaseTestSuite( testClass.getSimpleName(), "test.framework.test.default.platforms", testClass); - } + } } diff --git a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/SolarisPrivilegesSupportTest.java b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/SolarisPrivilegesSupportTest.java index 1185640b970d..49cf4db14365 100644 --- a/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/SolarisPrivilegesSupportTest.java +++ b/ide/dlight.nativeexecution/test/unit/src/org/netbeans/modules/nativeexecution/util/SolarisPrivilegesSupportTest.java @@ -19,7 +19,6 @@ package org.netbeans.modules.nativeexecution.util; import java.io.IOException; -import java.security.acl.NotOwnerException; import java.util.Arrays; import junit.framework.Test; import org.junit.AfterClass; @@ -38,6 +37,7 @@ * * @author ak119685 */ +@SuppressWarnings("removal") public class SolarisPrivilegesSupportTest extends NativeExecutionBaseTestCase { public SolarisPrivilegesSupportTest(String name) { @@ -85,13 +85,11 @@ public void test() { sps.requestPrivileges(Arrays.asList("dtrace_kernel"), true); // NOI18N } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); - } catch (NotOwnerException ex) { + } catch (SolarisPrivilegesSupport.NotOwnerException ex) { System.out.println(ex); } System.out.println(sps.getExecutionPrivileges()); - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } catch (CancellationException ex) { + } catch (IOException | CancellationException ex) { Exceptions.printStackTrace(ex); } }