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