1 /++ 2 + Copyright: Copyright © 2018, Christian Köstlin 3 + License: MIT 4 + Authors: Christian Koestlin, Christian Köstlin 5 +/ 6 module app; 7 8 import std.stdio; 9 import std..string; 10 import std.process; 11 import std.file; 12 import std.path; 13 import std.file; 14 import std.regex; 15 import std.experimental.logger; 16 17 void writeContent(string file, string content) 18 { 19 file.dirName.mkdirRecurse; 20 std.file.write(file, content); 21 } 22 23 auto getFromDubSdl(string path, string what) 24 { 25 try 26 { 27 auto pattern = "^%1$s \"(?P<%1$s>.*)\"$".format(what); 28 auto text = readText(path); 29 auto match = matchFirst(text, regex(pattern, "m")); 30 if (match.empty) 31 { 32 return null; 33 } 34 return match[what]; 35 } 36 catch (FileException e) 37 { 38 return null; 39 } 40 } 41 42 auto getFromDubJson(string path, string what) 43 { 44 try 45 { 46 import std.json; 47 48 return parseJSON(readText(path))[what].str; 49 } 50 catch (FileException e) 51 { 52 return null; 53 } 54 } 55 56 import std.process; 57 58 auto packageDir() 59 { 60 auto e = std.process.environment.toAA; 61 if ("DUB_PACKAGE_DIR" !in e) 62 { 63 return null; 64 } 65 return e["DUB_PACKAGE_DIR"]; 66 } 67 68 auto dubPackage() 69 { 70 auto e = std.process.environment.toAA; 71 if ("DUB_PACKAGE" !in e) 72 { 73 return null; 74 } 75 return e["DUB_PACKAGE"]; 76 } 77 78 auto getFromDubJsonFromPackageDir(string what) 79 { 80 if (string pd = packageDir) 81 { 82 return getFromDubJson(pd ~ "/dub.json", what); 83 } 84 return null; 85 } 86 87 string getFromDubSdlFromPackageDir(string what) 88 { 89 if (string pd = packageDir) 90 { 91 return getFromDubSdl(pd ~ "/dub.sdl", what); 92 } 93 return null; 94 } 95 96 string getFromGit() 97 { 98 auto gitCommand = ["git", "describe", "--dirty"].execute(null, Config.none, 99 size_t.max, packageDir); 100 if (gitCommand.status != 0) 101 { 102 "Cannot get version with git describe --dirty, make sure you have at least one annotated tag" 103 .info; 104 return null; 105 } 106 107 return gitCommand.output.strip; 108 } 109 110 string getLicense() 111 { 112 auto what = "license"; 113 if (string res = getFromDubJsonFromPackageDir(what)) 114 { 115 "Using %s from dub.json '%s'".format(what, res).warning; 116 return res; 117 } 118 if (string res = getFromDubSdlFromPackageDir(what)) 119 { 120 "Using %s from dub.sdl '%s'".format(what, res).warning; 121 return res; 122 } 123 throw new Exception("Cannot determine %s".format(what)); 124 125 } 126 127 string getVersion() 128 { 129 auto what = "version"; 130 if (string res = getFromDubJsonFromPackageDir(what)) 131 { 132 "Using %s from dub.json '%s'".format(what, res).warning; 133 return res; 134 } 135 if (string res = getFromDubSdlFromPackageDir(what)) 136 { 137 "Using %s from dub.sdl '%s'".format(what, res).warning; 138 return res; 139 } 140 if (string res = getFromGit) 141 { 142 "Using %s from git '%s'".format(what, res).warning; 143 return res; 144 } 145 throw new Exception("Cannot determine %s".format(what)); 146 } 147 148 int main(string[] args) 149 { 150 import std.getopt; 151 152 class CustomLogger : Logger 153 { 154 this(LogLevel lv) @safe 155 { 156 super(lv); 157 } 158 159 override void writeLogMsg(ref LogEntry payload) 160 { 161 import std.stdio; 162 163 writeln(payload.msg); 164 } 165 } 166 167 sharedLog = new CustomLogger(LogLevel.trace); 168 169 string packageName = std.process.environment.toAA["DUB_PACKAGE"]; 170 auto info = getopt(args, "packageName", &packageName); 171 if (info.helpWanted) 172 { 173 import packageversion.packageversion; 174 175 defaultGetoptPrinter("packageversion %s. Generate or update a simple packageversion module.".format(VERSION), 176 info.options); 177 return 0; 178 } 179 if (packageName == null) 180 { 181 defaultGetoptPrinter("Packagename required.", info.options); 182 return 1; 183 } 184 "packageversion for '%s' in '%s'".format(packageName, packageDir).warning; 185 186 if (packageName != dubPackage) 187 { 188 "Skipping packageversion".warning; 189 return 0; 190 } 191 auto versionText = getVersion(); 192 auto license = getLicense(); 193 194 auto file = (packageDir ? packageDir ~ "/" : "./") ~ "out/generated/packageversion/" 195 ~ packageName.replace(".", "/") ~ "/packageversion.d"; 196 auto moduleText = "module %s.packageversion;\n".format(packageName); 197 auto nameText = "const NAME = \"%s\";\n".format(packageName); 198 auto packageVersionText = "const VERSION = \"%s\";\n".format(versionText); 199 auto licenseText = "const LICENSE = \"%s\";\n".format(license); 200 auto registerVersionText = "static this()\n{\n import packageversion;\n packageversion.registerPackageVersion(NAME, VERSION, LICENSE);\n}\n"; 201 auto totalText = moduleText ~ nameText ~ packageVersionText ~ licenseText ~ registerVersionText; 202 203 if (exists(file)) 204 { 205 auto content = file.readText; 206 if (content != totalText) 207 { 208 "Updating packageversion module".warning; 209 file.writeContent(totalText); 210 } 211 else 212 { 213 "Packageversion already up-to-date".warning; 214 } 215 } 216 else 217 { 218 "Writing packageversion module".warning; 219 file.writeContent(totalText); 220 } 221 return 0; 222 }