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 }