1 /** 2 * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Jan 9, 2011 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dvm.dvm.ShellScript; 8 9 import tango.io.device.File; 10 11 import mambo.core._; 12 13 class ShellScript 14 { 15 string path; 16 private string content_; 17 18 string content () 19 { 20 return content_; 21 } 22 23 private string content (string content) 24 { 25 return content_ = content; 26 } 27 28 this (string path = "") 29 { 30 this.path = path; 31 } 32 33 ShellScript allArgs (bool quote = true) 34 { 35 append(Sh.allArgs); 36 return this; 37 } 38 39 ShellScript comment (string c) 40 { 41 append(Sh.comment(c)); 42 return this; 43 } 44 45 ShellScript declareVariable (string name, string value = "", bool local = false) 46 { 47 append(Sh.declareVariable(name, value, local)).nl; 48 return this; 49 } 50 51 ShellScript echoOff () 52 { 53 version (Windows) 54 append(Sh.echoOff).nl; 55 56 return this; 57 } 58 59 ShellScript exec (string name, string args = "") 60 { 61 append(Sh.exec(name, args)); 62 return this; 63 } 64 65 ShellScript export_ (string name, string content, bool quote = true) 66 { 67 append(Sh.export_(name, content, quote)); 68 return this; 69 } 70 71 ShellScript exportPath (string name, string[] args ...) 72 { 73 string content ; 74 75 foreach (i, arg ; args) 76 { 77 if (i != args.length - 1) 78 content ~= arg ~ Sh.separator; 79 80 else 81 content ~= arg; 82 } 83 84 return export_(name, content); 85 } 86 87 ShellScript ifFileIsNotEmpty (string path, void delegate () ifBlock, void delegate () elseBlock = null) 88 { 89 version (Posix) 90 ifStatement("-s " ~ path, ifBlock, elseBlock); 91 92 else 93 ifStatement("exist " ~ path, ifBlock, elseBlock); 94 95 return this; 96 } 97 98 ShellScript ifStatement (string condition, void delegate () ifBlock, void delegate () elseBlock = null) 99 { 100 version (Posix) 101 { 102 append(format("if [ {} ] ; then", condition)).nl.indent; 103 ifBlock(); 104 nl; 105 106 if (elseBlock) 107 { 108 append("else").nl.indent; 109 elseBlock(); 110 nl; 111 } 112 113 append("fi"); 114 } 115 116 else 117 { 118 append(format("if {} (", condition)).nl.indent; 119 ifBlock(); 120 nl; 121 append(")"); 122 123 if (elseBlock) 124 { 125 append(" else (").nl.indent; 126 elseBlock(); 127 nl; 128 append(")"); 129 } 130 } 131 132 return this; 133 } 134 135 ShellScript printError (string message, bool singleQuote = false) 136 { 137 version (Posix) 138 { 139 auto quote = singleQuote ? "'" : `"`; 140 append(format(`echo {}Error: {}{} >&2`, quote, message, quote)); 141 } 142 143 else 144 append(format(`echo Error: {} >&2`, message)); 145 146 return this; 147 } 148 149 ShellScript shebang () 150 { 151 version (Posix) 152 { 153 if (Sh.shebang != "") 154 append(Sh.shebang).nl; 155 } 156 157 return this; 158 } 159 160 ShellScript source (string path) 161 { 162 append(Sh.source(path)); 163 return this; 164 } 165 166 ShellScript variable (string name, bool quote = true) 167 { 168 append(Sh.variable(name, quote)); 169 return this; 170 } 171 172 ShellScript write () 173 { 174 File.set(path, content); 175 return this; 176 } 177 178 ShellScript append (Args...) (Args args) 179 { 180 enum fmt = "{}{}{}{}{}{}{}{}" 181 "{}{}{}{}{}{}{}{}" 182 "{}{}{}{}{}{}{}{}"; 183 184 static assert (Args.length <= fmt.length / 2, "dvm.dvm.ShellScript :: too many arguments"); 185 186 content_ ~= format(fmt[0 .. args.length * 2], args); 187 188 return this; 189 } 190 191 ShellScript nl () 192 { 193 version (Posix) 194 append('\n'); 195 196 else 197 append("\r\n"); 198 199 return this; 200 } 201 202 ShellScript indent () 203 { 204 append('\t'); 205 return this; 206 } 207 } 208 209 struct Sh 210 { 211 static: 212 213 string quote (string str) 214 { 215 return format(`"{}"`, str); 216 } 217 218 version (Posix) 219 { 220 enum shebang = "#!/bin/sh"; 221 enum separator = ":"; 222 223 string allArgs (bool quote = true) 224 { 225 return quote ? `"$@"` : "$@"; 226 } 227 228 string comment (string c) 229 { 230 return "# " ~ c; 231 } 232 233 string declareVariable (string name, string value = "", bool local = false) 234 { 235 string loc = local ? "local " : ""; 236 237 if (value == "") 238 return loc ~ name; 239 240 return format("{}{}={}", loc, name, value); 241 } 242 243 string exec (string name, string args = "") 244 { 245 args = args == "" ? "" : ' ' ~ args; 246 247 return format("exec {}{}", name, args); 248 } 249 250 string export_ (string name, string value, bool quote = true) 251 { 252 return format("{}=\"{}\"\nexport {}", name, value, name); 253 } 254 255 string source (string path, bool quote = true) 256 { 257 return format(". {}", path); 258 } 259 260 string exec (string command) 261 { 262 return format("exec {}", command); 263 } 264 265 string variable (string name, bool quote = true) 266 { 267 return quote ? format(`"${}"`, name) : '$' ~ name; 268 } 269 } 270 271 else version (Windows) 272 { 273 // DMD 1.068 and up optimizes this out causing a linker error 274 //enum shebang = ""; 275 enum echoOff = "@echo off"; 276 enum separator = ";"; 277 278 string allArgs (bool quote = true) 279 { 280 return "%*"; 281 } 282 283 string comment (string c) 284 { 285 return "rem " ~ c; 286 } 287 288 string declareVariable (string name, string value = "", bool local = false) 289 { 290 return format("set {}={}", name, value); 291 } 292 293 string export_ (string name, string content, bool quote = true) 294 { 295 return format("set {}={}", name, content); 296 } 297 298 string source (string path) 299 { 300 return format("call {}", path); 301 } 302 303 string exec (string name, string args = "") 304 { 305 return format("{} {}", name, args); 306 } 307 308 string variable (string name, bool quote = true) 309 { 310 return quote ? format(`"%{}%"`, name) : '%' ~ name ~ '%'; 311 } 312 } 313 } 314 315 string slashSafeSubstitute (string haystack, string needle, string replacement) 316 { 317 import tango.text.Util; 318 319 version (Windows) 320 { 321 needle = needle.substitute("/", "\\").assumeUnique; 322 replacement = replacement.substitute("/", "\\").assumeUnique; 323 } 324 325 return haystack.substitute(needle, replacement).assumeUnique; 326 }