Skip to content

Commit 3e6723a

Browse files
authored
Made Building happen async and in multiple process (#53)
* Use startprocess and async to make building faster * write log file on error * Logged error files should be chronological. * Clean up async dispatch for building
1 parent 280a626 commit 3e6723a

File tree

3 files changed

+39
-15
lines changed

3 files changed

+39
-15
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ docs/*
22
examplebook/my*
33
nbook
44
nbook.exe
5-
x_*
5+
x_*
6+
*.log

src/nimibook/builds.nim

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,28 @@
1-
import std / [os, strutils]
1+
import std / [os, strutils, asyncdispatch, osproc, streams, sugar]
22
import nimibook / [types, commands, themes]
33
import nimib
44

5-
proc buildNim*(entry: Entry, srcDir: string, nimOptions: seq[string]): bool =
5+
proc buildNim*(entry: Entry, srcDir: string, nimOptions: seq[string]): Future[bool] {.async.} =
66
let
77
cmd = "nim"
88
args = @["r"] & nimOptions & @[srcDir / entry.path]
99
# "-d:release", "-f", "--verbosity:0", "--hints:off"
1010
debugEcho "[Executing] ", cmd, " ", args.join(" ")
11-
if execShellCmd(cmd & " " & args.join(" ")) != 0:
12-
echo "[nimibook.error] error while processing ", entry.path
13-
return false
14-
return true
11+
12+
let process = startProcess(cmd, args = args, options = {poUsePath, poStdErrToStdOut})
13+
defer: process.close()
14+
while process.running():
15+
await sleepAsync(10)
16+
17+
result = process.peekexitCode == 0
18+
if not result:
19+
# Process failed so we write a '.log'
20+
let logPath = entry.path.changeFileExt("log")
21+
discard tryRemoveFile(logPath)
22+
let fs = openFileStream(logPath, fmWrite)
23+
defer: fs.close()
24+
for line in process.lines:
25+
fs.writeLine(line)
1526

1627
proc buildMd*(entry: Entry): bool =
1728
try:
@@ -24,25 +35,36 @@ proc buildMd*(entry: Entry): bool =
2435
echo "[nimibook.error] error while processing ", entry.path
2536
return false
2637

27-
proc build*(entry: Entry, srcDir: string, nimOptions: seq[string]): bool =
38+
proc build*(entry: Entry, srcDir: string, nimOptions: seq[string]): Future[bool] {.async.} =
2839
let splitted = entry.path.splitFile()
29-
if splitted.ext == ".nim":
30-
return buildNim(entry, srcDir, nimOptions)
31-
elif splitted.ext == ".md":
40+
case splitted.ext
41+
of ".nim":
42+
return await buildNim(entry, srcDir, nimOptions)
43+
of ".md":
3244
return buildMd(entry)
3345
else:
3446
echo "[nimibook.error] invalid file extension (must be one of .nim, .md): ", splitted.ext
3547
return false
3648

3749
proc build*(book: Book, nimOptions: seq[string] = @[]) =
38-
var buildErrors: seq[string]
50+
var
51+
buildErrors: seq[string]
52+
buildFutures: seq[Future[bool]]
3953
dump book
40-
for entry in book.toc.entries:
54+
for i in 0..book.toc.entries.high:
55+
let entry = book.toc.entries[i] # use index since `items` returns `lent` in `1.7.x+`
4156
if entry.isDraft:
4257
continue
4358
echo "[nimibook] build entry: ", entry.path
44-
if not build(entry, book.srcDir, nimOptions):
45-
buildErrors.add entry.path
59+
buildFutures.add build(entry, book.srcDir, nimOptions)
60+
closureScope:
61+
let path = entry.path
62+
buildFutures[^1].addCallback do (f: Future[bool]):
63+
if not f.read():
64+
buildErrors.add path
65+
66+
discard waitFor all buildFutures
67+
4668
if len(buildErrors) > 0:
4769
echo "[nimibook.error] ", len(buildErrors), " build errors:"
4870
for err in buildErrors:

src/nimibook/commands.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import jsony
44

55
proc dump*(book: Book) =
66
var book = book
7+
discard existsOrCreateDir(book.homeDir())
78
let uri = normalizedPath(book.homeDir / "book.json")
89
echo "[nimibook] dumping ", uri
910
writeFile(uri, book.toJson)

0 commit comments

Comments
 (0)