1 /// Generates a D module for package version info.
2 module genPackageVersion.genDModule;
3 
4 import std.array;
5 import scriptlike.only;
6 
7 import genPackageVersion.util;
8 import genPackageVersion.packageVersion;
9 
10 /// Returns path to the output file that was (or would've been) written.
11 string generateDModule(string packageName, string moduleName,
12 	string ver, string timestamp, string timestampIso, string dubExtras)
13 {
14 	// Generate D source code
15 	auto dModule =
16 `/++
17 Generated at `~timestamp~`
18 by gen-package-version `~packageVersion~`: 
19 $(LINK https://github.com/Abscissa/gen-package-version)
20 +/
21 module `~outPackageName~`.`~outModuleName~`;
22 
23 /++
24 Version of this package.
25 +/
26 enum packageVersion = "`~ver~`";
27 
28 /++
29 Human-readable timestamp of when this module was generated.
30 +/
31 enum packageTimestamp = "`~timestamp~`";
32 
33 /++
34 Timestamp of when this module was generated, as an ISO Ext string.
35 Get a SysTime from this via:
36 
37 ------
38 std.datetime.fromISOExtString(packageTimestampISO)
39 ------
40 +/
41 enum packageTimestampISO = "`~timestampIso~`";
42 `~dubExtras;
43 	//logTrace("--------------------------------------");
44 	//logTrace(dModule);
45 	//logTrace("--------------------------------------");
46 	
47 	import std.path : stdBuildPath = buildPath, stdDirName = dirName, dirSeparator;
48 	import scriptlike.file : scriptlikeRead = read, scriptlikeWrite = write;
49 	
50 	// Determine output filepath
51 	auto packagePath = outPackageName.replace(".", dirSeparator);
52 	auto outPath = stdBuildPath(projectSourcePath, packagePath, outModuleName) ~ ".d";
53 	logTrace("outPath: ", outPath);
54 	
55 	// Ensure directory for output file exits
56 	auto outDir = stdDirName(outPath);
57 	failEnforce(exists(Path(outDir)), "Output directory doesn't exist: ", outDir);
58 	failEnforce(isDir(Path(outDir)), "Output directory isn't a directory: ", outDir);
59 	
60 	// Check whether output file should be updated
61 	if(force)
62 		logVerbose(`--force used, skipping "up-to-date" check`);
63 	else
64 	{
65 		if(existsAsFile(outPath))
66 		{
67 			import std.regex;
68 
69 			auto existingModule = cast(string) scriptlikeRead(Path(outPath));
70 			auto adjustedExistingModule = existingModule
71 				.replaceFirst(regex(`Generated at [^\n]*\n`), `Generated at `~timestamp~"\n")
72 				.replaceFirst(regex(`packageTimestamp = "[^"]*";`), `packageTimestamp = "`~timestamp~`";`)
73 				.replaceFirst(regex(`packageTimestampISO = "[^"]*";`), `packageTimestampISO = "`~timestampIso~`";`);
74 
75 			if(adjustedExistingModule == dModule)
76 			{
77 				logVerbose("Existing version file is up-to-date, skipping overwrite of ", outPath);
78 				return outPath;
79 			}
80 		}
81 	}
82 	
83 	// Write the file
84 	logVerbose("Saving to ", outPath);
85 	if(!dryRun)
86 	{
87 		try
88 			scriptlikeWrite(outPath, dModule);
89 		catch(FileException e)
90 			fail(e.msg);
91 	}
92 	
93 	return outPath;
94 }