diff --git a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java index 9e752149e7c..5fd5dce9ac1 100644 --- a/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java +++ b/core/org.eclipse.cdt.core.native/src/org/eclipse/cdt/utils/spawner/ProcessFactory.java @@ -12,16 +12,23 @@ * QNX Software Systems - Initial API and implementation * Martin Oberhuber (Wind River) - [303083] Split out the Spawner * Red Hat Inc. - add flatpak support + * εΎζŒζ’ Xu Chiheng - refactor to help debugging *******************************************************************************/ package org.eclipse.cdt.utils.spawner; import java.io.File; import java.io.IOException; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; import java.util.StringTokenizer; +import java.util.TreeMap; import org.eclipse.cdt.internal.core.natives.CNativePlugin; import org.eclipse.cdt.internal.core.natives.Messages; import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; /** * @noextend This class is not intended to be subclassed by clients. @@ -33,6 +40,106 @@ public class ProcessFactory { private boolean hasSpawner; private Runtime runtime; + private String[] modifyCmdArrayIfFlatpak(String[] cmdarray) { + if (System.getenv("FLATPAK_SANDBOX_DIR") != null) { //$NON-NLS-1$ + String[] newArray = new String[cmdarray.length + 3]; + System.arraycopy(cmdarray, 0, newArray, 3, cmdarray.length); + newArray[0] = "flatpak-spawn"; //$NON-NLS-1$ + newArray[1] = "--host"; //$NON-NLS-1$ + newArray[2] = "--watch-bus"; //$NON-NLS-1$ + cmdarray = newArray; + } + return cmdarray; + } + + private static TreeMap newEmptyEnvironment() { + TreeMap environment; + if (Platform.getOS().equals(Platform.OS_WIN32)) { + environment = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + } else { + environment = new TreeMap<>(); + } + return environment; + } + + private static TreeMap envpToEnvMap(String[] envp) { + TreeMap environment = newEmptyEnvironment(); + if (envp != null) { + for (String envstring : envp) { + int eqlsign = envstring.indexOf('='); + if (eqlsign != -1) { + environment.put(envstring.substring(0, eqlsign), envstring.substring(eqlsign + 1)); + } else { + // Silently ignore envstrings lacking the required `='. + } + } + } + return environment; + } + + private static TreeMap getDefaultEnvironment() { + TreeMap environment = newEmptyEnvironment(); + Map env = new ProcessBuilder().environment(); + environment.putAll(env); + return environment; + } + + private static void appendEnvMapComparison(StringBuilder sb, TreeMap environmentA, + TreeMap environmentB) { + TreeMap environmentC = newEmptyEnvironment(); + environmentC.putAll(environmentA); + environmentC.putAll(environmentB); + Iterator> iterator = environmentC.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + String key = entry.getKey(); + String valueA, valueB; + if (environmentA.containsKey(key)) { + valueA = environmentA.get(key); + if (environmentB.containsKey(key)) { + valueB = environmentB.get(key); + int result = valueA.compareTo(valueB); + if (result == 0) { + // not changed + sb.append(' '); + sb.append(key); + sb.append('='); + sb.append(valueA); + sb.append('\n'); + } else { + // changed + sb.append('-'); + sb.append(key); + sb.append('='); + sb.append(valueA); + sb.append('\n'); + sb.append('+'); + sb.append(key); + sb.append('='); + sb.append(valueB); + sb.append('\n'); + } + } else { + // removed + sb.append('-'); + sb.append(key); + sb.append('='); + sb.append(valueA); + sb.append('\n'); + } + } else { + // environmentB contains the key + valueB = environmentB.get(key); + // added + sb.append('+'); + sb.append(key); + sb.append('='); + sb.append(valueB); + sb.append('\n'); + } + } + } + private class Builder { String[] cmdarray; String[] envp; @@ -50,6 +157,7 @@ public class ProcessFactory { this.cmdarray = new String[st.countTokens()]; for (int i = 0; st.hasMoreTokens(); i++) this.cmdarray[i] = st.nextToken(); + this.cmdarray = modifyCmdArrayIfFlatpak(this.cmdarray); } public Builder(String[] cmdarray) throws IOException { @@ -57,6 +165,7 @@ public class ProcessFactory { throw new IllegalArgumentException("Empty command"); //$NON-NLS-1$ } this.cmdarray = cmdarray; + this.cmdarray = modifyCmdArrayIfFlatpak(this.cmdarray); } public Builder environment(String[] envp) { @@ -81,8 +190,71 @@ public class ProcessFactory { return this; } + private StringBuilder debug() { + // for debug purpose + StringBuilder sb = new StringBuilder(); + + sb.append("command :\n"); //$NON-NLS-1$ + for (int i = 0; i < cmdarray.length; i++) { + sb.append(i); + sb.append(" : \""); //$NON-NLS-1$ + sb.append(cmdarray[i]); + sb.append("\"\n"); //$NON-NLS-1$ + } + sb.append("\n\n"); //$NON-NLS-1$ + + sb.append("directory :\n"); //$NON-NLS-1$ + if (dir != null) { + String pathString = dir.toString(); + sb.append(pathString); + sb.append('\n'); + Path path = new Path(pathString); + String pathDevice = path.getDevice(); + String[] pathSegments = path.segments(); + if (pathDevice != null) { + sb.append("device : "); //$NON-NLS-1$ + sb.append(pathDevice); + sb.append('\n'); + } + sb.append("segments : \n"); //$NON-NLS-1$ + for (int i = 0; i < pathSegments.length; i++) { + sb.append(i); + sb.append(" : "); //$NON-NLS-1$ + sb.append(pathSegments[i]); + sb.append('\n'); + } + } else { + sb.append("not specified\n"); //$NON-NLS-1$ + } + sb.append("\n\n"); //$NON-NLS-1$ + + { + TreeMap environmentA = getDefaultEnvironment(); + TreeMap environmentB = envpToEnvMap(envp); + + sb.append("environment :\n"); //$NON-NLS-1$ + appendEnvMapComparison(sb, environmentA, environmentB); + sb.append("\n\n"); //$NON-NLS-1$ + } + if (use_pty) { + sb.append("use pty : "); //$NON-NLS-1$ + sb.append(pty.toString()); + sb.append("\n\n"); //$NON-NLS-1$ + } + if (has_gracefulExitTimeMs) { + sb.append("has gracefulExitTimeMs : "); //$NON-NLS-1$ + sb.append(gracefulExitTimeMs); + sb.append("\n\n"); //$NON-NLS-1$ + } + // set breakpoint on next line to inspect sb when debugging, to see the + // ultimate parameters of ProcessBuilder + return sb; + } + public Process start() throws IOException { - cmdarray = modifyCmdArrayIfFlatpak(cmdarray); + // Uncomment the next line, set a breakpoint in the last line of debug() method, + // when the breakpoint is triggered, inspect the sb variable to see detailed info on what is being launched. + // debug(); Process p; if (hasSpawner) { if (use_pty) { @@ -215,16 +387,4 @@ public class ProcessFactory { .gracefulExitTimeMs(gracefulExitTimeMs).start(); return p; } - - private String[] modifyCmdArrayIfFlatpak(String[] cmdarray) { - if (System.getenv("FLATPAK_SANDBOX_DIR") != null) { //$NON-NLS-1$ - String[] newArray = new String[cmdarray.length + 3]; - System.arraycopy(cmdarray, 0, newArray, 3, cmdarray.length); - newArray[0] = "flatpak-spawn"; //$NON-NLS-1$ - newArray[1] = "--host"; //$NON-NLS-1$ - newArray[2] = "--watch-bus"; //$NON-NLS-1$ - cmdarray = newArray; - } - return cmdarray; - } }