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