-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathmake.jl
139 lines (116 loc) · 3.78 KB
/
make.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
using Markdown, PlotlyBase, PlotlyJS, YAML
# also load packages used in examples to avoid world collision issues when
# evaluating code
using Dates, LaTeXStrings, CSV, JSON, DataFrames, Distributions, HTTP, ImageFiltering, Colors, MLJ
import VegaDatasets
_transform(::Module, x) = x
function _transform(mm::Module, x::Markdown.Code)
if x.language == "julia"
code = "begin $(x.code) end"
expr = Meta.parse(code)
try
return [x, Core.eval(mm, macroexpand(Main, expr))]
catch err
error("Could not run code block: $(x.code)\n\n\nError was:\n\n\n$(err)\n")
end
end
return x
end
Markdown.html(io::IO, p::PlotlyJS.SyncPlot) = Markdown.html(io, p.plot)
function Markdown.html(io::IO, p::PlotlyBase.Plot)
return show(
io,
MIME"text/html"(),
p,
full_html=false,
include_plotlyjs="require-loaded",
include_mathjax=missing
)
end
struct DocPage
fn::String
frontmatter::Dict
html_content::String
end
function prep_file(fn::String)
content = String(open(read, joinpath("julia", fn)))
# strip out metadata
meta_block = match(r"^---\n(.+)\n---\n"sm, content)
if isnothing(meta_block)
error("Could not parse yaml frontmatter. Make sure it is separated by ---")
end
frontmatter = YAML.load(meta_block[1])
# parse markdown
md_content = content[length(meta_block.match) + 1:end]
parsed = Markdown.parse(md_content)
# make module to isolate execution environments for each file
mod = eval(:(module $(gensym()) end))
# _transform parsed markdown. Keep everything same, except eval code
transformed = _transform.(Ref(mod), parsed.content)
# convert all to html
htmls = Markdown.html.(transformed)
# join as string
html_content = join(htmls, "\n")
return DocPage(fn, frontmatter, html_content)
end
function output_path(x::DocPage)
base_name = rsplit(x.fn, ".", limit=2)[1]
joinpath("build", "html", string("2021-08-17-", base_name, ".html"))
end
# writing output
function write_yaml_header(io::IO, x::DocPage)
fm = x.frontmatter
if haskey(fm, "jupyter") && haskey(fm["jupyter"], "plotly")
println(io, "---")
YAML.write(io, fm["jupyter"]["plotly"])
println(io, "---")
end
end
write_html_content(io::IO, x::DocPage) = println(io, x.html_content)
function write_output(x::DocPage)
output_fn = output_path(x)
# ensure path exists
mkpath(dirname(output_fn))
# write the document
open(output_fn, "w") do f
write_yaml_header(f, x)
println(f, "\n\n{% raw %}")
println(f, "<div class=\"rendered rendered_html\">")
write_html_content(f, x)
println(f, "</div>")
println(f, "\n\n{% endraw %}")
end
@info "Wrote to $(output_fn)"
end
function process_file(fn::String, exit_on_fail::Bool=false)
bn = basename(fn)
file_root = rsplit(bn, ".", limit=2)[1]
fail_path = joinpath("build", "failures", file_root)
rm(fail_path, force=true)
try
@info "processing file $fn on thread $(Base.Threads.threadid())"
content = prep_file(bn)
write_output(content)
catch err
open(fail_path, "w") do f
println(f, err)
for (exc, bt) in Base.catch_stack()
println(f, "\n\n")
showerror(f, exc, bt)
println(f, "\n\n")
end
end
@warn "failed when running $fn\nError is:\n$err"
if exit_on_fail
exit(1)
end
end
end
function main(exit_on_fail::Bool=true)
mkpath(joinpath("build", "html"))
mkpath(joinpath("build", "failures"))
files = filter(endswith(".md"), readdir("julia"))
Base.Threads.@threads for file in files
process_file(file, exit_on_fail)
end
end