View Javadoc

1   /**
2    *
3    * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4    *
5    * ====================================================================
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   * ====================================================================
18   */
19  package org.jclouds.scriptbuilder;
20  
21  import static com.google.common.base.Preconditions.checkNotNull;
22  
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Map.Entry;
26  
27  import org.jclouds.scriptbuilder.domain.OsFamily;
28  import org.jclouds.scriptbuilder.domain.ShellToken;
29  import org.jclouds.scriptbuilder.domain.Statement;
30  import org.jclouds.scriptbuilder.util.Utils;
31  
32  import com.google.common.annotations.VisibleForTesting;
33  import com.google.common.base.Function;
34  import com.google.common.collect.ImmutableSet;
35  import com.google.common.collect.Iterables;
36  import com.google.common.collect.Lists;
37  import com.google.common.collect.Maps;
38  
39  /**
40   * Creates a shell script.
41   * 
42   * @author Adrian Cole
43   */
44  public class ScriptBuilder implements Statement {
45  
46     @VisibleForTesting
47     List<Statement> statements = Lists.newArrayList();
48  
49     @VisibleForTesting
50     Map<String, Map<String, String>> variableScopes = Maps.newLinkedHashMap();
51  
52     @VisibleForTesting
53     List<String> variablesToUnset = Lists.newArrayList("path", "javaHome", "libraryPath");
54  
55     public ScriptBuilder addStatement(Statement statement) {
56        statements.add(checkNotNull(statement, "statement"));
57        return this;
58     }
59  
60     /**
61      * Unsets a variable to ensure it is set within the script.
62      */
63     public ScriptBuilder unsetEnvironmentVariable(String name) {
64        variablesToUnset.add(checkNotNull(name, "name"));
65        return this;
66     }
67  
68     /**
69      * Exports a variable inside the script
70      */
71     public ScriptBuilder addEnvironmentVariableScope(String scopeName, Map<String, String> variables) {
72        variableScopes.put(checkNotNull(scopeName, "scopeName"), checkNotNull(variables, "variables"));
73        return this;
74     }
75  
76     /**
77      * builds the shell script, by adding the following
78      * <ol>
79      * <li>shell declaration line</li>
80      * <li>variable exports</li>
81      * <li>case/switch</li>
82      * </ol>
83      * 
84      * @param osFamily
85      *           whether to write a cmd or bash script.
86      */
87  
88     @Override
89     public String render(OsFamily osFamily) {
90        Map<String, String> functions = Maps.newLinkedHashMap();
91        functions.put("abort", Utils.writeFunctionFromResource("abort", osFamily));
92  
93        for (Entry<String, Map<String, String>> entry : variableScopes.entrySet()) {
94           functions.put(entry.getKey(), Utils.writeFunction(entry.getKey(), Utils.writeVariableExporters(entry
95                    .getValue())));
96        }
97        final Map<String, String> tokenValueMap = ShellToken.tokenValueMap(osFamily);
98        StringBuilder builder = new StringBuilder();
99        builder.append(ShellToken.BEGIN_SCRIPT.to(osFamily));
100       builder.append(Utils.writeUnsetVariables(Lists.newArrayList(Iterables.transform(variablesToUnset,
101                new Function<String, String>() {
102                   @Override
103                   public String apply(String from) {
104                      if (tokenValueMap.containsKey(from + "Variable"))
105                         return Utils.FUNCTION_UPPER_UNDERSCORE_TO_LOWER_CAMEL.apply(tokenValueMap
106                                  .get(from + "Variable"));
107                      return from;
108                   }
109 
110                })), osFamily));
111       resolveFunctionDependencies(functions, osFamily);
112       if (functions.size() > 0) {
113          builder.append(ShellToken.BEGIN_FUNCTIONS.to(osFamily));
114          for (String function : functions.values()) {
115             builder.append(Utils.replaceTokens(function, tokenValueMap));
116          }
117          builder.append(ShellToken.END_FUNCTIONS.to(osFamily));
118       }
119       builder.append(Utils.writeZeroPath(osFamily));
120       StringBuilder statementBuilder = new StringBuilder();
121       for (Statement statement : statements) {
122          statementBuilder.append(statement.render(osFamily));
123       }
124       builder.append(statementBuilder.toString().replaceAll(ShellToken.RETURN.to(osFamily),
125                ShellToken.EXIT.to(osFamily)));
126       builder.append(ShellToken.END_SCRIPT.to(osFamily));
127       return builder.toString();
128    }
129 
130    @VisibleForTesting
131    void resolveFunctionDependencies(Map<String, String> functions, final OsFamily osFamily) {
132       Iterable<String> dependentFunctions = Iterables.concat(Iterables.transform(statements,
133                new Function<Statement, Iterable<String>>() {
134                   @Override
135                   public Iterable<String> apply(Statement from) {
136                      return from.functionDependencies(osFamily);
137                   }
138                }));
139       List<String> unresolvedFunctions = Lists.newArrayList(dependentFunctions);
140       Iterables.removeAll(unresolvedFunctions, functions.keySet());
141       for (String functionName : unresolvedFunctions) {
142          functions.put(functionName, Utils.writeFunctionFromResource(functionName, osFamily));
143       }
144    }
145 
146    @Override
147    public Iterable<String> functionDependencies(OsFamily family) {
148       return ImmutableSet.<String> of();
149    }
150 }