mirror of https://github.com/apache/jclouds.git
Issue 126: ability to run scripts
git-svn-id: http://jclouds.googlecode.com/svn/trunk@2360 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
df529b2592
commit
c98245a66c
|
@ -0,0 +1,184 @@
|
|||
/**
|
||||
*
|
||||
* 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 static org.jclouds.scriptbuilder.domain.Statements.interpret;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.jclouds.scriptbuilder.util.Utils;
|
||||
|
||||
import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Creates a run script
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class CreateRunScript implements Statement {
|
||||
final String instanceName;
|
||||
final List<String> exports;
|
||||
final String pwd;
|
||||
final String execLine;
|
||||
|
||||
public CreateRunScript(String instanceName, List<String> exports, String pwd, String execLine) {
|
||||
this.instanceName = checkNotNull(instanceName, "instanceName");
|
||||
this.exports = checkNotNull(exports, "exports");
|
||||
this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}");
|
||||
this.execLine = checkNotNull(execLine, "execLine");
|
||||
}
|
||||
|
||||
public static class AddTitleToFile implements Statement {
|
||||
final String title;
|
||||
final String file;
|
||||
|
||||
public AddTitleToFile(String title, String file) {
|
||||
this.title = checkNotNull(title, "title");
|
||||
this.file = checkNotNull(file, "file");
|
||||
}
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_TITLE_PATTERN = ImmutableMap.of(
|
||||
OsFamily.UNIX,
|
||||
"echo \"PROMPT_COMMAND='echo -ne \\\"\\033]0;{title}\\007\\\"'\">>{file}\n",
|
||||
OsFamily.WINDOWS, "echo title {title}>>{file}\r\n");
|
||||
|
||||
@Override
|
||||
public Iterable<String> functionDependecies(OsFamily family) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String render(OsFamily family) {
|
||||
return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(
|
||||
OS_TO_TITLE_PATTERN.get(family), ImmutableMap.of("title", title, "file", file)));
|
||||
}
|
||||
}
|
||||
|
||||
public static class AddExportToFile implements Statement {
|
||||
final String export;
|
||||
final String value;
|
||||
final String file;
|
||||
|
||||
public AddExportToFile(String export, String value, String file) {
|
||||
this.export = checkNotNull(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export),
|
||||
"export");
|
||||
this.value = checkNotNull(value, "value");
|
||||
this.file = checkNotNull(file, "file");
|
||||
}
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_EXPORT_PATTERN = ImmutableMap.of(
|
||||
OsFamily.UNIX, "echo \"export {export}='{value}'\">>{file}\n", OsFamily.WINDOWS,
|
||||
"echo set {export}={value}>>{file}\r\n");
|
||||
|
||||
@Override
|
||||
public Iterable<String> functionDependecies(OsFamily family) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String render(OsFamily family) {
|
||||
return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(
|
||||
OS_TO_EXPORT_PATTERN.get(family), ImmutableMap.of("export", export, "value",
|
||||
value, "file", file)));
|
||||
}
|
||||
}
|
||||
|
||||
public static String escapeVarTokens(String toEscape, OsFamily family) {
|
||||
Map<String, String> inputToEscape = Maps.newHashMap();
|
||||
for (ShellToken token : ImmutableList.of(ShellToken.VARL, ShellToken.VARR)) {
|
||||
if (!token.to(family).equals("")) {
|
||||
String tokenS = "{" + token.toString().toLowerCase() + "}";
|
||||
inputToEscape.put(tokenS, "{escvar}" + tokenS);
|
||||
}
|
||||
}
|
||||
for (Entry<String, String> entry : inputToEscape.entrySet()) {
|
||||
toEscape = toEscape.replace(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return toEscape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> functionDependecies(OsFamily family) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_CHMOD_PATTERN = ImmutableMap.of(OsFamily.UNIX,
|
||||
"chmod u+x {file}\n", OsFamily.WINDOWS, "");
|
||||
|
||||
@Override
|
||||
public String render(OsFamily family) {
|
||||
List<Statement> statements = Lists.newArrayList();
|
||||
Map<String, String> tokenMap = ShellToken.tokenValueMap(family);
|
||||
String runScript = Utils.replaceTokens(pwd + "{fs}" + instanceName + ".{sh}", tokenMap);
|
||||
statements.add(interpret(String.format("{md} %s{lf}", pwd)));
|
||||
statements.add(interpret(String.format("{rm} %s 2{closeFd}{lf}", runScript)));
|
||||
for (String line : Splitter.on(ShellToken.LF.to(family)).split(
|
||||
ShellToken.BEGIN_SCRIPT.to(family))) {
|
||||
if (!line.equals(""))
|
||||
statements.add(appendToFile(line, runScript, family));
|
||||
}
|
||||
statements.add(new AddTitleToFile(instanceName, runScript));
|
||||
statements.add(new AddExportToFile("instanceName", instanceName, runScript));
|
||||
for (String export : exports) {
|
||||
statements.add(new AddExportToFile(export, Utils.replaceTokens("{varl}"
|
||||
+ CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export) + "{varr}",
|
||||
tokenMap), runScript));
|
||||
}
|
||||
statements.add(appendToFile("{cd} " + pwd, runScript, family));
|
||||
statements.add(appendToFile(execLine, runScript, family));
|
||||
for (String line : Splitter.on(ShellToken.LF.to(family)).split(
|
||||
ShellToken.END_SCRIPT.to(family))) {
|
||||
if (!line.equals(""))
|
||||
statements.add(appendToFile(line, runScript, family));
|
||||
}
|
||||
statements.add(interpret(Utils.replaceTokens(OS_TO_CHMOD_PATTERN.get(family), ImmutableMap
|
||||
.of("file", runScript))));
|
||||
return new StatementList(statements).render(family);
|
||||
}
|
||||
|
||||
private Statement appendToFile(String line, String runScript, OsFamily family) {
|
||||
String quote = "";
|
||||
if (!ShellToken.VQ.to(family).equals("")) {
|
||||
quote = "'";
|
||||
} else {
|
||||
line = escapeVarTokens(line, family);
|
||||
}
|
||||
return interpret(addSpaceToEnsureWeDontAccidentallyRedirectFd(String.format(
|
||||
"echo %s%s%s>>%s{lf}", quote, line, quote, runScript)));
|
||||
}
|
||||
|
||||
static String addSpaceToEnsureWeDontAccidentallyRedirectFd(String line) {
|
||||
return line.matches(".*[0-2]>>.*") ? line.replace(">>", " >>") : line;
|
||||
}
|
||||
|
||||
}
|
|
@ -39,7 +39,7 @@ import com.google.common.collect.Maps;
|
|||
*/
|
||||
public enum ShellToken {
|
||||
|
||||
FS, PS,
|
||||
FS, RM, CD, TMP, UID, ROOT, CLOSE_FD, PS, MD, ESCVAR,
|
||||
|
||||
/**
|
||||
* If variable values need to be quoted when they include spaces, this will contain quotation
|
||||
|
@ -96,7 +96,6 @@ public enum ShellToken {
|
|||
case UNIX:
|
||||
return "function ";
|
||||
}
|
||||
|
||||
case FNCR:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
|
@ -111,6 +110,13 @@ public enum ShellToken {
|
|||
case UNIX:
|
||||
return " return 0\n}\n";
|
||||
}
|
||||
case ESCVAR:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "%";
|
||||
case UNIX:
|
||||
return "\\";
|
||||
}
|
||||
case PS:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
|
@ -118,6 +124,27 @@ public enum ShellToken {
|
|||
case UNIX:
|
||||
return ":";
|
||||
}
|
||||
case CLOSE_FD:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return ">NUL";
|
||||
case UNIX:
|
||||
return ">&-";
|
||||
}
|
||||
case RM:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "del";
|
||||
case UNIX:
|
||||
return "rm";
|
||||
}
|
||||
case MD:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "md";
|
||||
case UNIX:
|
||||
return "mkdir -p";
|
||||
}
|
||||
case VQ:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
|
@ -174,6 +201,27 @@ public enum ShellToken {
|
|||
case UNIX:
|
||||
return "exit";
|
||||
}
|
||||
case ROOT:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "c:\\";
|
||||
case UNIX:
|
||||
return "/";
|
||||
}
|
||||
case TMP:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "%TEMP%";
|
||||
case UNIX:
|
||||
return "/tmp";
|
||||
}
|
||||
case UID:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "%USERNAME%";
|
||||
case UNIX:
|
||||
return "$USER";
|
||||
}
|
||||
case LF:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
|
@ -202,6 +250,13 @@ public enum ShellToken {
|
|||
case UNIX:
|
||||
return ".";
|
||||
}
|
||||
case CD:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
return "cd /d";
|
||||
case UNIX:
|
||||
return "cd";
|
||||
}
|
||||
case REM:
|
||||
switch (family) {
|
||||
case WINDOWS:
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.scriptbuilder.domain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -45,6 +46,11 @@ public class Statements {
|
|||
return new Call(function, args);
|
||||
}
|
||||
|
||||
public static Statement createRunScript(String instanceName, List<String> exports, String pwd,
|
||||
String execLine) {
|
||||
return new CreateRunScript(instanceName, exports, pwd, execLine);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the pid into the variable {@code FOUND_PID} if successful.
|
||||
*
|
||||
|
|
|
@ -51,8 +51,8 @@ public class SwitchArg implements Statement {
|
|||
OsFamily.UNIX, "esac\n", OsFamily.WINDOWS, ":END_SWITCH\r\n");
|
||||
|
||||
public static final Map<OsFamily, String> OS_TO_CASE_PATTERN = ImmutableMap.of(OsFamily.UNIX,
|
||||
"{value})\n{action} ;;\n", OsFamily.WINDOWS,
|
||||
":CASE_{value}\r\n{action} GOTO END_SWITCH\r\n");
|
||||
"{value})\n{action};;\n", OsFamily.WINDOWS,
|
||||
":CASE_{value}\r\n{action}GOTO END_SWITCH\r\n");
|
||||
|
||||
private final int arg;
|
||||
|
||||
|
@ -91,7 +91,8 @@ public class SwitchArg implements Statement {
|
|||
for (Entry<String, Statement> entry : valueToActions.entrySet()) {
|
||||
switchClause.append(Utils.replaceTokens(OS_TO_CASE_PATTERN.get(family), ImmutableMap.of(
|
||||
"value", entry.getKey(), "action", entry.getValue().render(family).replaceAll(
|
||||
"^", " "))));
|
||||
"^", " ").replace(ShellToken.LF.to(family),
|
||||
ShellToken.LF.to(family) + " "))));
|
||||
}
|
||||
|
||||
switchClause.append(OS_TO_END_SWITCH_PATTERN.get(family));
|
||||
|
|
|
@ -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 org.jclouds.scriptbuilder.domain.Statements.createRunScript;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.io.Resources;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "scriptbuilder.CreateRunScriptTest")
|
||||
public class CreateRunScriptTest {
|
||||
Statement statement = createRunScript("yahooprod", ImmutableList.<String> of("javaHome"),
|
||||
"{tmp}{fs}{uid}{fs}scripttest",
|
||||
"echo {varl}JAVA_HOME{varr}{fs}bin{fs}java -DinstanceName={varl}INSTANCE_NAME{varr} myServer.Main");
|
||||
|
||||
public void testUNIX() throws IOException {
|
||||
assertEquals(statement.render(OsFamily.UNIX),CharStreams.toString(Resources
|
||||
.newReaderSupplier(Resources.getResource("test_runrun."
|
||||
+ ShellToken.SH.to(OsFamily.UNIX)), Charsets.UTF_8)));
|
||||
}
|
||||
|
||||
public void testWINDOWS() throws IOException {
|
||||
assertEquals(statement.render(OsFamily.WINDOWS),CharStreams.toString(Resources
|
||||
.newReaderSupplier(Resources.getResource("test_runrun."
|
||||
+ ShellToken.SH.to(OsFamily.WINDOWS)), Charsets.UTF_8)));
|
||||
}
|
||||
|
||||
public void testRedirectGuard(){
|
||||
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo>>"),"foo>>");
|
||||
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo0>>"),"foo0 >>");
|
||||
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo1>>"),"foo1 >>");
|
||||
assertEquals(CreateRunScript.addSpaceToEnsureWeDontAccidentallyRedirectFd("foo2>>"),"foo2 >>");
|
||||
}
|
||||
|
||||
}
|
|
@ -47,20 +47,24 @@ public class ShellTokenTest {
|
|||
"#!/bin/bash\nset +u\nshopt -s xpg_echo\nshopt -s expand_aliases\n").put(
|
||||
"endScript", "exit 0\n").put("vq", "\"").put("beginFunctions", "").put(
|
||||
"endFunctions", "").put("fncl", "function ").put("fncr", " {\n").put("fnce",
|
||||
" return 0\n}\n").put("export", "export").build();
|
||||
|
||||
" return 0\n}\n").put("export", "export").put("rm", "rm").put("cd", "cd").put(
|
||||
"tmp", "/tmp").put("uid", "$USER").put("root", "/").put("closeFd", ">&-").put("md",
|
||||
"mkdir -p").put("escvar", "\\").build();
|
||||
assertEquals(ShellToken.tokenValueMap(OsFamily.UNIX), expected);
|
||||
}
|
||||
|
||||
public void testTokenValueMapWindows() {
|
||||
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("varl", "%").put("exit", "exit /b").put("varr",
|
||||
"%").put("libraryPathVariable", "PATH").put("return", "exit /b").put("vq",
|
||||
"").put("beginFunctions", "GOTO FUNCTION_END\r\n").put("endFunctions",
|
||||
"@rem").put("args", "%*").put("varl", "%").put("exit", "exit /b").put(
|
||||
"varr", "%").put("libraryPathVariable", "PATH").put("return", "exit /b")
|
||||
.put("vq", "").put("beginFunctions", "GOTO FUNCTION_END\r\n").put("endFunctions",
|
||||
":FUNCTION_END\r\n").put("beginScript", "@echo off\r\n").put("endScript",
|
||||
"exit /b 0\r\n").put("fncl", ":").put("fncr", "\r\n").put("fnce",
|
||||
" exit /b 0\r\n").put("export", "set").build();
|
||||
" exit /b 0\r\n").put("export", "set").put("rm", "del")
|
||||
.put("cd", "cd /d").put("tmp", "%TEMP%").put("uid", "%USERNAME%")
|
||||
.put("root", "c:\\").put("closeFd", ">NUL").put("md", "md").put("escvar", "%")
|
||||
.build();
|
||||
|
||||
assertEquals(ShellToken.tokenValueMap(OsFamily.WINDOWS), expected);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
md %TEMP%\%USERNAME%\scripttest
|
||||
del %TEMP%\%USERNAME%\scripttest\yahooprod.cmd 2>NUL
|
||||
echo @echo off>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
||||
echo title yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
||||
echo set INSTANCE_NAME=yahooprod>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
||||
echo set JAVA_HOME=%JAVA_HOME%>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
||||
echo cd /d %TEMP%\%USERNAME%\scripttest>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
||||
echo echo %%JAVA_HOME%%\bin\java -DinstanceName=%%INSTANCE_NAME%% myServer.Main>>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
||||
echo exit /b 0 >>%TEMP%\%USERNAME%\scripttest\yahooprod.cmd
|
|
@ -0,0 +1,13 @@
|
|||
mkdir -p /tmp/$USER/scripttest
|
||||
rm /tmp/$USER/scripttest/yahooprod.sh 2>&-
|
||||
echo '#!/bin/bash'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo 'set +u'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo 'shopt -s xpg_echo'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo 'shopt -s expand_aliases'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo "PROMPT_COMMAND='echo -ne \"\033]0;yahooprod\007\"'">>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo "export INSTANCE_NAME='yahooprod'">>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo "export JAVA_HOME='$JAVA_HOME'">>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo 'cd /tmp/$USER/scripttest'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo 'echo $JAVA_HOME/bin/java -DinstanceName=$INSTANCE_NAME myServer.Main'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
echo 'exit 0'>>/tmp/$USER/scripttest/yahooprod.sh
|
||||
chmod u+x /tmp/$USER/scripttest/yahooprod.sh
|
|
@ -19,13 +19,13 @@ if not "%1" == "start" if not "%1" == "stop" if not "%1" == "status" (
|
|||
goto CASE_%1
|
||||
:CASE_start
|
||||
call :default
|
||||
if errorlevel 1 goto abort
|
||||
echo start %RUNTIME%
|
||||
if errorlevel 1 goto abort
|
||||
echo start %RUNTIME%
|
||||
GOTO END_SWITCH
|
||||
:CASE_stop
|
||||
call :default
|
||||
if errorlevel 1 goto abort
|
||||
echo stop %RUNTIME%
|
||||
if errorlevel 1 goto abort
|
||||
echo stop %RUNTIME%
|
||||
GOTO END_SWITCH
|
||||
:CASE_status
|
||||
echo the following should be []: [%RUNTIME%]
|
||||
|
|
|
@ -15,11 +15,11 @@ export PATH=/usr/ucb/bin:/bin:/usr/bin:/usr/sbin
|
|||
case $1 in
|
||||
start)
|
||||
default || exit 1
|
||||
echo start $RUNTIME
|
||||
echo start $RUNTIME
|
||||
;;
|
||||
stop)
|
||||
default || exit 1
|
||||
echo stop $RUNTIME
|
||||
echo stop $RUNTIME
|
||||
;;
|
||||
status)
|
||||
echo "the following should be []: [$RUNTIME]"
|
||||
|
|
Loading…
Reference in New Issue