1 /** 2 * Copyright © DiamondMVC 2018 3 * License: MIT (https://github.com/DiamondMVC/emeralD/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 */ 6 module cmd; 7 8 import std.conv : to; 9 import std.array : replace, array, split, join; 10 import std.algorithm : map, endsWith, startsWith, filter; 11 import std.stdio : File; 12 import std.file : write, append, read, isFile, mkdirRecurse, dirEntries, SpanMode, exists; 13 import std.string : indexOf; 14 import std.path : dirName; 15 import std.process : executeShell; 16 17 import meta : thisExeDir, workFolder; 18 import templates; 19 20 /** 21 * Executes an array of command-line args. 22 * Params: 23 * args = The command-line args. 24 */ 25 void executeCommands(string[] args) 26 { 27 if (!args || !args.length) 28 { 29 return; 30 } 31 32 if (args[0] == "--shell" || args[0] == "-sh") 33 { 34 if (args.length > 1) 35 { 36 executeShell(args[1 .. $].join(" "), null, Config.none, size_t.max, workFolder && workFolder.length ? workFolder : null); 37 } 38 39 return; 40 } 41 42 if (args[0] == "--remote" || args[0] == "-rm") 43 { 44 if (args.length == 4) 45 { 46 if (args[1] == "--scaffold" || args[1] == "-sc") 47 { 48 addRemoteScaffold(args[2], args[3]); 49 } 50 else 51 { 52 addRemoteTemplate(args[1], args[2], args[3]); 53 loadRemoteTemplates(); 54 } 55 } 56 57 return; 58 } 59 60 if (args[0] == "--project" || args[0] == "-prj") 61 { 62 if (args.length == 3) 63 { 64 addWorkFolder(args[1], args[2]); 65 66 return; 67 } 68 } 69 70 if (args[0] == "--scaffold" || args[0] == "-sc") 71 { 72 if ((args.length == 2 || args.length == 3 || args.length == 4 || args.length == 5) && args[1] && args[1].length) 73 { 74 bool excludeScaffoldName; 75 76 foreach (arg; args.dup) 77 { 78 if (arg && arg.length && (arg == "--exclude" || arg == "-ex")) 79 { 80 excludeScaffoldName = true; 81 args = args.filter!(a => a != "--exclude" && a != "-ex").array; 82 } 83 else if (arg.startsWith("--project=") || arg.startsWith("-prj=")) 84 { 85 auto nameEndIndex = arg.indexOf('='); 86 87 if (nameEndIndex < (arg.length - 1)) 88 { 89 auto projectName = arg[nameEndIndex + 1 .. $]; 90 91 if (projectName && projectName.length) 92 { 93 setWorkFolder(projectName); 94 } 95 } 96 97 args = args.filter!(a => !a.startsWith("--project") && !a.startsWith("-prj")).array; 98 } 99 } 100 101 auto scaffoldTemplate = args[1]; 102 auto scaffoldPath = (args.length == 3 ? (args[2] ~ "/") : null); 103 104 if (scaffoldTemplate && scaffoldTemplate.length) 105 { 106 foreach (string item; dirEntries(thisExeDir ~ "/scaffold/" ~ scaffoldTemplate, SpanMode.depth)) 107 { 108 auto itemDir = dirName(item); 109 string dirReplace = (thisExeDir ~ "/scaffold/").replace("\\", "/"); 110 111 string dest = (item.replace("\\", "/")).replace(dirReplace, ""); 112 113 if (scaffoldPath && scaffoldPath.length) 114 { 115 dest = scaffoldPath ~ "/" ~ dest; 116 } 117 118 if (excludeScaffoldName) 119 { 120 dest = dest.replace(scaffoldTemplate ~ "/", ""); 121 } 122 123 dest = workFolder ~ dest; 124 auto dirDest = dirName(dest); 125 126 if (!exists(dirDest)) 127 { 128 mkdirRecurse(dirDest); 129 } 130 131 if (item.isFile) 132 { 133 write(dest, read(item)); 134 } 135 } 136 } 137 138 return; 139 } 140 141 return; 142 } 143 144 string path; 145 bool appending; 146 string root; 147 string templateName; 148 string name; 149 string[] arguments; 150 string remoteUrl; 151 string fileName; 152 153 foreach (arg; args) 154 { 155 if (!arg || !arg.length) 156 { 157 continue; 158 } 159 160 if (arg.startsWith("--path=") || arg.startsWith("-p=")) 161 { 162 auto pathEndIndex = arg.indexOf('='); 163 164 if (pathEndIndex < (arg.length - 1)) 165 { 166 path = arg[pathEndIndex + 1 .. $]; 167 } 168 } 169 else if (arg.startsWith("--project=") || arg.startsWith("-prj=")) 170 { 171 auto nameEndIndex = arg.indexOf('='); 172 173 if (nameEndIndex < (arg.length - 1)) 174 { 175 auto projectName = arg[nameEndIndex + 1 .. $]; 176 177 if (projectName && projectName.length) 178 { 179 setWorkFolder(projectName); 180 } 181 } 182 } 183 else if (arg == "--append" || arg == "-a") 184 { 185 appending = true; 186 } 187 else if (arg.startsWith("--file=") || arg.startsWith("-f=")) 188 { 189 auto pathEndIndex = arg.indexOf('='); 190 191 if (pathEndIndex < (arg.length - 1)) 192 { 193 fileName = arg[pathEndIndex + 1 .. $]; 194 } 195 } 196 else 197 { 198 if (!root) 199 { 200 root = arg; 201 } 202 else if (!templateName) 203 { 204 templateName = arg; 205 } 206 else if (!name) 207 { 208 name ~= arg; 209 } 210 else 211 { 212 arguments ~= arg; 213 } 214 } 215 } 216 217 if (!root || !root.length || !templateName || !templateName.length) 218 { 219 return; 220 } 221 222 if (fileName && fileName.length) 223 { 224 fileName = fileName.replace("$1", name); 225 226 foreach (i; 0 .. arguments.length) 227 { 228 fileName = fileName.replace("$" ~ to!string(i + 2), arguments[i]); 229 } 230 } 231 232 if (templateName.endsWith(".emd")) 233 { 234 auto cmdArgs = File(thisExeDir ~ "/templates/" ~ root ~ "/" ~ templateName); 235 236 foreach (line; cmdArgs.byLine.map!(a => a.replace("\r", ""))) 237 { 238 if (!line || !line.length) 239 { 240 continue; 241 } 242 243 executeCommands(line.split(" ").map!((lineArg) 244 { 245 if (name && name.length) 246 { 247 lineArg = lineArg.replace("$1", name); 248 } 249 250 foreach (i; 0 .. arguments.length) 251 { 252 lineArg = lineArg.replace("$" ~ to!string(i + 2), arguments[i]); 253 } 254 255 return cast(string)lineArg; 256 }).array); 257 } 258 259 return; 260 } 261 262 if (!name || !name.length) 263 { 264 return; 265 } 266 267 import templates; 268 269 auto templateContent = readTemplate(root, templateName); 270 271 if (!templateContent || !templateContent.length) 272 { 273 return; 274 } 275 276 templateContent = templateContent.replace("$1", name); 277 278 foreach (i; 0 .. arguments.length) 279 { 280 templateContent = templateContent.replace("$" ~ to!string(i + 2), arguments[i]); 281 } 282 283 if (appending) 284 { 285 append(workFolder ~ path, templateContent); 286 } 287 else 288 { 289 fileName = fileName ? fileName : name ~ templateName[templateName.indexOf('.') .. $]; 290 291 if (path) 292 { 293 path ~= "/" ~ fileName; 294 } 295 else 296 { 297 path = fileName; 298 } 299 300 write(workFolder ~ path, templateContent); 301 } 302 }