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 auto packageDir()
57 {
58     auto e = std.process.environment.toAA;
59     if ("DUB_PACKAGE_DIR" !in e)
60     {
61         return null;
62     }
63     return e["DUB_PACKAGE_DIR"];
64 }
65 
66 auto dubPackage()
67 {
68     auto e = std.process.environment.toAA;
69     if ("DUB_PACKAGE" !in e)
70     {
71         return null;
72     }
73     return e["DUB_PACKAGE"];
74 }
75 
76 auto getFromDubJsonFromPackageDir(string what)
77 {
78     if (string pd = packageDir)
79     {
80         return getFromDubJson(pd ~ "/dub.json", what);
81     }
82     return null;
83 }
84 
85 string getFromDubSdlFromPackageDir(string what)
86 {
87     if (string pd = packageDir)
88     {
89         return getFromDubSdl(pd ~ "/dub.sdl", what);
90     }
91     return null;
92 }
93 
94 string getFromGit()
95 {
96     auto gitCommand = ["git", "describe", "--dirty"].execute(null, Config.none,
97             size_t.max, packageDir);
98     if (gitCommand.status != 0)
99     {
100         "Cannot get version with git describe --dirty, make sure you have at least one annotated tag"
101             .info;
102         return null;
103     }
104 
105     return gitCommand.output.strip;
106 }
107 
108 string getLicense()
109 {
110     auto what = "license";
111     if (string res = getFromDubJsonFromPackageDir(what))
112     {
113         "Using %s from dub.json '%s'".format(what, res).warning;
114         return res;
115     }
116     if (string res = getFromDubSdlFromPackageDir(what))
117     {
118         "Using %s from dub.sdl '%s'".format(what, res).warning;
119         return res;
120     }
121     throw new Exception("Cannot determine %s".format(what));
122 
123 }
124 
125 string getVersionFromEnv()
126 {
127     return std.process.environment["DUB_PACKAGE_VERSION"];
128 }
129 
130 string getVersion()
131 {
132     auto what = "version";
133     if (string res = getVersionFromEnv())
134     {
135         "Using %s from env".format(res).warning;
136         return res;
137     }
138     if (string res = getFromDubJsonFromPackageDir(what))
139     {
140         "Using %s from dub.json '%s'".format(what, res).warning;
141         return res;
142     }
143     if (string res = getFromDubSdlFromPackageDir(what))
144     {
145         "Using %s from dub.sdl '%s'".format(what, res).warning;
146         return res;
147     }
148     if (string res = getFromGit)
149     {
150         "Using %s from git '%s'".format(what, res).warning;
151         return res;
152     }
153     throw new Exception("Cannot determine %s".format(what));
154 }
155 
156 int main(string[] args)
157 {
158     import std.getopt;
159 
160     class CustomLogger : Logger
161     {
162         this(LogLevel lv) @safe
163         {
164             super(lv);
165         }
166 
167         override void writeLogMsg(ref LogEntry payload)
168         {
169             import std.stdio;
170 
171             writeln(payload.msg);
172         }
173     }
174 
175     sharedLog = new CustomLogger(LogLevel.trace);
176     writeln(args);
177     string packageName = std.process.environment.get("DUB_PACKAGE");
178     auto info = getopt(args, "packageName", &packageName);
179     if (info.helpWanted)
180     {
181         import packageversion.packageversion;
182 
183         defaultGetoptPrinter("packageversion %s. Generate or update a simple packageversion module.".format(VERSION),
184                 info.options);
185         return 0;
186     }
187     if (packageName == null)
188     {
189         defaultGetoptPrinter("Packagename required.", info.options);
190         return 1;
191     }
192     "packageversion for '%s' in '%s'".format(packageName, packageDir).warning;
193 
194     if (packageName != dubPackage)
195     {
196         "Skipping packageversion".warning;
197         return 0;
198     }
199     auto versionText = getVersion();
200     auto license = getLicense();
201 
202     auto file = (packageDir ? packageDir ~ "/" : "./") ~ "out/generated/packageversion/"
203         ~ packageName.replace(".", "/") ~ "/packageversion.d";
204     auto moduleText = "module %s.packageversion;\n".format(packageName);
205     auto nameText = "const NAME = \"%s\";\n".format(packageName);
206     auto packageVersionText = "const VERSION = \"%s\";\n".format(versionText);
207     auto licenseText = "const LICENSE = \"%s\";\n".format(license);
208     auto registerVersionText = "static this()\n{\n    import packageversion;\n    packageversion.registerPackageVersion(NAME, VERSION, LICENSE);\n}\n";
209     auto totalText = moduleText ~ nameText ~ packageVersionText ~ licenseText ~ registerVersionText;
210 
211     if (exists(file))
212     {
213         auto content = file.readText;
214         if (content != totalText)
215         {
216             "Updating packageversion module".warning;
217             file.writeContent(totalText);
218         }
219         else
220         {
221             "Packageversion already up-to-date".warning;
222         }
223     }
224     else
225     {
226         "Writing packageversion module".warning;
227         file.writeContent(totalText);
228     }
229     return 0;
230 }