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;
18 
19 /**
20 * Executes an array of command-line args.
21 * Params:
22 *   args = The command-line args.
23 */
24 void executeCommands(string[] args)
25 {
26   if (!args || !args.length)
27   {
28     return;
29   }
30 
31   if (args[0] == "--shell" || args[0] == "-sh")
32   {
33     if (args.length > 1)
34     {
35       executeShell(args[1 .. $].join(" "));
36     }
37 
38     return;
39   }
40 
41   if (args[0] == "--remote" || args[0] == "-rm")
42   {
43     if (args.length == 4)
44     {
45       import templates;
46 
47       if (args[1] == "--scaffold" || args[1] == "-sc")
48       {
49         addRemoteScaffold(args[2], args[3]);
50       }
51       else
52       {
53         addRemoteTemplate(args[1], args[2], args[3]);
54         loadRemoteTemplates();
55       }
56     }
57 
58     return;
59   }
60 
61   if (args[0] == "--scaffold" || args[0] == "-sc")
62   {
63     if ((args.length == 2 || args.length == 3 || args.length == 4) && args[1] && args[1].length)
64     {
65       bool excludeScaffoldName;
66 
67       foreach (arg; args.dup)
68       {
69         if (arg && arg.length && (arg == "--exclude" || arg == "-ex"))
70         {
71           excludeScaffoldName = true;
72           args = args.filter!(a => a != "--exclude" && a != "-ex").array;
73           break;
74         }
75       }
76 
77       auto scaffoldTemplate = args[1];
78       auto scaffoldPath = (args.length == 3 ? (args[2] ~ "/") : null);
79 
80       if (scaffoldTemplate && scaffoldTemplate.length)
81       {
82         foreach (string item; dirEntries(thisExeDir ~ "/scaffold/" ~ scaffoldTemplate, SpanMode.depth))
83         {
84           auto itemDir = dirName(item);
85           string dirReplace = (thisExeDir ~ "/scaffold/").replace("\\", "/");
86 
87           string dest = (item.replace("\\", "/")).replace(dirReplace, "");
88 
89           if (scaffoldPath && scaffoldPath.length)
90           {
91             dest = scaffoldPath ~ "/" ~ dest;
92           }
93 
94           if (excludeScaffoldName)
95           {
96             dest = dest.replace(scaffoldTemplate ~ "/", "");
97           }
98 
99           if (!exists(dest))
100           {
101             mkdirRecurse(dest);
102           }
103 
104           if (dest.isFile)
105           {
106             write(dest, read(item));
107           }
108         }
109       }
110 
111       return;
112     }
113 
114     return;
115   }
116 
117   string path;
118   bool appending;
119   string root;
120   string templateName;
121   string name;
122   string[] arguments;
123   string remoteUrl;
124   string fileName;
125 
126   foreach (arg; args)
127   {
128     if (!arg || !arg.length)
129     {
130       continue;
131     }
132 
133     if (arg.startsWith("--path=") || arg.startsWith("-p="))
134     {
135       auto pathEndIndex = arg.indexOf('=');
136 
137       if (pathEndIndex < (arg.length - 1))
138       {
139         path = arg[pathEndIndex + 1 .. $];
140       }
141     }
142     else if (arg == "--append" || arg == "-a")
143     {
144       appending = true;
145     }
146     else if (arg.startsWith("--file=") || arg.startsWith("-f="))
147     {
148       auto pathEndIndex = arg.indexOf('=');
149 
150       if (pathEndIndex < (arg.length - 1))
151       {
152         fileName = arg[pathEndIndex + 1 .. $];
153       }
154     }
155     else
156     {
157       if (!root)
158       {
159         root = arg;
160       }
161       else if (!templateName)
162       {
163         templateName = arg;
164       }
165       else if (!name)
166       {
167         name ~= arg;
168       }
169       else
170       {
171         arguments ~= arg;
172       }
173     }
174   }
175 
176   if (!root || !root.length || !templateName || !templateName.length)
177   {
178     return;
179   }
180 
181   if (fileName && fileName.length)
182   {
183     fileName = fileName.replace("$1", name);
184 
185     foreach (i; 0 .. arguments.length)
186     {
187       fileName = fileName.replace("$" ~ to!string(i + 2), arguments[i]);
188     }
189   }
190 
191   if (templateName.endsWith(".emd"))
192   {
193     auto cmdArgs = File(thisExeDir ~ "/templates/" ~ root ~ "/" ~ templateName);
194 
195     foreach (line; cmdArgs.byLine.map!(a => a.replace("\r", "")))
196     {
197       if (!line || !line.length)
198       {
199         continue;
200       }
201 
202       executeCommands(line.split(" ").map!((lineArg)
203       {
204         if (name && name.length)
205         {
206           lineArg = lineArg.replace("$1", name);
207         }
208 
209         foreach (i; 0 .. arguments.length)
210         {
211           lineArg = lineArg.replace("$" ~ to!string(i + 2), arguments[i]);
212         }
213 
214         return cast(string)lineArg;
215       }).array);
216     }
217 
218     return;
219   }
220 
221   if (!name || !name.length)
222   {
223     return;
224   }
225 
226   import templates;
227 
228   auto templateContent = readTemplate(root, templateName);
229 
230   if (!templateContent || !templateContent.length)
231   {
232     return;
233   }
234 
235   templateContent = templateContent.replace("$1", name);
236 
237   foreach (i; 0 .. arguments.length)
238   {
239     templateContent = templateContent.replace("$" ~ to!string(i + 2), arguments[i]);
240   }
241 
242   if (appending)
243   {
244     append(path, templateContent);
245   }
246   else
247   {
248     fileName = fileName ? fileName : name ~ templateName[templateName.indexOf('.') .. $];
249 
250     if (path)
251     {
252       path ~= "/" ~ fileName;
253     }
254     else
255     {
256       path = fileName;
257     }
258 
259     write(path, templateContent);
260   }
261 }