# HG changeset patch # User Andrew Krasny # Date 1274301121 -14400 # Node ID 6789258a77cb950419ff998c73a867e3d7166fbf # Parent bf27f4d32140cc1655b6860fc95e619b5da2e611 Bug 186316 - Debugger doesn't work in internal terminal if NetBeans is installed in path with spaces diff -r bf27f4d32140 -r 6789258a77cb dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java --- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java Wed May 19 18:13:53 2010 +0400 +++ b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/pty/PtyAllocator.java Thu May 20 00:32:01 2010 +0400 @@ -53,6 +53,7 @@ import org.netbeans.modules.nativeexecution.api.HostInfo; import org.netbeans.modules.nativeexecution.api.pty.Pty; import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils; +import org.netbeans.modules.nativeexecution.api.util.MacroMap; import org.netbeans.modules.nativeexecution.api.util.Shell; import org.netbeans.modules.nativeexecution.api.util.WindowsSupport; import org.netbeans.modules.nativeexecution.pty.PtyOpenUtility.PtyInfo; @@ -93,15 +94,21 @@ try { if (env.isLocal()) { + ProcessBuilder pb = new ProcessBuilder(hostInfo.getShell(), "-s"); // NOI18N + 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 } ptyOpenUtilityPath = WindowsSupport.getInstance().convertToCygwinPath(ptyOpenUtilityPath); + + // cygwin requires cygwin1.dll to be in the path... + // take already 'tuned' path from the MacroMap.forExecEnv() + String path = MacroMap.forExecEnv(env).get("PATH"); // NOI18N + pb.environment().put("Path", path); // NOI18N } - ProcessBuilder pb = new ProcessBuilder(hostInfo.getShell(), "-s"); // NOI18N Process pty = pb.start(); output = pty.getOutputStream(); input = pty.getInputStream(); @@ -119,7 +126,7 @@ error = streams.err; } - output.write(("exec " + ptyOpenUtilityPath + "\n").getBytes()); // NOI18N + output.write(("exec \"" + ptyOpenUtilityPath + "\"\n").getBytes()); // NOI18N output.flush(); PtyInfo ptyInfo = PtyOpenUtility.getInstance().readSatelliteOutput(input); diff -r bf27f4d32140 -r 6789258a77cb dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/HelperUtility.java --- a/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/HelperUtility.java Wed May 19 18:13:53 2010 +0400 +++ b/dlight.nativeexecution/src/org/netbeans/modules/nativeexecution/support/HelperUtility.java Thu May 20 00:32:01 2010 +0400 @@ -42,7 +42,10 @@ package org.netbeans.modules.nativeexecution.support; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; +import java.nio.channels.FileChannel; import java.text.ParseException; import java.util.HashMap; import java.util.MissingResourceException; @@ -72,7 +75,8 @@ /** * * @param env - * @return the ready-to-use remote path for the utility + * @return the ready-to-use remote path for the utility. It is quaranteed + * that returned path contain no spaces nor non-ascii chars. * @throws IOException */ public final String getPath(final ExecutionEnvironment env) throws IOException { @@ -95,7 +99,38 @@ String localFile = getLocalFileLocationFor(env); if (env.isLocal()) { - result = localFile; + // We want to be sure that utility is in a 'good' location, + // which means path contains no spaces nor non-ascii chars in it. + // This will help to avoid a number of problems. + // So will use the 'original' if it is 'good' or will + // make a copy to user's tmp if it is not. + + boolean pathIsOK = checkPath(localFile); + + if (pathIsOK) { + result = localFile; + } else { + // copy to a tmp dir + File orig = new File(localFile); + File newFile = new File(hinfo.getTempDirFile(), orig.getName()); + + if (newFile.exists()) { + // result will be cached. So this is done once + // per IDE invocation... + // also it is a localhost, so should be fast to + // copy (not slower than taking and comparing md5sums) + // force-copying every time will ensure that + // utility is up-to-date + newFile.delete(); + } + + result = newFile.getAbsolutePath(); + copyLocalFile(orig, newFile); + + // give execution permissions to + // the file... + CommonTasksSupport.chmod(env, result, 0755, null).get(); + } } else { final String fileName = new File(localFile).getName(); final String remoteFile = hinfo.getTempDir() + '/' + fileName; @@ -134,4 +169,44 @@ return file.getAbsolutePath(); } + + private static void copyLocalFile(final File from, final File to) throws IOException { + FileChannel inChannel = new FileInputStream(from).getChannel(); + FileChannel outChannel = new FileOutputStream(to).getChannel(); + + try { + inChannel.transferTo(0, inChannel.size(), outChannel); + } catch (IOException e) { + throw e; + } finally { + if (inChannel != null) { + inChannel.close(); + } + if (outChannel != null) { + outChannel.close(); + } + } + } + + private static boolean checkPath(String path) { + for (int i = 0; i < path.length(); i++) { + char c = path.charAt(i); + + if (Character.isDigit(c) || c == '_' || c == '/' || c == '\\' || c == '-') { + continue; + } + + if (c >= 'A' && c <= 'Z') { + continue; + } + + if (c >= 'a' && c <= 'z') { + continue; + } + + return false; + } + + return true; + } }