-
Notifications
You must be signed in to change notification settings - Fork 119
Expand file tree
/
Copy pathlakefile.lean
More file actions
397 lines (326 loc) · 12.1 KB
/
Copy pathlakefile.lean
File metadata and controls
397 lines (326 loc) · 12.1 KB
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
import Lake
open Lake DSL
require subverso from git "https://github.com/leanprover/subverso"@"main"
require MD4Lean from git "https://github.com/acmepjz/md4lean"@"main"
require plausible from git "https://github.com/leanprover-community/plausible"@"main"
require illuminate from git "https://github.com/leanprover/illuminate"@"main"
package verso where
precompileModules := false -- temporarily disabled to work around an issue with nightly-2025-03-30
leanOptions := #[⟨`experimental.module, true⟩]
@[default_target]
lean_lib VersoUtil where
srcDir := "src/verso-util"
roots := #[`VersoUtil]
input_dir staticWeb where
text := true
path := "static-web"
input_dir vendorJs where
path := "vendored-js"
@[default_target]
lean_lib Verso where
srcDir := "src/verso"
roots := #[`Verso]
needs := #[staticWeb, vendorJs]
@[default_target]
lean_lib MultiVerso where
srcDir := "src/multi-verso"
roots := #[`MultiVerso]
@[default_target]
lean_lib VersoSearch where
srcDir := "src/verso-search"
-- Rebuild search when JS on disk changes
needs := #[staticWeb]
@[default_target]
lean_lib VersoBlog where
srcDir := "src/verso-blog"
roots := #[`VersoBlog]
@[default_target]
lean_lib VersoManual where
srcDir := "src/verso-manual"
roots := #[`VersoManual]
needs := #[staticWeb]
@[default_target]
lean_lib VersoIlluminate where
srcDir := "src/verso-illuminate"
roots := #[`VersoIlluminate]
input_file tutorialDefaultCss where
text := true
path := "src/verso-tutorial/default.css"
@[default_target]
lean_lib VersoTutorial where
srcDir := "src/verso-tutorial"
roots := #[`VersoTutorial]
needs := #[tutorialDefaultCss]
input_file ghSetupLiteratePages where
text := true
path := "gh-setup/verso-literate-pages.yml"
@[default_target]
lean_exe «verso» where
root := `VersoMain
srcDir := "src/cli"
needs := #[ghSetupLiteratePages]
supportInterpreter := true
@[default_target]
lean_lib VersoServe where
roots := #[`VersoServe]
srcDir := "src/verso-serve"
@[default_target]
lean_exe «verso-serve» where
root := `VersoServeMain
srcDir := "src/verso-serve"
@[default_target]
lean_lib VersoLiterate where
roots := #[`VersoLiterate]
srcDir := "src/verso-literate"
@[default_target]
lean_exe «verso-literate» where
root := `VersoLiterateMain
srcDir := "src/verso-literate"
supportInterpreter := true
@[default_target]
lean_lib VersoLiterateCode where
srcDir := "src/verso-literate-code"
roots := #[`VersoLiterateCode]
input_file «verso-html-css» where
text := true
path := "src/verso-html/code.css"
@[default_target]
lean_exe «verso-html» where
root := `VersoHtmlMain
srcDir := "src/verso-html"
needs := #[«verso-html-css»]
supportInterpreter := true
input_file «verso-literate-html-css» where
text := true
path := "src/verso-literate-html/literate.css"
input_dir literateStaticWeb where
text := true
path := "static-web/literate"
@[default_target]
lean_exe «verso-literate-html» where
root := `LiterateHtmlMain
srcDir := "src/verso-literate-html"
needs := #[«verso-literate-html-css», literateStaticWeb]
supportInterpreter := true
@[default_target]
lean_exe «verso-literate-plan» where
root := `LiteratePlanMain
srcDir := "src/verso-literate-plan"
supportInterpreter := true
@[default_target]
lean_lib Tests where
srcDir := "src/tests"
@[test_driver]
lean_exe «verso-tests» where
root := `TestMain
srcDir := "src/tests"
supportInterpreter := true
-- The release notes compute the version under development from this file while they elaborate,
-- so its contents are an input to the library.
input_file leanToolchain where
text := true
path := "lean-toolchain"
lean_lib UsersGuide where
srcDir := "doc"
leanOptions := #[⟨`weak.linter.verso.manual.headerTags, true⟩]
needs := #[leanToolchain]
@[default_target]
lean_exe usersguide where
root := `UsersGuideMain
supportInterpreter := true
-- A demo site that shows how to generate websites with Verso
lean_lib DemoSite where
srcDir := "test-projects/website"
roots := #[`DemoSite]
@[default_target]
lean_exe demosite where
srcDir := "test-projects/website"
root := `DemoSiteMain
supportInterpreter := true
-- An example of a textbook project built in Verso
lean_lib DemoTextbook where
srcDir := "test-projects/textbook"
roots := #[`DemoTextbook]
@[default_target]
lean_exe demotextbook where
srcDir := "test-projects/textbook"
root := `DemoTextbookMain
supportInterpreter := true
-- An example of a package documentation project built in Verso
lean_lib PackageManual where
srcDir := "test-projects/package-manual"
roots := #[`PackageManual]
@[default_target]
lean_exe packagedocs where
srcDir := "test-projects/package-manual"
root := `PackageManualMain
supportInterpreter := true
-- An example of a minimal nontrivial custom genre
@[default_target]
lean_lib SimplePage where
srcDir := "test-projects/custom-genre"
roots := #[`SimplePage]
@[default_target]
lean_exe simplepage where
srcDir := "test-projects/custom-genre"
root := `SimplePageMain
supportInterpreter := true
@[default_target]
lean_lib TutorialExample where
srcDir := "test-projects/tutorial-test"
@[default_target]
lean_exe «tutorial-example» where
srcDir := "test-projects/tutorial-test"
root := `TutorialExampleMain
supportInterpreter := true
private def leanOptionArgs (m : Module) : Array String := Id.run do
let opts := Module.leanOptions m
let vals := Lean.LeanOptions.values opts
let mut args : Array String := #[]
for (name, val) in vals.toList do
let valStr :=
match val with
| .ofString s => s
| .ofBool b => toString b
| .ofNat n => toString n
args := args.push s!"-D{name}={valStr}"
return args
module_facet literate mod : System.FilePath := do
let ws ← getWorkspace
let exeJob ← «verso-literate».fetch
let modJob ← mod.olean.fetch
let buildDir := ws.root.buildDir
let litFile := mod.filePath (buildDir / "literate") "json"
let optArgs := leanOptionArgs mod
exeJob.bindM fun exeFile =>
modJob.mapM fun _oleanPath => do
addLeanTrace
addTrace (← computeTrace exeFile)
addPureTrace (toString optArgs) "leanOptions"
buildFileUnlessUpToDate' (text := true) litFile <|
proc {
cmd := exeFile.toString
args := #[mod.name.toString, litFile.toString] ++ optArgs
env := ← getAugmentedEnv
}
pure litFile
library_facet literate lib : Array System.FilePath := do
let mods ← (← lib.modules.fetch).await
let lits ← mods.mapM fun x =>
x.facet `literate |>.fetch
pure <| Job.collectArray lits
package_facet literate pkg : Array System.FilePath := do
let libs := Job.collectArray (← pkg.leanLibs.mapM (·.facet `literate |>.fetch))
let exes := Job.collectArray (← pkg.leanExes.mapM (·.toLeanLib.facet `literate |>.fetch))
return libs.zipWith (·.flatten ++ ·.flatten) exes
section
variable [Monad m]
variable [MonadWorkspace m] [MonadLog m]
variable [MonadLiftT BaseIO m] [MonadLiftT IO m]
def checkDeployActions (pkg : Package) : m Unit := do
let ws ← getWorkspace
-- This is the build directory of the current root package (that is, the one t
let buildDir := pkg.buildDir
-- Check GitHub Pages workflow staleness
let workflowFile : System.FilePath :=
pkg.dir / ".github" / "workflows" / "verso-literate-pages.yml"
let sentinelFile : System.FilePath := buildDir / ".literate-pages-prompted"
let normalizeNl := fun (s : String) =>
"\n".intercalate (s.splitOn "\n" |>.map fun (l : String) => l.trimAsciiEnd.copy)
let some versoPkg ← pure (ws.findPackageByName? `verso)
| Lake.logError "Verso was not found in the workspace"; return
let ghPagesSetupFile : System.FilePath :=
versoPkg.dir / "gh-setup" / "verso-literate-pages.yml"
let ghPagesSetupContent ← IO.FS.readFile ghPagesSetupFile
-- If the user already has the workflow file that we are producing, check for
-- stale content
if ← workflowFile.pathExists then
let existingContent ← IO.FS.readFile workflowFile
unless normalizeNl existingContent == normalizeNl ghPagesSetupContent do
Lake.logWarning <|
s!"{workflowFile} is outdated. Run `lake exe verso setup-literate` to update it."
return
-- If the workflow file doesn't exist, then check whether we've already told the user how to set
-- it up. If not, tell them.
unless ← sentinelFile.pathExists do
Lake.logInfo "Run `lake exe verso setup-literate` to set up GitHub Pages deployment."
IO.FS.writeFile sentinelFile ""
end
package_facet literateHtml pkg : System.FilePath := do
let buildDir := pkg.buildDir
let htmlDir := buildDir / "literate-html"
let planFile := buildDir / "literate-plan"
let moduleListFile := buildDir / "literate-modules"
let moduleMapFile := buildDir / "literate-module-map"
let tomlFile := pkg.dir / "literate.toml"
-- Step 1: Collect all modules from libraries and executables
let allModules ← pkg.leanLibs.foldlM (init := #[]) fun acc lib => do
let mods ← (← lib.modules.fetch).await
return acc ++ mods.map fun m => (lib.name, m, lib.srcDir)
let allModules ← pkg.leanExes.foldlM (init := allModules) fun acc exe => do
let lib := exe.toLeanLib
let mods ← (← lib.modules.fetch).await
return acc ++ mods.map fun m => (lib.name, m, lib.srcDir)
let moduleListContent :=
"\n".intercalate (allModules.map fun (libName, mod, _) => s!"{libName}\t{mod.name}").toList ++ "\n"
let planExeJob ← «verso-literate-plan».fetch
let htmlExeJob ← «verso-literate-html».fetch
planExeJob.bindM fun planExeFile => do
if ← tomlFile.pathExists then
addTrace (← computeTrace tomlFile)
else
addPureTrace "No literate TOML config file"
addPureTrace moduleListContent
buildFileUnlessUpToDate' moduleListFile do
IO.FS.createDirAll buildDir
IO.FS.writeFile moduleListFile moduleListContent
-- Re-add TOML trace (buildFileUnlessUpToDate' resets trace to output file hash)
if ← tomlFile.pathExists then
addTrace (← computeTrace tomlFile)
addPureTrace moduleListContent
buildFileUnlessUpToDate' planFile do
let planArgs := #[moduleListFile.toString, planFile.toString] ++
(if ← tomlFile.pathExists then #[tomlFile.toString] else #[])
proc {
cmd := planExeFile.toString
args := planArgs
env := ← getAugmentedEnv
}
-- Step 2: Read plan, fetch literate JSON for planned modules only
let planContents ← IO.FS.readFile planFile
let plannedNames := planContents.splitOn "\n"
|>.filter (!·.isEmpty)
|>.map String.toName
let litJobs ← plannedNames.filterMapM fun name => do
match allModules.find? fun (_, mod, _) => mod.name == name with
| some (_, mod, srcDir) =>
let job ← mod.facet `literate |>.fetch
pure (some (name, job, srcDir))
| none => pure none
(Job.collectArray (litJobs.map (·.2.1) |>.toArray)).bindM fun litFiles => do
-- Build module→JSON mapping (litFiles[i] corresponds to litJobs[i])
let mappingContent := "\n".intercalate
(litJobs.zip litFiles.toList |>.map fun ((name, _, srcDir), jsonPath) =>
s!"{name}\t{jsonPath}\t{srcDir}") ++ "\n"
addPureTrace mappingContent
buildFileUnlessUpToDate' (text := true) moduleMapFile do
IO.FS.writeFile moduleMapFile mappingContent
-- Step 3: Run HTML generator with module map
htmlExeJob.mapM fun htmlExeFile => do
-- Re-add traces that were reset by buildFileUnlessUpToDate'
for jsonPath in litFiles do
addTrace (← computeTrace jsonPath)
if ← tomlFile.pathExists then
addTrace (← computeTrace tomlFile)
buildUnlessUpToDate htmlDir (← getTrace) (htmlDir.addExtension "trace") do
IO.FS.createDirAll htmlDir
let mut htmlArgs := #[htmlDir.toString, moduleMapFile.toString]
if ← tomlFile.pathExists then
htmlArgs := htmlArgs.push tomlFile.toString
proc {
cmd := htmlExeFile.toString
args := htmlArgs
env := ← getAugmentedEnv
}
checkDeployActions pkg
pure htmlDir