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 }