/*******************************************************************************
* Copyright (c) 2016 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.lang.tooling.commands;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull;
import static melnorme.utilbox.core.CoreUtil.areEqual;
import java.util.Map;
import java.util.Map.Entry;
import melnorme.lang.tooling.utils.ArgumentsParser;
import melnorme.lang.utils.EnvUtils;
import melnorme.lang.utils.ProcessUtils;
import melnorme.utilbox.collections.HashMap2;
import melnorme.utilbox.collections.Indexable;
import melnorme.utilbox.collections.MapAccess;
import melnorme.utilbox.core.CommonException;
import melnorme.utilbox.fields.validation.ValidatedValueSource;
import melnorme.utilbox.misc.HashcodeUtil;
import melnorme.utilbox.status.Severity;
import melnorme.utilbox.status.StatusException;
public class CommandInvocation {
protected final String commandLine;
protected final MapAccess<String, String> environmentVars; // Can be null
protected final boolean appendEnvironment;
public CommandInvocation(String commandLine) {
this(commandLine, null, true);
}
public CommandInvocation(String commandLine, MapAccess<String, String> envVars, boolean appendEnv) {
this.commandLine = assertNotNull(commandLine);
this.environmentVars = envVars != null ? envVars : new HashMap2<>();
this.appendEnvironment = appendEnv;
}
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof CommandInvocation)) return false;
CommandInvocation other = (CommandInvocation) obj;
return
areEqual(commandLine, other.commandLine) &&
areEqual(environmentVars, other.environmentVars) &&
areEqual(appendEnvironment, other.appendEnvironment);
}
@Override
public int hashCode() {
return HashcodeUtil.combinedHashCode(commandLine, environmentVars);
}
public String getCommandLine() {
return commandLine;
}
public Indexable<String> parseCommandLineArguments() {
return ArgumentsParser.parse(this.commandLine);
}
public MapAccess<String, String> getEnvironmentVars() {
return environmentVars;
}
public boolean isAppendEnvironment() {
return appendEnvironment;
}
/* ----------------- ----------------- */
public CommandInvocation getResolvedCommandInvocation(IVariablesResolver variablesResolver)
throws StatusException, CommonException {
String commandLine = evaluateCommandArguments(variablesResolver);
HashMap2<String, String> resolvedEnvVars = new HashMap2<>();
for (Entry<String, String> envVar : getEnvironmentVars()) {
String newValue = variablesResolver.performStringSubstitution(envVar.getValue());
resolvedEnvVars.put(envVar.getKey(), newValue);
}
return new CommandInvocation(commandLine, resolvedEnvVars, isAppendEnvironment());
}
public ProcessBuilder getProcessBuilder(IVariablesResolver variablesResolver) throws CommonException {
return getResolvedCommandInvocation(variablesResolver).getProcessBuilder();
}
public ProcessBuilder getProcessBuilder() {
Indexable<String> commandLine = parseCommandLineArguments();
ProcessBuilder pb = ProcessUtils.createProcessBuilder(commandLine, null);
Map<String, String> environment = pb.environment();
if(!isAppendEnvironment()) {
environment.clear();
}
for (Entry<String, String> envVar : getEnvironmentVars()) {
EnvUtils.putVarInEnvMap(environment, envVar.getKey(), envVar.getValue());
}
return pb;
}
public String evaluateCommandArguments(IVariablesResolver variablesResolver) throws StatusException {
return getValidatedCommandArguments(variablesResolver).getValidatedValue();
}
protected ValidatedCommandArgumentsSource getValidatedCommandArguments(IVariablesResolver variablesResolver) {
return new ValidatedCommandArgumentsSource(commandLine, variablesResolver);
}
public static class ValidatedCommandArgumentsSource implements ValidatedValueSource<String> {
public static final String MSG_NO_COMMAND_SPECIFIED = "No command specified.";
protected final IVariablesResolver variablesResolver;
protected final String commandArguments;
public ValidatedCommandArgumentsSource(String commandArguments, IVariablesResolver variablesResolver) {
this.commandArguments = commandArguments;
this.variablesResolver = variablesResolver;
}
@Override
public String getValidatedValue() throws StatusException {
try {
return doGetValidatedValue(variablesResolver);
} catch(CommonException e) {
throw e.toStatusException(Severity.WARNING);
}
}
public String doGetValidatedValue(IVariablesResolver variablesResolver) throws CommonException {
if(commandArguments == null) {
handleNoCommandLine();
}
String evaluatedCommandLine = variablesResolver.performStringSubstitution(commandArguments);
if(evaluatedCommandLine.trim().isEmpty()) {
handleNoCommandLine();
}
return evaluatedCommandLine;
}
protected void handleNoCommandLine() throws CommonException {
throw new CommonException(MSG_NO_COMMAND_SPECIFIED);
}
}
}