1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.scriptbuilder.domain;
20
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static org.jclouds.scriptbuilder.domain.Statements.interpret;
23
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.regex.Pattern;
29
30 import org.jclouds.scriptbuilder.util.Utils;
31
32 import com.google.common.base.CaseFormat;
33 import com.google.common.base.Splitter;
34 import com.google.common.collect.ImmutableList;
35 import com.google.common.collect.ImmutableMap;
36 import com.google.common.collect.Lists;
37 import com.google.common.collect.Maps;
38
39
40
41
42
43
44 public class CreateRunScript implements Statement {
45 public final static String MARKER = "END_OF_SCRIPT";
46 final String instanceName;
47 final Iterable<String> exports;
48 final String pwd;
49 final Iterable<Statement> statements;
50
51 public CreateRunScript(String instanceName, Iterable<String> exports, String pwd, Iterable<Statement> statements) {
52 this.instanceName = checkNotNull(instanceName, "instanceName");
53 this.exports = checkNotNull(exports, "exports");
54 this.pwd = checkNotNull(pwd, "pwd").replaceAll("[/\\\\]", "{fs}");
55 this.statements = checkNotNull(statements, "statements");
56 }
57
58 public static class AddTitleToFile implements Statement {
59 final String title;
60 final String file;
61
62 public AddTitleToFile(String title, String file) {
63 this.title = checkNotNull(title, "title");
64 this.file = checkNotNull(file, "file");
65 }
66
67 public static final Map<OsFamily, String> OS_TO_TITLE_PATTERN = ImmutableMap.of(OsFamily.UNIX,
68 "echo \"PROMPT_COMMAND='echo -ne \\\"\\033]0;{title}\\007\\\"'\">>{file}\n", OsFamily.WINDOWS,
69 "echo title {title}>>{file}\r\n");
70
71 @Override
72 public Iterable<String> functionDependencies(OsFamily family) {
73 return Collections.emptyList();
74 }
75
76 @Override
77 public String render(OsFamily family) {
78 return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(OS_TO_TITLE_PATTERN.get(family),
79 ImmutableMap.of("title", title, "file", file)));
80 }
81 }
82
83 public static class AddExportToFile implements Statement {
84 final String export;
85 final String value;
86 final String file;
87
88 public AddExportToFile(String export, String value, String file) {
89 this.export = checkNotNull(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export), "export");
90 this.value = checkNotNull(value, "value");
91 this.file = checkNotNull(file, "file");
92 }
93
94 public static final Map<OsFamily, String> OS_TO_EXPORT_PATTERN = ImmutableMap.of(OsFamily.UNIX,
95 "echo \"export {export}='{value}'\">>{file}\n", OsFamily.WINDOWS,
96 "echo set {export}={value}>>{file}\r\n");
97
98 @Override
99 public Iterable<String> functionDependencies(OsFamily family) {
100 return Collections.emptyList();
101 }
102
103 @Override
104 public String render(OsFamily family) {
105 return addSpaceToEnsureWeDontAccidentallyRedirectFd(Utils.replaceTokens(OS_TO_EXPORT_PATTERN.get(family),
106 ImmutableMap.of("export", export, "value", value, "file", file)));
107 }
108 }
109
110 public static String escapeVarTokens(String toEscape, OsFamily family) {
111 Map<String, String> inputToEscape = Maps.newHashMap();
112 for (ShellToken token : ImmutableList.of(ShellToken.VARL, ShellToken.VARR)) {
113 if (!token.to(family).equals("")) {
114 String tokenS = "{" + token.toString().toLowerCase() + "}";
115 inputToEscape.put(tokenS, "{escvar}" + tokenS);
116 }
117 }
118 for (Entry<String, String> entry : inputToEscape.entrySet()) {
119 toEscape = toEscape.replace(entry.getKey(), entry.getValue());
120 }
121 return toEscape;
122 }
123
124 @Override
125 public Iterable<String> functionDependencies(OsFamily family) {
126 return Collections.emptyList();
127 }
128
129 public static final Map<OsFamily, String> OS_TO_CHMOD_PATTERN = ImmutableMap.of(OsFamily.UNIX, "chmod u+x {file}\n",
130 OsFamily.WINDOWS, "");
131
132 @Override
133 public String render(OsFamily family) {
134 List<Statement> statements = Lists.newArrayList();
135 Map<String, String> tokenMap = ShellToken.tokenValueMap(family);
136 String runScript = Utils.replaceTokens(pwd + "{fs}" + instanceName + ".{sh}", tokenMap);
137 statements.add(interpret(String.format("{md} %s{lf}", pwd)));
138 if (family == OsFamily.UNIX) {
139 StringBuilder builder = new StringBuilder();
140 builder.append("\n");
141 addUnixRunScriptHeader(family, runScript, builder);
142 builder.append("\n");
143 addUnixRunScript(runScript, builder);
144 builder.append("\n");
145 addUnixRunScriptFooter(family, runScript, builder);
146 builder.append("\n");
147 statements.add(interpret(builder.toString()));
148 } else {
149 statements.add(interpret(String.format("{rm} %s 2{closeFd}{lf}", runScript)));
150 for (String line : Splitter.on(ShellToken.LF.to(family)).split(ShellToken.BEGIN_SCRIPT.to(family))) {
151 if (!line.equals(""))
152 statements.add(appendToFile(line, runScript, family));
153 }
154 statements.add(new AddTitleToFile(instanceName, runScript));
155 statements.add(appendToFile(Utils.writeZeroPath(family).replace(ShellToken.LF.to(family), ""), runScript,
156 family));
157 statements.add(new AddExportToFile("instanceName", instanceName, runScript));
158 for (String export : exports) {
159 statements
160 .add(new AddExportToFile(export, Utils.replaceTokens("{varl}"
161 + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export) + "{varr}", tokenMap),
162 runScript));
163 }
164 statements.add(appendToFile("{cd} " + pwd, runScript, family));
165 statements.addAll(statements);
166 for (String line : Splitter.on(ShellToken.LF.to(family)).split(ShellToken.END_SCRIPT.to(family))) {
167 if (!line.equals(""))
168 statements.add(appendToFile(line, runScript, family));
169 }
170 }
171 statements
172 .add(interpret(Utils.replaceTokens(OS_TO_CHMOD_PATTERN.get(family), ImmutableMap.of("file", runScript))));
173 return new StatementList(statements).render(family);
174 }
175
176 private void addUnixRunScriptFooter(OsFamily family, String runScript, StringBuilder builder) {
177 builder.append("# add runscript footer\n");
178 builder.append("cat >> ").append(runScript).append(" <<'").append(MARKER).append("'\n");
179 builder.append(ShellToken.END_SCRIPT.to(family));
180 builder.append(MARKER).append("\n");
181 }
182
183 private void addUnixRunScript(String runScript, StringBuilder builder) {
184 builder.append("# add desired commands from the user\n");
185 builder.append("cat >> ").append(runScript).append(" <<'").append(MARKER).append("'\n");
186 builder.append("cd ").append(pwd).append("\n");
187 for (Statement statement : statements) {
188 builder.append(statement.render(OsFamily.UNIX)).append("\n");
189 }
190 builder.append(MARKER).append("\n");
191 }
192
193 private void addUnixRunScriptHeader(OsFamily family, String runScript, StringBuilder builder) {
194 builder.append("# create runscript header\n");
195 builder.append("cat > ").append(runScript).append(" <<").append(MARKER).append("\n");
196 builder.append(ShellToken.BEGIN_SCRIPT.to(family));
197 builder.append("PROMPT_COMMAND='echo -ne \"\\033]0;").append(instanceName).append("\\007\"'\n");
198 builder.append(Utils.writeZeroPath(family));
199 builder.append("export INSTANCE_NAME='").append(instanceName).append("'\n");
200 for (String export : exports) {
201 String variableNameInUpper = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, export);
202 builder.append("export ").append(variableNameInUpper).append("='$").append(variableNameInUpper).append("'\n");
203 }
204 builder.append(MARKER).append("\n");
205 }
206
207 private Statement appendToFile(String line, String runScript, OsFamily family) {
208 String quote = "";
209 if (!ShellToken.VQ.to(family).equals("")) {
210 quote = "'";
211 } else {
212 line = escapeVarTokens(line, family);
213 }
214 return interpret(addSpaceToEnsureWeDontAccidentallyRedirectFd(String.format("echo %s%s%s>>%s{lf}", quote, line,
215 quote, runScript)));
216 }
217
218 public static final Pattern REDIRECT_FD_PATTERN = Pattern.compile(".*[0-2]>>.*");
219
220 static String addSpaceToEnsureWeDontAccidentallyRedirectFd(String line) {
221 return REDIRECT_FD_PATTERN.matcher(line).matches() ? line.replace(">>", " >>") : line;
222 }
223
224 }