Issue 126: added initializers and positional parameter converters

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2344 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-11-29 21:25:29 +00:00
parent d43c31f1fd
commit fbf9225f5d
7 changed files with 175 additions and 26 deletions

View File

@ -25,6 +25,7 @@ package org.jclouds.initbuilder;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -33,6 +34,9 @@ import org.jclouds.initbuilder.domain.ShellToken;
import org.jclouds.initbuilder.util.Utils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
@ -48,6 +52,9 @@ public class InitBuilder {
@VisibleForTesting
Map<String, String> variables = Maps.newHashMap();
@VisibleForTesting
List<String> variablesToUnset = Lists.newArrayList("path", "javaHome", "libraryPath");
/**
* Adds a switch statement to the script. If its value is found, it will invoke the corresponding
* action.
@ -73,6 +80,14 @@ public class InitBuilder {
return this;
}
/**
* Unsets a variable to ensure it is set within the script.
*/
public InitBuilder unsetEnvironmentVariable(String name) {
variablesToUnset.add(checkNotNull(name, "name"));
return this;
}
/**
* Exports a variable inside the script
*/
@ -92,15 +107,26 @@ public class InitBuilder {
* @param osFamily
* whether to write a cmd or bash script.
*/
public String build(OsFamily osFamily) {
public String build(final OsFamily osFamily) {
StringBuilder builder = new StringBuilder();
builder.append(ShellToken.SHEBANG.to(osFamily));
builder.append(ShellToken.ZERO_PATH.to(osFamily));
builder.append(Utils.writeUnsetVariables(Lists.newArrayList(Iterables.transform(
variablesToUnset, new Function<String, String>() {
@Override
public String apply(String from) {
if (ShellToken.tokenValueMap(osFamily).containsKey(from + "Variable"))
return Utils.FUNCTION_UPPER_UNDERSCORE_TO_LOWER_CAMEL.apply(ShellToken
.tokenValueMap(osFamily).get(from + "Variable"));
return from;
}
})), osFamily));
builder.append(Utils.writeZeroPath(osFamily));
builder.append(Utils.writeVariableExporters(variables, osFamily));
for (Entry<String, Map<String, String>> entry : switchExec.entrySet()) {
builder.append(Utils.writeSwitch(entry.getKey(), entry.getValue(), osFamily));
}
return builder.toString();
}
}

View File

@ -33,13 +33,13 @@ import com.google.common.collect.MapMaker;
import com.google.common.collect.Maps;
/**
* Constants used in operating suy
* Constants used in shell scripting.
*
* @author Adrian Cole
*/
public enum ShellToken {
FS, PS, LF, SH, SOURCE, REM, ARGS, VARSTART, VAREND, SHEBANG, ZERO_PATH, EXE;
FS, PS, LF, SH, SOURCE, REM, ARGS, VARSTART, VAREND, SHEBANG, LIBRARY_PATH_VARIABLE;
private static final Map<OsFamily, Map<String, String>> familyToTokenValueMap = new MapMaker()
.makeComputingMap(new Function<OsFamily, Map<String, String>>() {
@ -91,6 +91,13 @@ public enum ShellToken {
case UNIX:
return "bash";
}
case LIBRARY_PATH_VARIABLE:
switch (family) {
case WINDOWS:
return "PATH";
case UNIX:
return "LD_LIBRARY_PATH";
}
case SOURCE:
switch (family) {
case WINDOWS:
@ -133,20 +140,7 @@ public enum ShellToken {
case UNIX:
return "#!/bin/bash\n";
}
case ZERO_PATH:
switch (family) {
case WINDOWS:
return "set PATH=c:\\windows\\;C:\\windows\\system32\r\n";
case UNIX:
return "export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin\n";
}
case EXE:
switch (family) {
case WINDOWS:
return ".exe";
case UNIX:
return "";
}
default:
throw new UnsupportedOperationException("token " + this + " not configured");
}

View File

@ -23,6 +23,7 @@
*/
package org.jclouds.initbuilder.util;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
@ -31,7 +32,10 @@ import java.util.regex.Pattern;
import org.jclouds.initbuilder.domain.OsFamily;
import com.google.common.base.CaseFormat;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
/**
* Utilities used to build init scripts.
@ -40,7 +44,25 @@ import com.google.common.collect.ImmutableMap;
*/
public class Utils {
public static final Pattern pattern = Pattern.compile("\\{(.+?)\\}");
public static final LowerCamelToUpperUnderscore FUNCTION_LOWER_CAMEL_TO_UPPER_UNDERSCORE = new LowerCamelToUpperUnderscore();
public static final class LowerCamelToUpperUnderscore implements Function<String, String> {
@Override
public String apply(String from) {
return CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, from);
}
}
public static final UpperUnderscoreToLowerCamel FUNCTION_UPPER_UNDERSCORE_TO_LOWER_CAMEL = new UpperUnderscoreToLowerCamel();
public static final class UpperUnderscoreToLowerCamel implements Function<String, String> {
@Override
public String apply(String from) {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, from);
}
}
private static final Pattern pattern = Pattern.compile("\\{(.+?)\\}");
/**
* replaces tokens that are expressed as <code>{token}</code>
@ -98,6 +120,70 @@ public class Utils {
return initializers.toString();
}
public static final Map<OsFamily, String> OS_TO_POSITIONAL_VAR_PATTERN = ImmutableMap.of(
OsFamily.UNIX, "set {key}=$1\nshift\n", OsFamily.WINDOWS, "set {key}=%1\r\nshift\r\n");
public static final Map<OsFamily, String> OS_TO_LOCAL_VAR_PATTERN = ImmutableMap.of(
OsFamily.UNIX, "set {key}=\"{value}\"\n", OsFamily.WINDOWS, "set {key}={value}\r\n");
/**
* Writes an initialization statement for use inside a script or a function.
*
* @param positionalVariablesInLowerCamelCase
* - transfer the value of args into these statements. Note that there is no check to
* ensure that all source args are indeed present.
*/
public static String writePositionalVars(List<String> positionalVariablesInLowerCamelCase,
OsFamily family) {
StringBuilder initializers = new StringBuilder();
for (String variableInLowerCamelCase : positionalVariablesInLowerCamelCase) {
String key = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE,
variableInLowerCamelCase);
initializers.append(replaceTokens(OS_TO_POSITIONAL_VAR_PATTERN.get(family), ImmutableMap
.of("key", key)));
}
return initializers.toString();
}
/**
* Ensures that variables come from a known source instead of bleeding in from a profile
*
* @param variablesInLowerCamelCase
* - System variables to unset
*/
public static String writeUnsetVariables(List<String> variablesInLowerCamelCase, OsFamily family) {
switch (family) {
case UNIX:
return String.format("unset %s\n", Joiner.on(' ').join(
Iterables.transform(variablesInLowerCamelCase,
FUNCTION_LOWER_CAMEL_TO_UPPER_UNDERSCORE)));
case WINDOWS:
StringBuilder initializers = new StringBuilder();
for (String variableInLowerCamelCase : variablesInLowerCamelCase) {
String key = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE,
variableInLowerCamelCase);
initializers.append(replaceTokens(OS_TO_LOCAL_VAR_PATTERN.get(family), ImmutableMap
.of("key", key, "value", "")));
}
return initializers.toString();
default:
throw new UnsupportedOperationException("unsupported os: " + family);
}
}
public static final Map<OsFamily, String> OS_TO_ZERO_PATH = ImmutableMap.of(OsFamily.WINDOWS,
"set PATH=c:\\windows\\;C:\\windows\\system32\r\n", OsFamily.UNIX,
"export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin\n");
/**
* @return line used to zero out the path of the script such that basic commands such as unix ps
* will work.
*/
public static String writeZeroPath(OsFamily family) {
return OS_TO_ZERO_PATH.get(family);
}
public static final Map<OsFamily, String> OS_TO_SWITCH_PATTERN = ImmutableMap.of(OsFamily.UNIX,
"case ${variable} in\n", OsFamily.WINDOWS, "goto CASE%{variable}\r\n");
@ -108,6 +194,25 @@ public class Utils {
"{value})\n {action}\n ;;\n", OsFamily.WINDOWS,
":CASE_{value}\r\n {action}\r\n GOTO END_SWITCH\r\n");
/**
* Generates a switch statement based on {@code variable}. If its value is found to be a key in
* {@code valueToActions}, the corresponding action is invoked.
*
* <p/>
* Ex. variable is {@code 1} - the first argument to the script<br/>
* and valueToActions is {"start" -> "echo hello", "stop" -> "echo goodbye"}<br/>
* the script created will respond accordingly:<br/>
* {@code ./script start }<br/>
* << returns hello<br/>
* {@code ./script stop }<br/>
* << returns goodbye<br/>
*
* @param variable
* - shell variable to switch on
* @param valueToActions
* - case statements, if the value of the variable matches a key, the corresponding
* value will be invoked.
*/
public static String writeSwitch(String variable, Map<String, String> valueToActions,
OsFamily family) {
StringBuilder switchClause = new StringBuilder();

View File

@ -40,9 +40,8 @@ public class ShellTokenTest {
public void testTokenValueMapUNIX() {
Map<String, String> expected = new ImmutableMap.Builder<String, String>().put("fs", "/").put(
"ps", ":").put("lf", "\n").put("sh", "bash").put("source", ".").put("rem", "#").put(
"args", "$@").put("varstart", "$").put("varend", "").put("shebang", "#!/bin/bash\n")
.put("zeroPath", "export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin\n")
.put("exe", "").build();
"args", "$@").put("varstart", "$").put("varend", "").put("libraryPathVariable",
"LD_LIBRARY_PATH").put("shebang", "#!/bin/bash\n").build();
assertEquals(ShellToken.tokenValueMap(OsFamily.UNIX), expected);
}
@ -51,9 +50,7 @@ public class ShellTokenTest {
Map<String, String> expected = new ImmutableMap.Builder<String, String>().put("fs", "\\")
.put("ps", ";").put("lf", "\r\n").put("sh", "cmd").put("source", "@call").put("rem",
"@rem").put("args", "%*").put("varstart", "%").put("varend", "%").put(
"shebang", "@echo off\r\n").put("zeroPath",
"set PATH=c:\\windows\\;C:\\windows\\system32\r\n").put("exe", ".exe")
.build();
"libraryPathVariable", "PATH").put("shebang", "@echo off\r\n").build();
assertEquals(ShellToken.tokenValueMap(OsFamily.WINDOWS), expected);
}

View File

@ -24,10 +24,13 @@
package org.jclouds.initbuilder.util;
import static org.testng.Assert.assertEquals;
import java.io.UnsupportedEncodingException;
import org.jclouds.initbuilder.domain.OsFamily;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
/**
@ -53,6 +56,26 @@ public class UtilsTest {
"set MAVEN_OPTS=-Xms128m -Xmx256m -XX:+HeapDumpOnOutOfMemoryError\r\n");
}
public void testWritePositionalVarsUNIX() {
assertEquals(Utils.writePositionalVars(ImmutableList.of("host", "port"), OsFamily.UNIX),
"set HOST=$1\nshift\nset PORT=$1\nshift\n");
}
public void testWritePositionalVarsWindows() {
assertEquals(Utils.writePositionalVars(ImmutableList.of("host", "port"), OsFamily.WINDOWS),
"set HOST=%1\r\nshift\r\nset PORT=%1\r\nshift\r\n");
}
public void testWriteUnsetVariablesUNIX() {
assertEquals(Utils.writeUnsetVariables(ImmutableList.of("host", "port"), OsFamily.UNIX),
"unset HOST PORT\n");
}
public void testWriteUnsetVariablesWindows() {
assertEquals(Utils.writeUnsetVariables(ImmutableList.of("host", "port"), OsFamily.WINDOWS),
"set HOST=\r\nset PORT=\r\n");
}
public void testWriteSwitchUNIX() {
assertEquals(Utils.writeSwitch("i", ImmutableMap.of("0", "echo hello zero", "1",
"echo hello one"), OsFamily.UNIX),

View File

@ -1,4 +1,5 @@
#!/bin/bash
unset PATH JAVA_HOME LD_LIBRARY_PATH
export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin
export JAVA_HOME="/apps/jdk1.6"
case $1 in

View File

@ -1,4 +1,7 @@
@echo off
set PATH=
set JAVA_HOME=
set PATH=
set PATH=c:\windows\;C:\windows\system32
set JAVA_HOME=/apps/jdk1.6
goto CASE%1