kochdocs.nim 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. ## Part of 'koch' responsible for the documentation generation.
  2. import os, strutils, osproc
  3. const
  4. gaCode* = " --doc.googleAnalytics:UA-48159761-1"
  5. nimArgs = "--hint[Conf]:off --hint[Path]:off --hint[Processing]:off -d:boot --putenv:nimversion=$#" % system.NimVersion
  6. gitUrl = "https://github.com/nim-lang/Nim"
  7. docHtmlOutput = "doc/html"
  8. webUploadOutput = "web/upload"
  9. docHackDir = "tools/dochack"
  10. proc exe*(f: string): string =
  11. result = addFileExt(f, ExeExt)
  12. when defined(windows):
  13. result = result.replace('/','\\')
  14. proc findNim*(): string =
  15. var nim = "nim".exe
  16. result = "bin" / nim
  17. if existsFile(result): return
  18. for dir in split(getEnv("PATH"), PathSep):
  19. if existsFile(dir / nim): return dir / nim
  20. # assume there is a symlink to the exe or something:
  21. return nim
  22. proc exec*(cmd: string, errorcode: int = QuitFailure, additionalPath = "") =
  23. let prevPath = getEnv("PATH")
  24. if additionalPath.len > 0:
  25. var absolute = additionalPATH
  26. if not absolute.isAbsolute:
  27. absolute = getCurrentDir() / absolute
  28. echo("Adding to $PATH: ", absolute)
  29. putEnv("PATH", (if prevPath.len > 0: prevPath & PathSep else: "") & absolute)
  30. echo(cmd)
  31. if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
  32. putEnv("PATH", prevPath)
  33. template inFold*(desc, body) =
  34. if existsEnv("TRAVIS"):
  35. echo "travis_fold:start:" & desc.replace(" ", "_")
  36. body
  37. if existsEnv("TRAVIS"):
  38. echo "travis_fold:end:" & desc.replace(" ", "_")
  39. proc execFold*(desc, cmd: string, errorcode: int = QuitFailure, additionalPath = "") =
  40. ## Execute shell command. Add log folding on Travis CI.
  41. # https://github.com/travis-ci/travis-ci/issues/2285#issuecomment-42724719
  42. inFold(desc):
  43. exec(cmd, errorcode, additionalPath)
  44. proc execCleanPath*(cmd: string,
  45. additionalPath = ""; errorcode: int = QuitFailure) =
  46. # simulate a poor man's virtual environment
  47. let prevPath = getEnv("PATH")
  48. when defined(windows):
  49. let CleanPath = r"$1\system32;$1;$1\System32\Wbem" % getEnv"SYSTEMROOT"
  50. else:
  51. const CleanPath = r"/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin"
  52. putEnv("PATH", CleanPath & PathSep & additionalPath)
  53. echo(cmd)
  54. if execShellCmd(cmd) != 0: quit("FAILURE", errorcode)
  55. putEnv("PATH", prevPath)
  56. proc nimexec*(cmd: string) =
  57. # Consider using `nimCompile` instead
  58. exec findNim() & " " & cmd
  59. proc nimCompile*(input: string, outputDir = "bin", mode = "c", options = "") =
  60. let output = outputDir / input.splitFile.name.exe
  61. let cmd = findNim() & " " & mode & " -o:" & output & " " & options & " " & input
  62. exec cmd
  63. proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options = "") =
  64. let output = outputDir / input.splitFile.name.exe
  65. let cmd = findNim() & " " & mode & " -o:" & output & " " & options & " " & input
  66. execFold(desc, cmd)
  67. const
  68. pdf = """
  69. doc/manual.rst
  70. doc/lib.rst
  71. doc/tut1.rst
  72. doc/tut2.rst
  73. doc/tut3.rst
  74. doc/nimc.rst
  75. doc/niminst.rst
  76. doc/gc.rst
  77. """.splitWhitespace()
  78. rst2html = """
  79. doc/intern.rst
  80. doc/apis.rst
  81. doc/lib.rst
  82. doc/manual.rst
  83. doc/manual_experimental.rst
  84. doc/tut1.rst
  85. doc/tut2.rst
  86. doc/tut3.rst
  87. doc/nimc.rst
  88. doc/hcr.rst
  89. doc/overview.rst
  90. doc/filters.rst
  91. doc/tools.rst
  92. doc/niminst.rst
  93. doc/nimgrep.rst
  94. doc/gc.rst
  95. doc/estp.rst
  96. doc/idetools.rst
  97. doc/docgen.rst
  98. doc/koch.rst
  99. doc/backends.rst
  100. doc/nimsuggest.rst
  101. doc/nep1.rst
  102. doc/nims.rst
  103. doc/contributing.rst
  104. doc/codeowners.rst
  105. doc/packaging.rst
  106. doc/manual/var_t_return.rst
  107. """.splitWhitespace()
  108. doc = """
  109. lib/system.nim
  110. lib/system/io.nim
  111. lib/system/nimscript.nim
  112. lib/system/assertions.nim
  113. lib/system/iterators.nim
  114. lib/system/dollars.nim
  115. lib/system/widestrs.nim
  116. lib/deprecated/pure/ospaths.nim
  117. lib/pure/parsejson.nim
  118. lib/pure/cstrutils.nim
  119. lib/core/macros.nim
  120. lib/pure/marshal.nim
  121. lib/core/typeinfo.nim
  122. lib/impure/re.nim
  123. lib/pure/typetraits.nim
  124. nimsuggest/sexp.nim
  125. lib/pure/concurrency/threadpool.nim
  126. lib/pure/concurrency/cpuinfo.nim
  127. lib/pure/concurrency/cpuload.nim
  128. lib/js/dom.nim
  129. lib/js/jsffi.nim
  130. lib/js/jsconsole.nim
  131. lib/js/asyncjs.nim
  132. lib/pure/os.nim
  133. lib/pure/strutils.nim
  134. lib/pure/math.nim
  135. lib/std/editdistance.nim
  136. lib/std/wordwrap.nim
  137. lib/experimental/diff.nim
  138. lib/pure/algorithm.nim
  139. lib/pure/stats.nim
  140. lib/windows/winlean.nim
  141. lib/pure/random.nim
  142. lib/pure/complex.nim
  143. lib/pure/times.nim
  144. lib/pure/osproc.nim
  145. lib/pure/pegs.nim
  146. lib/pure/dynlib.nim
  147. lib/pure/strscans.nim
  148. lib/pure/parseopt.nim
  149. lib/pure/hashes.nim
  150. lib/pure/strtabs.nim
  151. lib/pure/lexbase.nim
  152. lib/pure/parsecfg.nim
  153. lib/pure/parsexml.nim
  154. lib/pure/parsecsv.nim
  155. lib/pure/parsesql.nim
  156. lib/pure/streams.nim
  157. lib/pure/terminal.nim
  158. lib/pure/cgi.nim
  159. lib/pure/unicode.nim
  160. lib/pure/strmisc.nim
  161. lib/pure/htmlgen.nim
  162. lib/pure/parseutils.nim
  163. lib/pure/browsers.nim
  164. lib/impure/db_postgres.nim
  165. lib/impure/db_mysql.nim
  166. lib/impure/db_sqlite.nim
  167. lib/impure/db_odbc.nim
  168. lib/pure/db_common.nim
  169. lib/pure/httpclient.nim
  170. lib/pure/smtp.nim
  171. lib/pure/ropes.nim
  172. lib/pure/unidecode/unidecode.nim
  173. lib/pure/xmlparser.nim
  174. lib/pure/htmlparser.nim
  175. lib/pure/xmltree.nim
  176. lib/pure/colors.nim
  177. lib/pure/mimetypes.nim
  178. lib/pure/json.nim
  179. lib/pure/base64.nim
  180. lib/impure/nre.nim
  181. lib/impure/nre/private/util.nim
  182. lib/pure/collections/tables.nim
  183. lib/pure/collections/sets.nim
  184. lib/pure/collections/lists.nim
  185. lib/pure/collections/sharedlist.nim
  186. lib/pure/collections/sharedtables.nim
  187. lib/pure/collections/intsets.nim
  188. lib/pure/collections/deques.nim
  189. lib/pure/encodings.nim
  190. lib/pure/collections/sequtils.nim
  191. lib/pure/collections/rtarrays.nim
  192. lib/pure/cookies.nim
  193. lib/pure/memfiles.nim
  194. lib/pure/collections/critbits.nim
  195. lib/core/locks.nim
  196. lib/core/rlocks.nim
  197. lib/pure/oids.nim
  198. lib/pure/endians.nim
  199. lib/pure/uri.nim
  200. lib/pure/nimprof.nim
  201. lib/pure/unittest.nim
  202. lib/packages/docutils/highlite.nim
  203. lib/packages/docutils/rst.nim
  204. lib/packages/docutils/rstast.nim
  205. lib/packages/docutils/rstgen.nim
  206. lib/pure/logging.nim
  207. lib/pure/options.nim
  208. lib/pure/asyncdispatch.nim
  209. lib/pure/asyncnet.nim
  210. lib/pure/asyncstreams.nim
  211. lib/pure/asyncfutures.nim
  212. lib/pure/nativesockets.nim
  213. lib/pure/asynchttpserver.nim
  214. lib/pure/net.nim
  215. lib/pure/selectors.nim
  216. lib/pure/sugar.nim
  217. lib/pure/collections/chains.nim
  218. lib/pure/asyncfile.nim
  219. lib/pure/asyncftpclient.nim
  220. lib/pure/lenientops.nim
  221. lib/pure/md5.nim
  222. lib/pure/rationals.nim
  223. lib/pure/distros.nim
  224. lib/pure/oswalkdir.nim
  225. lib/pure/collections/heapqueue.nim
  226. lib/pure/fenv.nim
  227. lib/std/sha1.nim
  228. lib/std/sums.nim
  229. lib/std/varints.nim
  230. lib/std/time_t.nim
  231. lib/impure/rdstdin.nim
  232. lib/wrappers/linenoise/linenoise.nim
  233. lib/pure/strformat.nim
  234. lib/pure/segfaults.nim
  235. lib/pure/mersenne.nim
  236. lib/pure/coro.nim
  237. lib/pure/httpcore.nim
  238. lib/pure/bitops.nim
  239. lib/pure/nimtracker.nim
  240. lib/pure/punycode.nim
  241. lib/pure/volatile.nim
  242. lib/posix/posix_utils.nim
  243. """.splitWhitespace()
  244. doc0 = """
  245. lib/system/threads.nim
  246. lib/system/channels.nim
  247. """.splitWhitespace()
  248. withoutIndex = """
  249. lib/wrappers/mysql.nim
  250. lib/wrappers/iup.nim
  251. lib/wrappers/sqlite3.nim
  252. lib/wrappers/postgres.nim
  253. lib/wrappers/tinyc.nim
  254. lib/wrappers/odbcsql.nim
  255. lib/wrappers/pcre.nim
  256. lib/wrappers/openssl.nim
  257. lib/posix/posix.nim
  258. lib/posix/linux.nim
  259. lib/posix/termios.nim
  260. lib/wrappers/odbcsql.nim
  261. lib/js/jscore.nim
  262. """.splitWhitespace()
  263. proc sexec(cmds: openarray[string]) =
  264. ## Serial queue wrapper around exec.
  265. for cmd in cmds:
  266. echo(cmd)
  267. let (outp, exitCode) = osproc.execCmdEx(cmd)
  268. if exitCode != 0: quit outp
  269. proc mexec(cmds: openarray[string]) =
  270. ## Multiprocessor version of exec
  271. let r = execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd})
  272. if r != 0:
  273. echo "external program failed, retrying serial work queue for logs!"
  274. sexec(cmds)
  275. proc buildDocSamples(nimArgs, destPath: string) =
  276. ## Special case documentation sample proc.
  277. ##
  278. ## TODO: consider integrating into the existing generic documentation builders
  279. ## now that we have a single `doc` command.
  280. exec(findNim() & " doc $# -o:$# $#" %
  281. [nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"])
  282. proc buildDoc(nimArgs, destPath: string) =
  283. # call nim for the documentation:
  284. var
  285. commands = newSeq[string](rst2html.len + len(doc0) + len(doc) + withoutIndex.len)
  286. i = 0
  287. let nim = findNim()
  288. for d in items(rst2html):
  289. commands[i] = nim & " rst2html $# --git.url:$# -o:$# --index:on $#" %
  290. [nimArgs, gitUrl,
  291. destPath / changeFileExt(splitFile(d).name, "html"), d]
  292. i.inc
  293. for d in items(doc0):
  294. commands[i] = nim & " doc0 $# --git.url:$# -o:$# --index:on $#" %
  295. [nimArgs, gitUrl,
  296. destPath / changeFileExt(splitFile(d).name, "html"), d]
  297. i.inc
  298. for d in items(doc):
  299. commands[i] = nim & " doc $# --git.url:$# -o:$# --index:on $#" %
  300. [nimArgs, gitUrl,
  301. destPath / changeFileExt(splitFile(d).name, "html"), d]
  302. i.inc
  303. for d in items(withoutIndex):
  304. commands[i] = nim & " doc2 $# --git.url:$# -o:$# $#" %
  305. [nimArgs, gitUrl,
  306. destPath / changeFileExt(splitFile(d).name, "html"), d]
  307. i.inc
  308. mexec(commands)
  309. exec(nim & " buildIndex -o:$1/theindex.html $1" % [destPath])
  310. proc buildPdfDoc*(nimArgs, destPath: string) =
  311. createDir(destPath)
  312. if os.execShellCmd("pdflatex -version") != 0:
  313. echo "pdflatex not found; no PDF documentation generated"
  314. else:
  315. const pdflatexcmd = "pdflatex -interaction=nonstopmode "
  316. for d in items(pdf):
  317. exec(findNim() & " rst2tex $# $#" % [nimArgs, d])
  318. # call LaTeX twice to get cross references right:
  319. exec(pdflatexcmd & changeFileExt(d, "tex"))
  320. exec(pdflatexcmd & changeFileExt(d, "tex"))
  321. # delete all the crappy temporary files:
  322. let pdf = splitFile(d).name & ".pdf"
  323. let dest = destPath / pdf
  324. removeFile(dest)
  325. moveFile(dest=dest, source=pdf)
  326. removeFile(changeFileExt(pdf, "aux"))
  327. if existsFile(changeFileExt(pdf, "toc")):
  328. removeFile(changeFileExt(pdf, "toc"))
  329. removeFile(changeFileExt(pdf, "log"))
  330. removeFile(changeFileExt(pdf, "out"))
  331. removeFile(changeFileExt(d, "tex"))
  332. proc buildJS() =
  333. exec(findNim() & " js -d:release --out:$1 tools/nimblepkglist.nim" %
  334. [webUploadOutput / "nimblepkglist.js"])
  335. exec(findNim() & " js " & (docHackDir / "dochack.nim"))
  336. proc buildDocs*(args: string) =
  337. let
  338. a = nimArgs & " " & args
  339. docHackJs = "dochack.js"
  340. docHackJsSource = docHackDir / docHackJs
  341. docHackJsDest = docHtmlOutput / docHackJs
  342. buildJS() # This call generates docHackJsSource
  343. let docup = webUploadOutput / NimVersion
  344. createDir(docup)
  345. buildDocSamples(a, docup)
  346. buildDoc(a, docup)
  347. # 'nimArgs' instead of 'a' is correct here because we don't want
  348. # that the offline docs contain the 'gaCode'!
  349. createDir(docHtmlOutput)
  350. buildDocSamples(nimArgs, docHtmlOutput)
  351. buildDoc(nimArgs, docHtmlOutput)
  352. copyFile(docHackJsSource, docHackJsDest)
  353. copyFile(docHackJsSource, docup / docHackJs)