Newer
Older
dub_jkp / scripts / man / gen_man.d
@Matthias Klumpp Matthias Klumpp on 25 Mar 2018 4 KB gen_man: Fix build with gdc-8
  1. #!/usr/bin/env dub
  2. /+dub.sdl:
  3. dependency "dub" path="../.."
  4. +/
  5.  
  6. import std.algorithm, std.conv, std.format, std.path, std.range, std.stdio;
  7. import dub.commandline;
  8.  
  9. string italic(string w)
  10. {
  11. return `\fI` ~ w ~ `\fR`;
  12. }
  13.  
  14. string bold(string w)
  15. {
  16. return `\fB` ~ w ~ `\fR`;
  17. }
  18.  
  19. string header(string heading)
  20. {
  21. return ".SH " ~ heading;
  22. }
  23.  
  24. string br(string s)
  25. {
  26. return ".BR " ~ s;
  27. }
  28.  
  29. struct Config
  30. {
  31. import std.datetime;
  32. SysTime date;
  33.  
  34. static Config init(){
  35. import std.process : environment;
  36. Config config;
  37. config.date = Clock.currTime;
  38. auto diffable = environment.get("DIFFABLE", "0");
  39. if (diffable == "1")
  40. config.date = SysTime(DateTime(2018, 01, 01));
  41.  
  42. config.cwd = __FILE_FULL_PATH__.dirName;
  43. return config;
  44. }
  45. string cwd;
  46. }
  47.  
  48. void writeHeader(ref File manFile, string manName, const Config config)
  49. {
  50. static immutable manHeader =
  51. `.TH %s 1 "%s" "The D Language Foundation" "The D Language Foundation"
  52. .SH NAME`;
  53. manFile.writefln(manHeader, manName, config.date.toISOExtString.take(10));
  54. }
  55.  
  56. void writeFooter(ref File manFile, string seeAlso, const Config config)
  57. {
  58. static immutable manFooter =
  59. `.SH FILES
  60. \fIdub\&.sdl\fR, \fIdub\&.json\fR
  61. .SH AUTHOR
  62. Copyright (c) 1999-%s by The D Language Foundation
  63. .SH "ONLINE DOCUMENTATION"
  64. .UR http://code.dlang.org/docs/commandline
  65. .UE http://code.dlang.org/docs/commandline
  66. .SH "SEE ALSO"
  67. %s`;
  68. manFile.writefln(manFooter, config.date.year, seeAlso);
  69. }
  70.  
  71. void writeMainManFile(CommandArgs args, CommandGroup[] commands,
  72. string fileName, const Config config)
  73. {
  74. auto manFile = File(config.cwd.buildPath(fileName), "w");
  75. manFile.writeHeader("DUB", config);
  76. auto seeAlso = ["dmd(1)".br, "rdmd(1)"].joiner("\n").to!string;
  77. scope(exit) manFile.writeFooter(seeAlso, config);
  78.  
  79. alias writeln = (m) => manFile.writeln(m);
  80. writeln(`dub \- Package and build management system for D`);
  81. writeln("SYNOPSIS".header);
  82. writeln(`.B dub
  83. [\-\-version]
  84. [\fICOMMAND\fR]
  85. [\fIOPTIONS\&.\&.\&.\fR]
  86. [\-\- [\fIAPPLICATION ARGUMENTS\&.\&.\&.\fR]]`);
  87.  
  88. writeln("DESCRIPTION".header);
  89. writeln(`Manages the DUB project in the current directory\&. DUB can serve as a build
  90. system and a package manager, automatically keeping track of project's
  91. dependencies \- both downloading them and linking them into the application.`);
  92.  
  93. writeln(".SH COMMANDS");
  94. foreach (grp; commands) {
  95. foreach (cmd; grp.commands) {
  96. writeln(".TP");
  97. writeln(cmd.name.bold);
  98. writeln(cmd.helpText.joiner("\n"));
  99. }
  100. }
  101.  
  102. writeln("COMMON OPTIONS".header);
  103. args.writeArgs(manFile);
  104. }
  105.  
  106. string highlightArguments(string args)
  107. {
  108. import std.regex : regex, replaceAll;
  109. static auto re = regex("<([^>]*)>");
  110. static const reReplacement = "<%s>".format(`$1`.italic);
  111. return args.replaceAll(re, reReplacement);
  112. }
  113.  
  114. void writeArgs(CommandArgs args, ref File manFile)
  115. {
  116. alias write = (m) => manFile.write(m);
  117. foreach (arg; args.recognizedArgs)
  118. {
  119. auto names = arg.names.split("|");
  120. assert(names.length == 1 || names.length == 2);
  121. string sarg = names[0].length == 1 ? names[0] : null;
  122. string larg = names[0].length > 1 ? names[0] : names.length > 1 ? names[1] : null;
  123. write(".IP ");
  124. if (sarg !is null) {
  125. write("-%s".format(sarg));
  126. if (larg !is null)
  127. write(", ");
  128. }
  129. if (larg !is null) {
  130. write("--%s".format(larg));
  131. if (!arg.defaultValue.peek!bool)
  132. write("=VALUE");
  133. }
  134. manFile.writeln;
  135. manFile.writeln(arg.helpText.join("\n"));
  136. }
  137. }
  138.  
  139. void writeManFile(Command command, const Config config)
  140. {
  141. import std.uni : toUpper;
  142.  
  143. auto args = new CommandArgs(null);
  144. command.prepare(args);
  145. string fileName = format("dub-%s.1", command.name);
  146. auto manFile = File(config.cwd.buildPath(fileName), "w");
  147. auto manName = format("DUB-%s", command.name).toUpper;
  148. manFile.writeHeader(manName, config);
  149. static immutable seeAlso = ["dmd(1)".br, "dub(1)"].joiner("\n").to!string;
  150. scope(exit) manFile.writeFooter(seeAlso, config);
  151.  
  152. alias writeln = (m) => manFile.writeln(m);
  153. writeln(`dub \- Package and build management system for D`);
  154.  
  155. writeln("SYNOPSIS".header);
  156. writeln("dub %s".format(command.name).bold);
  157. writeln(command.argumentsPattern.highlightArguments);
  158. writeln(`OPTIONS\&.\&.\&.`.italic);
  159. if (command.acceptsAppArgs)
  160. {
  161. writeln("[-- <%s>]".format("application arguments...".italic));
  162. }
  163.  
  164. writeln("DESCRIPTION".header);
  165. writeln(command.helpText.joiner("\n\n"));
  166. writeln("OPTIONS".header);
  167. args.writeArgs(manFile);
  168. }
  169.  
  170. void main()
  171. {
  172. Config config = Config.init;
  173. auto commands = getCommands();
  174.  
  175. // main dub.1
  176. {
  177. CommonOptions options;
  178. auto args = new CommandArgs(null);
  179. options.prepare(args);
  180. args.writeMainManFile(commands, "dub.1", config);
  181. }
  182.  
  183. // options for each specific command
  184. foreach (cmd; commands.map!(a => a.commands).joiner) {
  185. cmd.writeManFile(config);
  186. }
  187. }