Skip to content

Commit 17ec1cc

Browse files
committed
community build can run doc on supported tasksFix sources in doc
1 parent d8367ea commit 17ec1cc

File tree

6 files changed

+153
-38
lines changed

6 files changed

+153
-38
lines changed
Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,91 @@
11
package dotty.communitybuild
22

3-
object Main {
3+
import java.nio.file.Paths
4+
import java.nio.file.Path
5+
import java.nio.file.Files
6+
import scala.sys.process._
7+
8+
9+
object Main:
10+
def allProjects = projects.projectMap.keys.toList.sorted
11+
12+
private def generateDocs(project: CommunityProject): Seq[Path] =
13+
val name = project.project
14+
try
15+
project.doc()
16+
val pathsOut = s"find community-projects/$name/ -name 'scala3doc.version'".!!
17+
pathsOut.linesIterator.map(Paths.get(_).getParent).toList
18+
catch
19+
case e: Exception =>
20+
e.printStackTrace()
21+
Nil
22+
423
/** Allows running various commands on community build projects. */
524
def main(args: Array[String]): Unit =
6-
if args.length != 2 then
7-
println("USAGE: <COMMAND> <PROJECT NAME>")
8-
println("COMMAND is one of: publish doc")
9-
println("Available projects are:")
10-
projects.projectMap.keys.foreach { k =>
11-
println(s"\t$k")
12-
}
13-
sys.exit(0)
14-
15-
val Array(cmd, proj) = args
16-
cmd match {
17-
case "doc" => projects(proj).doc()
18-
case "publish" => projects(proj).publish()
19-
}
20-
}
25+
args.toList match
26+
case "publish" :: name :: Nil =>
27+
case "doc" :: "all" :: destStr :: Nil =>
28+
val dest = Paths.get(destStr)
29+
s"rm -rf $destStr".!
30+
Files.createDirectory(dest)
31+
val (toRun, ignored) =
32+
allProjects.map(projects.projectMap).partition(_.docCommand != null)
33+
34+
val paths = toRun.map { project =>
35+
val name = project.project
36+
val projectDest = dest.resolve(name)
37+
val projectRoot = Paths.get(s"community-projects/$name")
38+
println(s"generating docs for $name into $projectDest")
39+
val generatedDocs = generateDocs(project)
40+
if !Files.exists(projectDest) && generatedDocs.nonEmpty then
41+
Files.createDirectory(projectDest)
42+
43+
val docsFiles = generatedDocs.map { docsPath =>
44+
val destFileName =
45+
docsPath.subpath(2, docsPath.getNameCount).toString.replace('/', '_')
46+
47+
s"cp -r $docsPath $projectDest/$destFileName".!
48+
destFileName
49+
}
50+
name -> docsFiles
51+
}
52+
53+
val (failed, withDocs) = paths.partition{ case (_, paths) => paths.isEmpty }
54+
55+
val indexFile = withDocs.map { case (name, paths) =>
56+
paths.map(p => s"""<a href="$name/$p">$p</a></br>\n""")
57+
.mkString(s"<h1>$name</h1>","\n", "\n")
58+
}.mkString("<html><body>\n", "\n", "\n</html></body>")
59+
60+
Files.write(dest.resolve("index.html"), indexFile.getBytes)
61+
62+
if ignored.nonEmpty then println(s"Ignored project without doc command: $ignored")
63+
64+
if failed.nonEmpty then
65+
println(s"Documentation not found for ${failed.map(_._1).mkString(", ")}")
66+
sys.exit(1)
67+
68+
case "doc" :: names if names.nonEmpty =>
69+
val missing = names.filterNot(projects.projectMap.contains)
70+
if missing.nonEmpty then
71+
println(s"Missing projects: ${missing.mkString(", ")}. All projects: ${allProjects.mkString(", ")}")
72+
sys.exit(0)
73+
74+
val failed = names.filter{ p =>
75+
val docsRoots = generateDocs(projects.projectMap(p))
76+
if docsRoots.nonEmpty then println(s"Docs for $p generated in $docsRoots")
77+
docsRoots.isEmpty
78+
}
79+
if failed.nonEmpty then
80+
println(s"Documentation not found for ${failed.mkString(", ")}")
81+
sys.exit(0)
82+
83+
case args =>
84+
println("USAGE: <COMMAND> <PROJECT NAME>")
85+
println("COMMAND is one of: publish doc")
86+
println("Available projects are:")
87+
allProjects.foreach { k =>
88+
println(s"\t$k")
89+
}
90+
sys.exit(0)
91+

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ final case class SbtCommunityProject(
141141

142142
object projects:
143143

144+
private def forceDoc(projects: String*) =
145+
projects.map(project =>
146+
s""";set $project/Compile/doc/sources ++= file("a.scala") +: ($project/Compile/doc/tastyFiles).value ;$project/doc"""
147+
).mkString(" ")
148+
149+
private def aggregateDoc(in: String)(projects: String*) =
150+
val tastyFiles =
151+
(in +: projects).map(p => s"($p/Compile/doc/tastyFiles).value").mkString(" ++ ")
152+
s""";set $in/Compile/doc/sources ++= file("a.scala") +: ($tastyFiles) ;$in/doc"""
153+
144154
lazy val utest = MillCommunityProject(
145155
project = "utest",
146156
baseCommand = s"utest.jvm[$compilerVersion]",
@@ -219,14 +229,14 @@ object projects:
219229
lazy val algebra = SbtCommunityProject(
220230
project = "algebra",
221231
sbtTestCommand = "coreJVM/compile",
222-
sbtDocCommand = "coreJVM/doc"
232+
sbtDocCommand = forceDoc("coreJVM")
223233
)
224234

225235
lazy val scalacheck = SbtCommunityProject(
226236
project = "scalacheck",
227237
sbtTestCommand = "jvm/test;js/test",
228238
sbtPublishCommand = "jvm/publishLocal;js/publishLocal",
229-
sbtDocCommand = "jvm/doc"
239+
sbtDocCommand = forceDoc("jvm")
230240
)
231241

232242
lazy val scalatest = SbtCommunityProject(
@@ -269,13 +279,17 @@ object projects:
269279
lazy val ScalaPB = SbtCommunityProject(
270280
project = "ScalaPB",
271281
sbtTestCommand = "dotty-community-build/compile",
272-
sbtDocCommand = "dotty-community-build/doc"
282+
// aggregateDoc("runtimeJVM")("scalapbc", "grpcRuntime", "compilerPlugin") fails with
283+
// module class ScalaPbCodeGenerator$ has non-class parent: TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module protocbridge),ProtocCodeGenerator)
284+
// Also it seems that we do not handle correctly aggreagation projects
285+
// sbtDocCommand = "dotty-community-build/doc"
286+
sbtDocCommand = forceDoc("scalapbc", "grpcRuntime","runtimeJVM", "compilerPlugin")
273287
)
274288

275289
lazy val minitest = SbtCommunityProject(
276290
project = "minitest",
277291
sbtTestCommand = "test",
278-
sbtDocCommand = "dotty-community-build/doc",
292+
sbtDocCommand = aggregateDoc("lawsJVM")("minitestJVM"),
279293
dependencies = List(scalacheck)
280294
)
281295

@@ -298,7 +312,7 @@ object projects:
298312
lazy val shapeless = SbtCommunityProject(
299313
project = "shapeless",
300314
sbtTestCommand = "test",
301-
sbtDocCommand = "doc"
315+
sbtDocCommand = forceDoc("typeable", "deriving", "data")
302316
)
303317

304318
lazy val xmlInterpolator = SbtCommunityProject(
@@ -332,13 +346,15 @@ object projects:
332346
lazy val sconfig = SbtCommunityProject(
333347
project = "sconfig",
334348
sbtTestCommand = "sconfigJVM/test",
335-
sbtDocCommand = "sconfigJVM/doc",
349+
// sbtDocCommand = "sconfigJVM/doc", // Fails with:
350+
// Problem parsing sconfig/sharedScala3/src/main/scala/org/ekrich/config/ConfigSyntax.scala:[73..92..1340], documentation may not be generated.
351+
// scala.MatchError: ValDef(JSON,TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class ekrich)),module config),class ConfigSyntax)],Apply(Ident($new),List(Literal(Constant(0)), Literal(Constant(JSON))))) (of class dotty.tools.dotc.ast.Trees$ValDef)
336352
)
337353

338354
lazy val zio = SbtCommunityProject(
339355
project = "zio",
340356
sbtTestCommand = "testJVMDotty",
341-
// sbtDocCommand = "coreJVM/doc",
357+
// sbtDocCommand = forceDoc("coreJVM"),
342358
// Fails on tasty unpickling https://github.com/lampepfl/dotty/issues/10499
343359
)
344360

@@ -368,19 +384,33 @@ object projects:
368384
lazy val scalaParserCombinators = SbtCommunityProject(
369385
project = "scala-parser-combinators",
370386
sbtTestCommand = "parserCombinatorsJVM/test",
371-
sbtDocCommand = "parserCombinatorsJVM/doc",
387+
sbtDocCommand = forceDoc("parserCombinatorsJVM"),
372388
)
373389

374390
lazy val dottyCpsAsync = SbtCommunityProject(
375391
project = "dotty-cps-async",
376392
sbtTestCommand = "test",
377-
sbtDocCommand = "doc",
393+
// Does not compile (before reaches doc)
394+
// sbtDocCommand = "cpsJVM/doc",
378395
)
379396

380397
lazy val scalaz = SbtCommunityProject(
381398
project = "scalaz",
382399
sbtTestCommand = "rootJVM/test",
383-
sbtDocCommand = "rootJVM/doc",
400+
401+
// sbtDocCommand = forceDoc("coreJVM"), // Fails with:
402+
// [error] class scalaz.Conts cannot be unpickled because no class file was found
403+
// [error] class scalaz.ContsT cannot be unpickled because no class file was found
404+
// [error] class scalaz.IndexedCont cannot be unpickled because no class file was found
405+
406+
// aggregateDoc("rootJVM")("effectJVM", "iterateeJVM"), // Fails With
407+
// [error] Caused by: java.lang.AssertionError: assertion failed:
408+
// trait MonadIO has non-class parent: AppliedType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module scalaz),Monad),List(TypeRef(ThisType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class scalaz)),module effect),trait MonadIO)),type F)))
409+
410+
// sbtDocCommand = forceDoc("iterateeJVM"), // Fails with
411+
// [error] class scalaz.iteratee.Iteratee cannot be unpickled because no class file was found
412+
413+
sbtDocCommand = forceDoc("effectJVM"),
384414
dependencies = List(scalacheck)
385415
)
386416

@@ -393,7 +423,8 @@ object projects:
393423
lazy val catsEffect2 = SbtCommunityProject(
394424
project = "cats-effect-2",
395425
sbtTestCommand = "test",
396-
sbtDocCommand = ";coreJVM/doc ;lawsJVM/doc",
426+
// Currently is excluded from community build
427+
// sbtDocCommand = ";coreJVM/doc ;lawsJVM/doc",
397428
)
398429

399430
lazy val catsEffect3 = SbtCommunityProject(
@@ -406,8 +437,8 @@ object projects:
406437
lazy val scalaParallelCollections = SbtCommunityProject(
407438
project = "scala-parallel-collections",
408439
sbtTestCommand = "test",
409-
sbtDocCommand = "doc",
410-
dependencies = List(scalacheck)
440+
sbtDocCommand = forceDoc("core"),
441+
dependencies = List(scalacheck)
411442
)
412443

413444
lazy val scalaCollectionCompat = SbtCommunityProject(

project/Build.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,9 +1576,12 @@ object Build {
15761576
Build.testcasesSourceRoot.in(Test),
15771577
Build.testDocumentationRoot,
15781578
),
1579+
Compile / buildInfoKeys := Seq[BuildInfoKey](version),
1580+
Compile / buildInfoPackage := "dotty.dokka",
15791581
testDocumentationRoot := (baseDirectory.value / "test-documentations").getAbsolutePath,
15801582
buildInfoPackage in Test := "dotty.dokka",
15811583
BuildInfoPlugin.buildInfoScopedSettings(Test),
1584+
BuildInfoPlugin.buildInfoScopedSettings(Compile),
15821585
BuildInfoPlugin.buildInfoDefaultSettings,
15831586
// Uncomment to debug dokka processing (require to run debug in listen mode on 5005 port)
15841587
// javaOptions.in(run) += "-agentlib:jdwp=transport=dt_socket,server=n,address=localhost:5005,suspend=y"

sbt-dotty/src/dotty/tools/sbtplugin/DottyPlugin.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,12 @@ object DottyPlugin extends AutoPlugin {
434434
private val docSettings = inTask(doc)(Seq(
435435
tastyFiles := {
436436
val _ = compile.value // Ensure that everything is compiled, so TASTy is available.
437-
(classDirectory.value ** "*.tasty").get.map(_.getAbsoluteFile)
437+
// sbt is too smart and do not start doc task if there are no *.scala files defined
438+
file("___fake___.scala") +:
439+
(classDirectory.value ** "*.tasty").get.map(_.getAbsoluteFile)
438440
},
439441
sources := Def.taskDyn[Seq[File]] {
440-
if (isDotty.value) Def.task { tastyFiles.value }
442+
if (isDotty.value && useScala3doc.value) Def.task { tastyFiles.value }
441443
else Def.task { sources.value }
442444
}.value,
443445
scalacOptions ++= {

scala3doc/src/dotty/dokka/Scala3docArgs.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ object Scala3docArgs:
6969
def parseTastyRoots(roots: String) =
7070
roots.split(File.pathSeparatorChar).toList.map(new File(_))
7171

72-
val (existing, nonExisting) =
73-
summary.arguments.map(File(_)).partition(_.exists)
72+
val inFiles = summary.arguments.map(File(_)).filter(_.getName != "___fake___.scala")
73+
val (existing, nonExisting) = inFiles.partition(_.exists)
7474

7575
if nonExisting.nonEmpty then report.warning(
7676
s"Scala3doc will ignore following nonexisiten paths: ${nonExisting.mkString(", ")}"

scala3doc/src/dotty/dokka/preprocessors/ScalaResourceInstaller.scala

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,24 @@ class ScalaResourceInstaller(using ctx: DocContext) extends PageTransformer:
1212
new RendererSpecificResourcePage(resourceName, java.util.ArrayList(), RenderingStrategy$Copy(s"/dotty_res/$resourceName"))
1313

1414
override def invoke(input: RootPageNode): RootPageNode =
15-
val defaultResources = input.getChildren.asScala ++ Seq("fonts", "images", "styles", "scripts", "hljs", "favicon.ico").map(dottyRes)
16-
val newResources = projectLogo ++ defaultResources ++ Seq(dynamicJsData)
15+
val dirs = Seq("fonts", "images", "styles", "scripts", "hljs", "favicon.ico")
16+
val defaultResources = input.getChildren.asScala ++ dirs.map(dottyRes)
17+
val newResources =
18+
projectLogo ++ defaultResources ++ Seq(dynamicJsData, scala3docVersionFile)
1719
input.modified(input.getName, newResources.asJava)
1820

21+
private def textFile(path: String, content: String) =
22+
val strategy = RenderingStrategy$Write(content)
23+
new RendererSpecificResourcePage(path, java.util.ArrayList(), strategy)
24+
1925
private def dynamicJsData =
20-
// If data at any point will become more complex we should use a proper
21-
val data: Map[String, Map[String, String]] = Map("filterDefaults" -> FilterAttributes.defaultValues)
26+
// If data at any point will become more complex we should use a proper mapping
27+
val data: Map[String, Map[String, String]] =
28+
Map("filterDefaults" -> FilterAttributes.defaultValues)
2229
val str = new ObjectMapper().writeValueAsString(data.transform((_, v) => v.asJava).asJava)
30+
textFile("scripts/data.js", s"var scala3DocData = $str")
2331

24-
new RendererSpecificResourcePage("scripts/data.js", java.util.ArrayList(), RenderingStrategy$Write(s"var scala3DocData = $str"))
32+
private def scala3docVersionFile = textFile("scala3doc.version", BuildInfo.version)
2533

2634
private def projectLogo = ctx.args.projectLogo.toSeq.map { path =>
2735
val fileName = Paths.get(path).getFileName()

0 commit comments

Comments
 (0)