| /** |
| * Licensed to jclouds, Inc. (jclouds) under one or more |
| * contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. jclouds 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 com.google.common.base.Predicates.instanceOf; |
| import static com.google.common.collect.Iterables.any; |
| import static com.google.common.collect.Lists.newArrayList; |
| import static java.lang.String.format; |
| import static org.jclouds.scriptbuilder.domain.Statements.appendFile; |
| import static org.jclouds.scriptbuilder.domain.Statements.createOrOverwriteFile; |
| import static org.jclouds.scriptbuilder.domain.Statements.exec; |
| import static org.jclouds.scriptbuilder.domain.Statements.interpret; |
| |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.jclouds.scriptbuilder.ExitInsteadOfReturn; |
| import org.jclouds.scriptbuilder.ScriptBuilder; |
| import org.jclouds.scriptbuilder.util.Utils; |
| |
| import com.google.common.base.CaseFormat; |
| import com.google.common.base.Function; |
| import com.google.common.base.Splitter; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableList.Builder; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Iterables; |
| |
| /** |
| * Creates a run script |
| * |
| * @author Adrian Cole |
| */ |
| public class CreateRunScript extends StatementList { |
| public final static String DELIMETER = "END_OF_JCLOUDS_SCRIPT"; |
| final String instanceName; |
| final Iterable<String> exports; |
| final String pwd; |
| |
| public CreateRunScript(String instanceName, Iterable<String> exports, String pwd, Iterable<Statement> statements) { |
| super(statements); |
| this.instanceName = checkNotNull(instanceName, "instanceName"); |
| this.exports = checkNotNull(exports, "exports"); |
| this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}"); |
| } |
| |
| public static class AddExport implements Statement { |
| final String export; |
| final String value; |
| |
| public AddExport(String export, String value) { |
| this.export = checkNotNull(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export), "export"); |
| this.value = checkNotNull(value, "value"); |
| } |
| |
| public static final Map<OsFamily, String> OS_TO_EXPORT_PATTERN = ImmutableMap.of(OsFamily.UNIX, |
| "export {export}='{value}'\n", OsFamily.WINDOWS, "set {export}={value}\r\n"); |
| |
| @Override |
| public Iterable<String> functionDependencies(OsFamily family) { |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public String render(OsFamily family) { |
| return Utils |
| .replaceTokens(OS_TO_EXPORT_PATTERN.get(family), ImmutableMap.of("export", export, "value", value)); |
| } |
| } |
| |
| @Override |
| public Iterable<String> functionDependencies(OsFamily family) { |
| return Collections.emptyList(); |
| } |
| |
| @Override |
| public String render(OsFamily family) { |
| if (checkNotNull(family, "family") == OsFamily.WINDOWS) |
| throw new UnsupportedOperationException("windows not yet implemented"); |
| List<Statement> statements = newArrayList(); |
| final 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))); |
| StringBuilder builder = new StringBuilder(); |
| builder.append("\n"); |
| addUnixRunScriptHeader(runScript, builder); |
| builder.append("\n"); |
| addUnixRunScript(runScript, builder); |
| builder.append("\n"); |
| addUnixRunScriptFooter(runScript, builder); |
| builder.append("\n"); |
| statements.add(interpret(builder.toString())); |
| statements.add(exec("chmod u+x " + runScript)); |
| return new StatementList(statements).render(family); |
| } |
| |
| private void addUnixRunScriptFooter(String runScript, StringBuilder builder) { |
| builder.append("# add runscript footer\n"); |
| Iterable<String> endScript = Splitter.on(ShellToken.LF.to(OsFamily.UNIX)).split( |
| ShellToken.END_SCRIPT.to(OsFamily.UNIX)); |
| builder.append(appendFile(runScript, endScript, DELIMETER).render(OsFamily.UNIX)); |
| } |
| |
| private void addUnixRunScript(String runScript, StringBuilder builder) { |
| builder.append("# add desired commands from the user\n"); |
| Builder<String> userCommands = ImmutableList.<String>builder(); |
| userCommands.add("cd " + pwd); |
| for (Statement statement : statements) { |
| if (statement instanceof Call |
| || (statement instanceof StatementList && any(StatementList.class.cast(statement).delegate(), |
| instanceOf(Call.class)))) { |
| statement = new ExitInsteadOfReturn(statement); |
| } |
| userCommands.addAll(Splitter.on('\n').split(statement.render(OsFamily.UNIX))); |
| } |
| builder.append(appendFile(runScript, userCommands.build(), DELIMETER).render(OsFamily.UNIX)); |
| } |
| |
| private void addUnixRunScriptHeader(String runScript, StringBuilder builder) { |
| builder.append("# create runscript header\n"); |
| |
| Builder<String> beginningOfFile = ImmutableList.<String> builder(); |
| beginningOfFile.addAll(Splitter.on(ShellToken.LF.to(OsFamily.UNIX)).split( |
| ShellToken.BEGIN_SCRIPT.to(OsFamily.UNIX))); |
| beginningOfFile.add(format("PROMPT_COMMAND='echo -ne \\\"\\033]0;%s\\007\\\"'", instanceName)); |
| beginningOfFile.add(Utils.writeZeroPath(OsFamily.UNIX)); |
| beginningOfFile.add(format("export INSTANCE_NAME='%s'", instanceName)); |
| builder.append(createOrOverwriteFile(runScript, beginningOfFile.build(), DELIMETER).render(OsFamily.UNIX)); |
| |
| // expanding variables here. |
| builder.append(AppendFile.builder().path(runScript).delimeter(DELIMETER).expandVariables(true) |
| .lines(Iterables.transform(exports, new Function<String, String>() { |
| |
| @Override |
| public String apply(String export) { |
| String variableNameInUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export); |
| return new StringBuilder().append("export ").append(variableNameInUpper).append("='$") |
| .append(variableNameInUpper).append("'").toString(); |
| } |
| })).build().render(OsFamily.UNIX)); |
| |
| Map<String, String> functionsToWrite = ScriptBuilder.resolveFunctionDependenciesForStatements( |
| ImmutableMap.<String, String> of("abort", Utils.writeFunctionFromResource("abort", OsFamily.UNIX)), |
| statements, OsFamily.UNIX); |
| |
| // if there are more functions than simply abort |
| if (functionsToWrite.size() > 1) { |
| StringBuilder functions = new StringBuilder(); |
| ScriptBuilder.writeFunctions(functionsToWrite, OsFamily.UNIX, functions); |
| builder.append(appendFile(runScript, functions.toString(), DELIMETER).render(OsFamily.UNIX)); |
| } |
| } |
| } |