package org.erlide.runtime.api; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.jdt.annotation.Nullable; import org.erlide.runtime.runtimeinfo.RuntimeInfo; import org.erlide.util.ErlangFunctionCall; import org.erlide.util.HostnameChecker; import org.erlide.util.SystemConfiguration; import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.google.common.collect.Sets; public class RuntimeData { protected boolean internal; protected boolean managed; protected boolean restartable; protected boolean startShell; protected boolean console; protected RuntimeInfo runtimeInfo; protected String cookie; protected String nodeName; protected boolean longName; protected String extraArgs; protected String workingDir; protected Map<String, String> env; protected ErlangFunctionCall initialCall; protected boolean loadOnAllNodes; protected boolean debug; protected EnumSet<ErlDebugFlags> debugFlags; protected Set<String> initialInterpretedModules; protected boolean reportErrors = false; public RuntimeData() { cookie = ""; managed = true; restartable = false; startShell = true; console = true; nodeName = ""; longName = true; extraArgs = ""; workingDir = "."; env = Maps.newHashMap(); initialCall = null; debugFlags = ErlDebugFlags.DEFAULT_DEBUG_FLAGS; loadOnAllNodes = false; internal = false; initialInterpretedModules = Sets.newHashSet(); runtimeInfo = null; debug = false; } public RuntimeData(final RuntimeInfo runtime, final String mode) { this(); runtimeInfo = runtime; debug = "debug".equals(mode); } public RuntimeData(final RuntimeInfo info, final String mode, final String defaultWorkingDir) { this(info, mode); setCookie("erlide"); setLongName(true); setWorkingDir(defaultWorkingDir); setConsole(true); setLoadAllNodes(false); if (info != null) { setExtraArgs(info.getArgs()); } } public String getCookie() { return cookie; } public void setCookie(final String cookie) { this.cookie = cookie.trim(); } public boolean isManaged() { return managed; } public void setManaged(final boolean managed) { this.managed = managed; } public boolean isRestartable() { return restartable; } public void setRestartable(final boolean restartable) { this.restartable = restartable; } public boolean useStartShell() { return startShell; } public void setUseStartShell(final boolean shell) { startShell = shell; } public boolean hasConsole() { return console; } public void setConsole(final boolean console) { this.console = console; } public boolean isDebug() { return debug; } public void setDebug(final boolean debug) { this.debug = debug; } public Set<String> getInitialInterpretedModules() { return initialInterpretedModules; } public String getNodeName() { return nodeName; } public void setNodeName(final String nodeName) { if (!validateNodeName(nodeName)) { throw new IllegalStateException("Erlang node can't be called " + nodeName); } this.nodeName = nodeName; } public static boolean validateNodeName(final String name) { return name != null && name.matches("[a-zA-Z0-9_-]+(@[a-zA-Z0-9_.-]+)?"); } public boolean hasLongName() { return longName; } public void setLongName(final boolean longname) { longName = longname; } public String getExtraArgs() { return extraArgs; } public void setExtraArgs(final String xtra) { extraArgs = xtra; } public String getWorkingDir() { return workingDir; } public void setWorkingDir(final String dir) { workingDir = dir; } public Map<String, String> getEnv() { return env; } @Nullable public ErlangFunctionCall getInitialCall() { return initialCall; } public RuntimeInfo getRuntimeInfo() { return runtimeInfo; } public EnumSet<ErlDebugFlags> getDebugFlags() { return debugFlags; } public boolean shouldLoadOnAllNodes() { return loadOnAllNodes; } public void setLoadAllNodes(final boolean load) { loadOnAllNodes = load; } public boolean isInternal() { return internal; } public void setInternal(final boolean internal) { this.internal = internal; } public String[] getCmdLine() { final RuntimeInfo r = getRuntimeInfo(); final List<String> result = new ArrayList<>(); if (hasDetachedConsole() && !isInternal()) { if (SystemConfiguration.getInstance().isOnWindows()) { result.add("cmd.exe"); result.add("/c"); result.add("start"); } else { final String command = System.getenv().get("TERM"); result.add(command); result.add("-e"); } } String erl = r.getOtpHome() + "/bin/erl"; if (erl.indexOf(' ') >= 0) { erl = "\"" + erl + "\""; } result.add(erl); for (final String path : r.getCodePath()) { if (!Strings.isNullOrEmpty(path)) { result.add("-pa"); result.add(path); } } if (!useStartShell()) { result.add("-noshell"); } if (!getNodeName().equals("")) { final String nameTag = hasLongName() ? "-name" : "-sname"; String nameOption = getNodeName(); if (!nameOption.contains("@")) { nameOption += "@" + HostnameChecker.getInstance().getErlangHostName(hasLongName()); } result.add(nameTag); result.add(nameOption); final String cky = getCookie(); if (!Strings.isNullOrEmpty(cky)) { result.add("-setcookie"); result.add(cky); } } final String gotArgs = r.getArgs(); if (!Strings.isNullOrEmpty(gotArgs)) { result.addAll(splitQuoted(gotArgs)); } return result.toArray(new String[result.size()]); } private boolean hasDetachedConsole() { // TODO add GUI for "detached console" return "true".equals(System.getProperty("erlide.backend.detached")); } /** * split on spaces but respect quotes * * @param theArgs * @return */ private Collection<String> splitQuoted(final String theArgs) { final Pattern p = Pattern.compile("(\"[^\"]*?\"|'[^']*?'|\\S+)"); final Matcher m = p.matcher(theArgs); final List<String> tokens = new ArrayList<>(); while (m.find()) { tokens.add(m.group(1)); } return tokens; } public String getQualifiedNodeName() { final String erlangHostName = HostnameChecker.getInstance() .getErlangHostName(hasLongName()); final String name = getNodeName(); final boolean hasHost = name.contains("@"); return hasHost ? name : name + "@" + erlangHostName; } public boolean isReportErrors() { return reportErrors; } public void setReportErrors(final boolean value) { reportErrors = value; } }