Skip to content

Commit 9d4bd15

Browse files
committed
community build can run doc on supported tasksFix sources in doc
1 parent 6714547 commit 9d4bd15

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
@@ -123,6 +123,16 @@ final case class SbtCommunityProject(
123123

124124
object projects:
125125

126+
private def forceDoc(projects: String*) =
127+
projects.map(project =>
128+
s""";set $project/Compile/doc/sources ++= file("a.scala") +: ($project/Compile/doc/tastyFiles).value ;$project/doc"""
129+
).mkString(" ")
130+
131+
private def aggregateDoc(in: String)(projects: String*) =
132+
val tastyFiles =
133+
(in +: projects).map(p => s"($p/Compile/doc/tastyFiles).value").mkString(" ++ ")
134+
s""";set $in/Compile/doc/sources ++= file("a.scala") +: ($tastyFiles) ;$in/doc"""
135+
126136
lazy val utest = MillCommunityProject(
127137
project = "utest",
128138
baseCommand = s"utest.jvm[$compilerVersion]",
@@ -201,14 +211,14 @@ object projects:
201211
lazy val algebra = SbtCommunityProject(
202212
project = "algebra",
203213
sbtTestCommand = "coreJVM/compile",
204-
sbtDocCommand = "coreJVM/doc"
214+
sbtDocCommand = forceDoc("coreJVM")
205215
)
206216

207217
lazy val scalacheck = SbtCommunityProject(
208218
project = "scalacheck",
209219
sbtTestCommand = "jvm/test;js/test",
210220
sbtPublishCommand = "jvm/publishLocal;js/publishLocal",
211-
sbtDocCommand = "jvm/doc"
221+
sbtDocCommand = forceDoc("jvm")
212222
)
213223

214224
lazy val scalatest = SbtCommunityProject(
@@ -251,13 +261,17 @@ object projects:
251261
lazy val ScalaPB = SbtCommunityProject(
252262
project = "ScalaPB",
253263
sbtTestCommand = "dotty-community-build/compile",
254-
sbtDocCommand = "dotty-community-build/doc"
264+
// aggregateDoc("runtimeJVM")("scalapbc", "grpcRuntime", "compilerPlugin") fails with
265+
// module class ScalaPbCodeGenerator$ has non-class parent: TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),module protocbridge),ProtocCodeGenerator)
266+
// Also it seems that we do not handle correctly aggreagation projects
267+
// sbtDocCommand = "dotty-community-build/doc"
268+
sbtDocCommand = forceDoc("scalapbc", "grpcRuntime","runtimeJVM", "compilerPlugin")
255269
)
256270

257271
lazy val minitest = SbtCommunityProject(
258272
project = "minitest",
259273
sbtTestCommand = "test",
260-
sbtDocCommand = "dotty-community-build/doc",
274+
sbtDocCommand = aggregateDoc("lawsJVM")("minitestJVM"),
261275
dependencies = List(scalacheck)
262276
)
263277

@@ -280,7 +294,7 @@ object projects:
280294
lazy val shapeless = SbtCommunityProject(
281295
project = "shapeless",
282296
sbtTestCommand = "test",
283-
sbtDocCommand = "doc"
297+
sbtDocCommand = forceDoc("typeable", "deriving", "data")
284298
)
285299

286300
lazy val xmlInterpolator = SbtCommunityProject(
@@ -314,13 +328,15 @@ object projects:
314328
lazy val sconfig = SbtCommunityProject(
315329
project = "sconfig",
316330
sbtTestCommand = "sconfigJVM/test",
317-
sbtDocCommand = "sconfigJVM/doc",
331+
// sbtDocCommand = "sconfigJVM/doc", // Fails with:
332+
// Problem parsing sconfig/sharedScala3/src/main/scala/org/ekrich/config/ConfigSyntax.scala:[73..92..1340], documentation may not be generated.
333+
// 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)
318334
)
319335

320336
lazy val zio = SbtCommunityProject(
321337
project = "zio",
322338
sbtTestCommand = "testJVMDotty",
323-
// sbtDocCommand = "coreJVM/doc",
339+
// sbtDocCommand = forceDoc("coreJVM"),
324340
// Fails on tasty unpickling https://github.com/lampepfl/dotty/issues/10499
325341
)
326342

@@ -349,19 +365,33 @@ object projects:
349365
lazy val scalaParserCombinators = SbtCommunityProject(
350366
project = "scala-parser-combinators",
351367
sbtTestCommand = "parserCombinatorsJVM/test",
352-
sbtDocCommand = "parserCombinatorsJVM/doc",
368+
sbtDocCommand = forceDoc("parserCombinatorsJVM"),
353369
)
354370

355371
lazy val dottyCpsAsync = SbtCommunityProject(
356372
project = "dotty-cps-async",
357373
sbtTestCommand = "test",
358-
sbtDocCommand = "doc",
374+
// Does not compile (before reaches doc)
375+
// sbtDocCommand = "cpsJVM/doc",
359376
)
360377

361378
lazy val scalaz = SbtCommunityProject(
362379
project = "scalaz",
363380
sbtTestCommand = "rootJVM/test",
364-
sbtDocCommand = "rootJVM/doc",
381+
382+
// sbtDocCommand = forceDoc("coreJVM"), // Fails with:
383+
// [error] class scalaz.Conts cannot be unpickled because no class file was found
384+
// [error] class scalaz.ContsT cannot be unpickled because no class file was found
385+
// [error] class scalaz.IndexedCont cannot be unpickled because no class file was found
386+
387+
// aggregateDoc("rootJVM")("effectJVM", "iterateeJVM"), // Fails With
388+
// [error] Caused by: java.lang.AssertionError: assertion failed:
389+
// 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)))
390+
391+
// sbtDocCommand = forceDoc("iterateeJVM"), // Fails with
392+
// [error] class scalaz.iteratee.Iteratee cannot be unpickled because no class file was found
393+
394+
sbtDocCommand = forceDoc("effectJVM"),
365395
dependencies = List(scalacheck)
366396
)
367397

@@ -374,7 +404,8 @@ object projects:
374404
lazy val catsEffect2 = SbtCommunityProject(
375405
project = "cats-effect-2",
376406
sbtTestCommand = "test",
377-
sbtDocCommand = ";coreJVM/doc ;lawsJVM/doc",
407+
// Currently is excluded from community build
408+
// sbtDocCommand = ";coreJVM/doc ;lawsJVM/doc",
378409
forceUpgradeSbtScalajsPlugin = true
379410
)
380411

@@ -388,8 +419,8 @@ object projects:
388419
lazy val scalaParallelCollections = SbtCommunityProject(
389420
project = "scala-parallel-collections",
390421
sbtTestCommand = "test",
391-
sbtDocCommand = "doc",
392-
dependencies = List(scalacheck)
422+
sbtDocCommand = forceDoc("core"),
423+
dependencies = List(scalacheck)
393424
)
394425

395426
lazy val scalaCollectionCompat = SbtCommunityProject(

project/Build.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1578,9 +1578,12 @@ object Build {
15781578
Build.testcasesSourceRoot.in(Test),
15791579
Build.testDocumentationRoot,
15801580
),
1581+
Compile / buildInfoKeys := Seq[BuildInfoKey](version),
1582+
Compile / buildInfoPackage := "dotty.dokka",
15811583
testDocumentationRoot := (baseDirectory.value / "test-documentations").getAbsolutePath,
15821584
buildInfoPackage in Test := "dotty.dokka",
15831585
BuildInfoPlugin.buildInfoScopedSettings(Test),
1586+
BuildInfoPlugin.buildInfoScopedSettings(Compile),
15841587
BuildInfoPlugin.buildInfoDefaultSettings,
15851588
// Uncomment to debug dokka processing (require to run debug in listen mode on 5005 port)
15861589
// 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
@@ -58,8 +58,8 @@ object Scala3docArgs:
5858
def parseTastyRoots(roots: String) =
5959
roots.split(File.pathSeparatorChar).toList.map(new File(_))
6060

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

6464
if nonExisting.nonEmpty then report.warning(
6565
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(args: Scala3doc.Args) 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 = args.projectLogo.toSeq.map { path =>
2735
val fileName = Paths.get(path).getFileName()

0 commit comments

Comments
 (0)