CommandLineComposer.java
package com.github.dakusui.actionunit.actions.cmd;
import com.github.dakusui.actionunit.actions.ContextVariable;
import com.github.dakusui.actionunit.core.Context;
import com.github.dakusui.actionunit.core.context.ContextFunction;
import com.github.dakusui.actionunit.exceptions.ActionException;
import com.github.dakusui.actionunit.utils.StableTemplatingUtils;
import java.util.ArrayList;
import java.util.Formattable;
import java.util.Formatter;
import java.util.LinkedList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.IntFunction;
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.joining;
public interface CommandLineComposer extends Function<ContextVariable[], BiFunction<Context, Object[], String>>, Formattable {
@Override
default BiFunction<Context, Object[], String> apply(ContextVariable[] variables) {
return (context, argValues) -> StableTemplatingUtils.template(
compose(context),
StableTemplatingUtils.toMapping(this.parameterPlaceHolderFactory().apply(variables), argValues)
);
}
@Override
default void formatTo(Formatter formatter, int flags, int width, int precision) {
formatter.format(format());
}
Function<ContextVariable[], IntFunction<String>> parameterPlaceHolderFactory();
String format();
String compose(Context context);
class Builder implements Cloneable {
private final Function<ContextVariable[], IntFunction<String>> parameterPlaceHolderFactory;
private List<ContextVariable> knownVariables;
private List<Function<Context, String>> tokens;
public Builder(Function<ContextVariable[], IntFunction<String>> parameterPlaceHolderFactory) {
this.parameterPlaceHolderFactory = requireNonNull(parameterPlaceHolderFactory);
this.tokens = new LinkedList<>();
this.knownVariables = new LinkedList<>();
}
public Builder append(String text, boolean quoted) {
requireNonNull(text);
ContextFunction<String> func = ContextFunction.of(() -> text, c -> text);
return append(func, quoted);
}
public Builder append(Function<Context, String> func, boolean quoted) {
if (quoted)
func = quoteWithApostrophe(func);
this.tokens.add(func);
return this;
}
@SuppressWarnings("UnusedReturnValue")
public Builder appendVariable(ContextVariable variable, boolean quoted) {
Function<Context, String> func = ContextFunction.of(
() -> "${" + variable.variableName() + "}",
variable::resolve
);
if (quoted) {
func = quoteWithApostrophe(func);
}
this.tokens.add(func);
return this.declareVariable(variable);
}
public Builder declareVariable(ContextVariable contextVariable) {
if (!knownVariables.contains(contextVariable))
this.knownVariables.add(contextVariable);
return this;
}
public CommandLineComposer build() {
return new CommandLineComposer() {
@Override
public Function<ContextVariable[], IntFunction<String>> parameterPlaceHolderFactory() {
return parameterPlaceHolderFactory;
}
@Override
public String format() {
return tokens.stream().map(Object::toString).collect(joining());
}
@Override
public String compose(Context context) {
return tokens.stream().map(each -> each.apply(context)).collect(joining());
}
};
}
public ContextVariable[] knownVariables() {
return knownVariables.toArray(new ContextVariable[0]);
}
@Override
public CommandLineComposer.Builder clone() {
try {
CommandLineComposer.Builder ret = (Builder) super.clone();
ret.knownVariables = new ArrayList<>(this.knownVariables);
ret.tokens = new ArrayList<>(this.tokens);
return ret;
} catch (CloneNotSupportedException e) {
throw ActionException.wrap(e);
}
}
@Override
public String toString() {
return String.format("Builder:%s(vars=%s)", tokens, knownVariables);
}
private static Function<Context, String> quoteWithApostrophe(Function<Context, String> func) {
return func.andThen(new Function<String, String>() {
@Override
public String apply(String s) {
return CommanderUtils.quoteWithApostropheForShell(s);
}
@Override
public String toString() {
return "'";
}
});
}
}
}