1 /** 2 * Copyright © DiamondMVC 2018 3 * License: MIT (https://github.com/DiamondMVC/emeralD/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 */ 6 module templates; 7 8 import std.file : dirEntries, SpanMode, isDir, isFile, mkdirRecurse, rmdirRecurse, write, readText, read, exists, append; 9 import std.path : baseName, dirName; 10 import std.stdio : File; 11 import std.string : format, strip; 12 import std.array : split, replace; 13 import std.algorithm : map, endsWith; 14 import std.zip : ZipArchive; 15 16 import meta : thisExeDir; 17 18 /// Collection of templates. 19 private string[string][string] _templates; 20 21 /// Loads the template paths. 22 void loadTemplates() 23 { 24 import std.stdio : writeln; 25 writeln(thisExeDir); 26 foreach (string root; dirEntries(thisExeDir ~ "/templates", SpanMode.shallow)) 27 { 28 if (root.isDir) 29 { 30 auto rootName = baseName(root); 31 32 foreach (string templatePath; dirEntries(root, SpanMode.shallow)) 33 { 34 if (templatePath.isFile) 35 { 36 auto templateName = baseName(templatePath); 37 38 _templates[rootName][templateName] = templatePath; 39 } 40 } 41 } 42 } 43 } 44 45 /// Loads all remote templates. 46 void loadRemoteTemplates() 47 { 48 auto templates = File(thisExeDir ~ "/remotetemplates.emd"); 49 50 foreach (line; templates.byLine.map!(l => l.replace("\r", ""))) 51 { 52 if (!line || !line.length) 53 { 54 continue; 55 } 56 57 auto data = line.split('|'); 58 59 if (data.length != 3) 60 { 61 continue; 62 } 63 64 immutable root = cast(immutable)data[0]; 65 immutable name = cast(immutable)data[1]; 66 immutable url = cast(immutable)data[2]; 67 68 if (root !in _templates || name !in _templates[root]) 69 { 70 import std.net.curl : get, HTTP; 71 72 auto templateResult = cast(string)get!HTTP(url); 73 74 if (templateResult) 75 { 76 auto rootPath = thisExeDir ~ "/templates/" ~ root; 77 78 if (!exists(rootPath)) 79 { 80 mkdirRecurse(rootPath); 81 } 82 83 auto path = rootPath ~ "/" ~ name; 84 85 write(path, templateResult); 86 87 _templates[root][name] = path; 88 } 89 } 90 } 91 } 92 93 /** 94 * Reads a template. 95 * Params: 96 * root = The root of the template. 97 * name = The name of the template. 98 */ 99 string readTemplate(string root, string name) 100 { 101 auto templates = _templates.get(root, null); 102 103 if (!templates) 104 { 105 return null; 106 } 107 108 auto path = templates.get(name, null); 109 110 if (!path) 111 { 112 return null; 113 } 114 115 return readText(path); 116 } 117 118 /** 119 * Adds a remote template. 120 * Params: 121 * root = The root of the template. 122 * name = The name of the template. 123 * url = The url of the template. 124 */ 125 void addRemoteTemplate(string root, string name, string url) 126 { 127 append(thisExeDir ~ "/remotetemplates.emd", "%s|%s|%s\r\n".format(root, name, url)); 128 } 129 130 /** 131 * Adds a remote scaffolding archive. 132 * Params: 133 * name = The name of the scaffolding archive. 134 * url = The url of the archive. (Must be zip.) 135 */ 136 void addRemoteScaffold(string name, string url) 137 { 138 import std.net.curl : download, HTTP; 139 140 if (!url.endsWith(".zip")) 141 { 142 return; 143 } 144 145 auto rootPath = thisExeDir ~ "/scaffold/" ~ name; 146 auto path = rootPath ~ "/__archive.zip"; 147 148 if (!exists(path)) 149 { 150 rmdirRecurse(rootPath); 151 rmdirRecurse(rootPath); 152 } 153 154 download!HTTP(url, path); 155 156 auto zip = new ZipArchive(read(path)); 157 158 159 foreach (name, am; zip.directory) 160 { 161 zip.expand(am); 162 163 auto filePath = (rootPath ~ "/" ~ name).replace("\\", "/"); 164 auto dir = dirName(filePath).replace("\\", "/"); 165 166 if (!exists(dir)) 167 { 168 mkdirRecurse(dir); 169 } 170 171 auto base = baseName(filePath); 172 auto data = base.split("."); 173 174 if (data.length >= 2 && data[0] && data[0].strip().length) 175 { 176 write(filePath, am.expandedData); 177 } 178 } 179 }