Issue 126: added composite statements

git-svn-id: http://jclouds.googlecode.com/svn/trunk@2358 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-12-01 04:55:51 +00:00
parent 6045cde384
commit 1ffb7d55ab
8 changed files with 186 additions and 39 deletions

View File

@ -27,6 +27,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import org.jclouds.scriptbuilder.domain.OsFamily; import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.scriptbuilder.domain.ShellToken; import org.jclouds.scriptbuilder.domain.ShellToken;
@ -50,10 +51,7 @@ public class ScriptBuilder {
List<Statement> statements = Lists.newArrayList(); List<Statement> statements = Lists.newArrayList();
@VisibleForTesting @VisibleForTesting
List<String> variableScopes = Lists.newArrayList(); Map<String, Map<String, String>> variableScopes = Maps.newLinkedHashMap();
@VisibleForTesting
Map<String, String> functions = Maps.newHashMap();
@VisibleForTesting @VisibleForTesting
List<String> variablesToUnset = Lists.newArrayList("path", "javaHome", "libraryPath"); List<String> variablesToUnset = Lists.newArrayList("path", "javaHome", "libraryPath");
@ -75,9 +73,8 @@ public class ScriptBuilder {
* Exports a variable inside the script * Exports a variable inside the script
*/ */
public ScriptBuilder addEnvironmentVariableScope(String scopeName, Map<String, String> variables) { public ScriptBuilder addEnvironmentVariableScope(String scopeName, Map<String, String> variables) {
variableScopes.add(checkNotNull(scopeName, "scopeName")); variableScopes
functions.put(scopeName, Utils.writeFunction(scopeName, Utils .put(checkNotNull(scopeName, "scopeName"), checkNotNull(variables, "variables"));
.writeVariableExporters(checkNotNull(variables, "variables"))));
return this; return this;
} }
@ -93,6 +90,13 @@ public class ScriptBuilder {
* whether to write a cmd or bash script. * whether to write a cmd or bash script.
*/ */
public String build(final OsFamily osFamily) { public String build(final OsFamily osFamily) {
Map<String, String> functions = Maps.newLinkedHashMap();
functions.put("abort", Utils.writeFunctionFromResource("abort", osFamily));
for (Entry<String, Map<String, String>> entry : variableScopes.entrySet()) {
functions.put(entry.getKey(), Utils.writeFunction(entry.getKey(), Utils
.writeVariableExporters(entry.getValue())));
}
final Map<String, String> tokenValueMap = ShellToken.tokenValueMap(osFamily); final Map<String, String> tokenValueMap = ShellToken.tokenValueMap(osFamily);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append(ShellToken.BEGIN_SCRIPT.to(osFamily)); builder.append(ShellToken.BEGIN_SCRIPT.to(osFamily));
@ -107,10 +111,9 @@ public class ScriptBuilder {
} }
})), osFamily)); })), osFamily));
resolveFunctionDependencies(osFamily); resolveFunctionDependencies(functions, osFamily);
if (functions.size() > 0) { if (functions.size() > 0) {
builder.append(ShellToken.BEGIN_FUNCTIONS.to(osFamily)); builder.append(ShellToken.BEGIN_FUNCTIONS.to(osFamily));
builder.append(Utils.writeFunctionFromResource("abort", osFamily));
for (String function : functions.values()) { for (String function : functions.values()) {
builder.append(Utils.replaceTokens(function, tokenValueMap)); builder.append(Utils.replaceTokens(function, tokenValueMap));
} }
@ -128,7 +131,7 @@ public class ScriptBuilder {
} }
@VisibleForTesting @VisibleForTesting
void resolveFunctionDependencies(final OsFamily osFamily) { void resolveFunctionDependencies(Map<String, String> functions, final OsFamily osFamily) {
Iterable<String> dependentFunctions = Iterables.concat(Iterables.transform(statements, Iterable<String> dependentFunctions = Iterables.concat(Iterables.transform(statements,
new Function<Statement, Iterable<String>>() { new Function<Statement, Iterable<String>>() {
@Override @Override
@ -137,8 +140,8 @@ public class ScriptBuilder {
} }
})); }));
List<String> unresolvedFunctions = Lists.newArrayList(dependentFunctions); List<String> unresolvedFunctions = Lists.newArrayList(dependentFunctions);
Iterables.removeAll(unresolvedFunctions, this.functions.keySet()); Iterables.removeAll(unresolvedFunctions, functions.keySet());
for (String functionName : dependentFunctions) { for (String functionName : unresolvedFunctions) {
functions.put(functionName, Utils.writeFunctionFromResource(functionName, osFamily)); functions.put(functionName, Utils.writeFunctionFromResource(functionName, osFamily));
} }
} }

View File

@ -0,0 +1,66 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.scriptbuilder.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
/**
* Statements used in a shell script
*
* @author Adrian Cole
*/
public class StatementList implements Statement {
public final List<Statement> statements;
public StatementList(Statement... statements) {
this.statements = Lists.newArrayList(checkNotNull(statements, "statements"));
}
public StatementList(Iterable<Statement> statements) {
this.statements = Lists.newArrayList(checkNotNull(statements, "statements"));
}
public String render(OsFamily family) {
StringBuilder statementsBuilder = new StringBuilder();
for (Statement statement : statements) {
statementsBuilder.append(statement.render(family));
}
return statementsBuilder.toString();
}
@Override
public Iterable<String> functionDependecies(OsFamily family) {
List<String> functions = Lists.newArrayList();
for (Statement statement : statements) {
Iterables.addAll(functions, statement.functionDependecies(family));
}
return functions;
}
}

View File

@ -33,6 +33,10 @@ import java.util.Map;
public class Statements { public class Statements {
private static final Kill KILL = new Kill(); private static final Kill KILL = new Kill();
public static Statement newStatementList(Statement... statements) {
return new StatementList(statements);
}
public static Statement switchOn(String variable, Map<String, Statement> valueToActions) { public static Statement switchOn(String variable, Map<String, Statement> valueToActions) {
return new Switch(variable, valueToActions); return new Switch(variable, valueToActions);
} }

View File

@ -50,8 +50,8 @@ public class Switch implements Statement {
OsFamily.UNIX, "esac\n", OsFamily.WINDOWS, ":END_SWITCH\r\n"); OsFamily.UNIX, "esac\n", OsFamily.WINDOWS, ":END_SWITCH\r\n");
public static final Map<OsFamily, String> OS_TO_CASE_PATTERN = ImmutableMap.of(OsFamily.UNIX, public static final Map<OsFamily, String> OS_TO_CASE_PATTERN = ImmutableMap.of(OsFamily.UNIX,
"{value})\n {action} ;;\n", OsFamily.WINDOWS, "{value})\n{action} ;;\n", OsFamily.WINDOWS,
":CASE_{value}\r\n {action} GOTO END_SWITCH\r\n"); ":CASE_{value}\r\n{action} GOTO END_SWITCH\r\n");
private final String variable; private final String variable;
@ -88,7 +88,8 @@ public class Switch implements Statement {
for (Entry<String, Statement> entry : valueToActions.entrySet()) { for (Entry<String, Statement> entry : valueToActions.entrySet()) {
switchClause.append(Utils.replaceTokens(OS_TO_CASE_PATTERN.get(family), ImmutableMap.of( switchClause.append(Utils.replaceTokens(OS_TO_CASE_PATTERN.get(family), ImmutableMap.of(
"value", entry.getKey(), "action", entry.getValue().render(family)))); "value", entry.getKey(), "action", entry.getValue().render(family).replaceAll(
"^", " "))));
} }
switchClause.append(OS_TO_END_SWITCH_PATTERN.get(family)); switchClause.append(OS_TO_END_SWITCH_PATTERN.get(family));

View File

@ -1,8 +1,10 @@
package org.jclouds.scriptbuilder; package org.jclouds.scriptbuilder;
import static org.jclouds.scriptbuilder.domain.Statements.call;
import static org.jclouds.scriptbuilder.domain.Statements.findPid; import static org.jclouds.scriptbuilder.domain.Statements.findPid;
import static org.jclouds.scriptbuilder.domain.Statements.interpret; import static org.jclouds.scriptbuilder.domain.Statements.interpret;
import static org.jclouds.scriptbuilder.domain.Statements.kill; import static org.jclouds.scriptbuilder.domain.Statements.kill;
import static org.jclouds.scriptbuilder.domain.Statements.newStatementList;
import static org.jclouds.scriptbuilder.domain.Statements.switchOn; import static org.jclouds.scriptbuilder.domain.Statements.switchOn;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
@ -27,10 +29,23 @@ import com.google.common.io.Resources;
*/ */
public class ScriptBuilderTest { public class ScriptBuilderTest {
ScriptBuilder testScriptBuilder = new ScriptBuilder().addStatement( ScriptBuilder testScriptBuilder = new ScriptBuilder()
switchOn("1", ImmutableMap.of("start", interpret("echo started{lf}"), "stop", .addEnvironmentVariableScope("default", ImmutableMap.of("runtime", "Moo"))
interpret("echo stopped{lf}")))).addEnvironmentVariableScope("default", .addStatement(
ImmutableMap.of("javaHome", "/apps/jdk1.6")); switchOn(
"1",
ImmutableMap
.of(
"start",
newStatementList(
call("default"),
interpret("echo start {varl}RUNTIME{varr}{lf}")),
"stop",
newStatementList(
call("default"),
interpret("echo stop {varl}RUNTIME{varr}{lf}")),
"status",
newStatementList(interpret("echo status ... the following should be empty, as we haven't sourced the variable\"{varl}RUNTIME{varr}\"{lf}")))));
@Test @Test
public void testBuildSimpleWindows() throws MalformedURLException, IOException { public void testBuildSimpleWindows() throws MalformedURLException, IOException {
@ -94,20 +109,20 @@ public class ScriptBuilderTest {
ScriptBuilder builder = new ScriptBuilder(); ScriptBuilder builder = new ScriptBuilder();
assertEquals(builder.statements.size(), 0); assertEquals(builder.statements.size(), 0);
} }
//
@Test // @Test
public void testExport() { // public void testExport() {
ScriptBuilder builder = new ScriptBuilder(); // ScriptBuilder builder = new ScriptBuilder();
builder.addEnvironmentVariableScope("default", ImmutableMap.of("javaHome", "/apps/jdk1.6")); // builder.addEnvironmentVariableScope("default", ImmutableMap.of("javaHome", "/apps/jdk1.6"));
assertEquals(builder.functions, ImmutableMap.of("default", // assertEquals(builder.functions, ImmutableMap.of("default",
"{fncl}default{fncr} {export} JAVA_HOME={vq}/apps/jdk1.6{vq}{lf}{fnce}")); // "{fncl}default{fncr} {export} JAVA_HOME={vq}/apps/jdk1.6{vq}{lf}{fnce}"));
} // }
//
@Test // @Test
public void testNoExport() { // public void testNoExport() {
ScriptBuilder builder = new ScriptBuilder(); // ScriptBuilder builder = new ScriptBuilder();
assertEquals(builder.functions.size(), 0); // assertEquals(builder.functions.size(), 0);
} // }
@Test(expectedExceptions = NullPointerException.class) @Test(expectedExceptions = NullPointerException.class)
public void testExportNPE() { public void testExportNPE() {

View File

@ -0,0 +1,46 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*/
package org.jclouds.scriptbuilder.domain;
import static org.jclouds.scriptbuilder.domain.Statements.*;
import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "scriptbuilder.StatementListTest")
public class StatementListTest {
Statement statement = newStatementList(call("default"), interpret("echo started{lf}"));
public void testUNIX() {
assertEquals(statement.render(OsFamily.UNIX), "default || return 1\necho started\n");
}
public void testWINDOWS() {
assertEquals(statement.render(OsFamily.WINDOWS),
"call :default\r\nif errorlevel 1 goto abort\r\necho started\r\n");
}
}

View File

@ -7,16 +7,23 @@ GOTO FUNCTION_END
echo aborting: %EXCEPTION% echo aborting: %EXCEPTION%
exit /b 1 exit /b 1
:default :default
set JAVA_HOME=/apps/jdk1.6 set RUNTIME=Moo
exit /b 0 exit /b 0
:FUNCTION_END :FUNCTION_END
set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem set PATH=c:\windows\;C:\windows\system32;c:\windows\system32\wbem
goto CASE%1 goto CASE%1
:CASE_start :CASE_start
echo started call :default
if errorlevel 1 goto abort
echo start %RUNTIME%
GOTO END_SWITCH GOTO END_SWITCH
:CASE_stop :CASE_stop
echo stopped call :default
if errorlevel 1 goto abort
echo stop %RUNTIME%
GOTO END_SWITCH
:CASE_status
echo status ... the following should be empty, as we haven't sourced the variable"%RUNTIME%"
GOTO END_SWITCH GOTO END_SWITCH
:END_SWITCH :END_SWITCH
exit /b 0 exit /b 0

View File

@ -8,16 +8,21 @@ function abort {
exit 1 exit 1
} }
function default { function default {
export JAVA_HOME="/apps/jdk1.6" export RUNTIME="Moo"
return 0 return 0
} }
export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin
case $1 in case $1 in
start) start)
echo started default || exit 1
echo start $RUNTIME
;; ;;
stop) stop)
echo stopped default || exit 1
echo stop $RUNTIME
;;
status)
echo status ... the following should be empty, as we haven't sourced the variable"$RUNTIME"
;; ;;
esac esac
exit 0 exit 0