@@ -3323,11 +3323,17 @@ object Build {
33233323 val testcasesSourceRoot = taskKey[String ](" Root directory where tests sources are generated" )
33243324 val testDocumentationRoot = taskKey[String ](" Root directory where tests documentation are stored" )
33253325 val generateSelfDocumentation = taskKey[Unit ](" Generate example documentation" )
3326- // Note: the two tasks below should be one, but a bug in Tasty prevents that
3327- val generateScalaDocumentation = inputKey[Unit ](" Generate documentation for dotty lib" )
3328- val generateStableScala3Documentation = inputKey[Unit ](" Generate documentation for stable dotty lib" )
33293326 val generateTestcasesDocumentation = taskKey[Unit ](" Generate documentation for testcases, useful for debugging tests" )
33303327
3328+ // Published on https://dotty.epfl.ch/ by nightly builds
3329+ // Contains additional internal/contributing docs
3330+ val generateScalaDocumentation = inputKey[Unit ](" Generate documentation for snapshot release" )
3331+
3332+ // Published on https://docs.scala-lang.org/api/all.html
3333+ val generateStableScala3Documentation = inputKey[Unit ](" Generate documentation for stable release" )
3334+
3335+ // Published on https://docs.scala-lang.org/scala3/reference/
3336+ // Does not produce API docs, contains additional redirects for improved stablity
33313337 val generateReferenceDocumentation = inputKey[Unit ](" Generate language reference documentation for Scala 3" )
33323338
33333339 lazy val `scaladoc-testcases` = project.in(file(" scaladoc-testcases" )).
@@ -3454,31 +3460,135 @@ object Build {
34543460 val outputDirOverride = extraArgs.headOption.fold(identity[GenerationConfig ](_))(newDir => {
34553461 config : GenerationConfig => config.add(OutputDir (newDir))
34563462 })
3457- val justAPIArg : Option [String ] = extraArgs.drop(1 ).find(_ == " --justAPI" )
3458- val justAPI = justAPIArg.fold(identity[GenerationConfig ](_))(_ => {
3459- config : GenerationConfig => config.remove[SiteRoot ]
3460- })
3461- val overrideFunc = outputDirOverride.andThen(justAPI)
3463+ val justAPI = extraArgs.contains(" --justAPI" )
3464+ def justAPIOverride (config : GenerationConfig ): GenerationConfig = {
3465+ if (! justAPI) config
3466+ else {
3467+ val siteRoot = IO .createTemporaryDirectory.getAbsolutePath()
3468+ config.add(SiteRoot (siteRoot))
3469+ }
3470+ }
3471+
3472+ // It would be the easiest to create a temp directory and apply patches there, but this task would be used frequently during development
3473+ // If we'd build using copy the emitted warnings would point developers to copies instead of original sources. Any fixes made in there would be lost.
3474+ // Instead let's apply revertable patches to the files as part snapshot doc generation process
3475+ abstract class SourcePatch (val file : File ) {
3476+ def apply (): Unit
3477+ def revert (): Unit
3478+ }
3479+ val docs = file(" docs" )
3480+ val sourcePatches = if (justAPI) Nil else Seq (
3481+ // Generate full sidebar.yml based on template and reference content
3482+ new SourcePatch (docs / " sidebar.yml" ) {
3483+ val referenceSideBarCopy = IO .temporaryDirectory / " sidebar.yml.copy"
3484+ IO .copyFile(file, referenceSideBarCopy)
3485+
3486+ override def apply (): Unit = {
3487+ val yaml = new org.yaml.snakeyaml.Yaml ()
3488+ type YamlObject = java.util.Map [String , AnyRef ]
3489+ type YamlList [T ] = java.util.List [T ]
3490+ def loadYaml (file : File ): YamlObject = {
3491+ val reader = Files .newBufferedReader(file.toPath)
3492+ try yaml.load(reader).asInstanceOf [YamlObject ]
3493+ finally reader.close()
3494+ }
3495+ // Ensure to always operate on original (Map, List) instances
3496+ val template = loadYaml(docs / " sidebar.nightly.template.yml" )
3497+ template.get(" subsection" )
3498+ .asInstanceOf [YamlList [YamlObject ]]
3499+ .stream()
3500+ .filter(_.get(" title" ) == " Reference" )
3501+ .findFirst()
3502+ .orElseThrow(() => new IllegalStateException (" Reference subsection not found in sidebar.nightly.template.yml" ))
3503+ .putAll(loadYaml(referenceSideBarCopy))
3504+
3505+ val sidebarWriter = Files .newBufferedWriter(this .file.toPath)
3506+ try yaml.dump(template, sidebarWriter)
3507+ finally sidebarWriter.close()
3508+ }
3509+ override def revert (): Unit = IO .move(referenceSideBarCopy, file)
3510+ },
3511+ // Add patch about nightly version usage
3512+ new SourcePatch (docs / " _layouts" / " static-site-main.html" ) {
3513+ lazy val originalContent = IO .read(file)
3514+
3515+ val warningMessage = """ {% if page.nightlyOf %}
3516+ | <aside class="warning">
3517+ | <div class='icon'></div>
3518+ | <div class='content'>
3519+ | This is a nightly documentation. The content of this page may not be consistent with the current stable version of language.
3520+ | Click <a href="{{ page.nightlyOf }}">here</a> to find the stable version of this page.
3521+ | </div>
3522+ | </aside>
3523+ |{% endif %}""" .stripMargin
3524+
3525+ override def apply (): Unit = {
3526+ IO .write(file,
3527+ originalContent
3528+ .replace(" {{ content }}" , s " $warningMessage {{ content }} " )
3529+ .ensuring(_.contains(warningMessage), " patch to static-site-main layout not applied!" )
3530+ )
3531+ }
3532+ override def revert (): Unit = IO .write(file, originalContent)
3533+ }
3534+ )
34623535
34633536 val config = Def .task {
3464- overrideFunc(Scala3 .value)
3537+ outputDirOverride
3538+ .andThen(justAPIOverride)
3539+ .apply(Scala3 .value)
34653540 }
34663541
34673542 val writeAdditionalFiles = Def .task {
34683543 val dest = file(config.value.get[OutputDir ].get.value)
3469- if (justAPIArg.isEmpty ) {
3544+ if (! justAPI ) {
34703545 IO .write(dest / " versions" / " latest-nightly-base" , majorVersion)
34713546 // This file is used by GitHub Pages when the page is available in a custom domain
34723547 IO .write(dest / " CNAME" , " dotty.epfl.ch" )
34733548 }
34743549 }
3550+ val applyPatches = Def .task {
3551+ streams.value.log.info(s " Generating snapshot scaladoc, would apply patches to ${sourcePatches.map(_.file)}" )
3552+ sourcePatches.foreach(_.apply())
3553+ }
3554+ val revertPatches = Def .task {
3555+ streams.value.log.info(s " Generated snapshot scaladoc, reverting changes made to ${sourcePatches.map(_.file)}" )
3556+ sourcePatches.foreach(_.revert())
3557+ }
34753558
3476- writeAdditionalFiles.dependsOn(generateDocumentation(config))
3559+ writeAdditionalFiles.dependsOn(
3560+ revertPatches.dependsOn(
3561+ generateDocumentation(config)
3562+ .dependsOn(applyPatches)
3563+ )
3564+ )
34773565 }.evaluated,
34783566
34793567 generateStableScala3Documentation := Def .inputTaskDyn {
34803568 val extraArgs = spaceDelimited(" <version>" ).parsed
3481- val config = stableScala3(extraArgs.head)
3569+ val version = baseVersion
3570+ // In the early days of scaladoc there was a practice to precompile artifacts of Scala 3 and generate docs using different version of scaladoc
3571+ // It's no longer needed after its stablisation.
3572+ // Allow to use explcit version check to detect using incorrect revision during release process
3573+ extraArgs.headOption.foreach { explicitVersion =>
3574+ assert(
3575+ explicitVersion == version,
3576+ s " Version of the build ( $version) does not match the explicit verion ( $explicitVersion) "
3577+ )
3578+ }
3579+
3580+ val docs = IO .createTemporaryDirectory
3581+ IO .copyDirectory(file(" docs" ), docs)
3582+ IO .delete(docs / " _blog" )
3583+
3584+ val config = Def .task {
3585+ Scala3 .value
3586+ .add(ProjectVersion (version))
3587+ .add(Revision (version))
3588+ .add(OutputDir (s " scaladoc/output/ ${version}" ))
3589+ .add(SiteRoot (docs.getAbsolutePath))
3590+ .remove[ApiSubdirectory ]
3591+ }
34823592 generateDocumentation(config)
34833593 }.evaluated,
34843594
@@ -3493,20 +3603,13 @@ object Build {
34933603 generateStaticAssetsTask.value
34943604
34953605 // Move all the source files to a temporary directory and apply some changes specific to the reference documentation
3496- val temp = IO .createTemporaryDirectory
3497- IO .copyDirectory(file(" docs" ), temp / " docs" )
3498- IO .delete(temp / " docs" / " _blog" )
3499-
3500- // Overwrite the main layout and the sidebar
3501- IO .copyDirectory(
3502- file(" project" ) / " resources" / " referenceReplacements" ,
3503- temp / " docs" ,
3504- overwrite = true
3505- )
3606+ val docs = IO .createTemporaryDirectory
3607+ IO .copyDirectory(file(" docs" ), docs)
3608+ IO .delete(docs / " _blog" )
35063609
35073610 // Add redirections from previously supported URLs, for some pages
35083611 for (name <- Seq (" changed-features" , " contextual" , " dropped-features" , " metaprogramming" , " other-new-features" )) {
3509- val path = temp / " docs" / " _docs" / " reference" / name / s " ${name}.md "
3612+ val path = docs / " _docs" / " reference" / name / s " ${name}.md "
35103613 val contentLines = IO .read(path).linesIterator.to[collection.mutable.ArrayBuffer ]
35113614 contentLines.insert(1 , s " redirectFrom: / ${name}.html " ) // Add redirection
35123615 val newContent = contentLines.mkString(" \n " )
@@ -3516,12 +3619,12 @@ object Build {
35163619 val languageReferenceConfig = Def .task {
35173620 Scala3 .value
35183621 .add(OutputDir (" scaladoc/output/reference" ))
3519- .add(SiteRoot (s " ${temp .getAbsolutePath} /docs " ))
3622+ .add(SiteRoot (docs .getAbsolutePath))
35203623 .add(ProjectName (" Scala 3 Reference" ))
35213624 .add(ProjectVersion (baseVersion))
35223625 .remove[VersionsDictionaryUrl ]
35233626 .add(SourceLinks (List (
3524- s " ${temp .getAbsolutePath}=github://scala/scala3/language-reference-stable "
3627+ s " ${docs.getParentFile() .getAbsolutePath}=github://scala/scala3/language-reference-stable "
35253628 )))
35263629 .withTargets(List (" ___fake___.scala" ))
35273630 }
@@ -4007,6 +4110,7 @@ object ScaladocConfigs {
40074110 .add(DocumentSyntheticTypes (true ))
40084111 // .add(SnippetCompiler(List(
40094112 // s"$dottyLibRoot/src/scala=compile",
4113+ // s"$dottyLibRoot/src/scala/quoted=compile",
40104114 // s"$dottyLibRoot/src/scala/compiletime=compile",
40114115 // s"$dottyLibRoot/src/scala/util=compile",
40124116 // s"$dottyLibRoot/src/scala/util/control=compile"
@@ -4016,33 +4120,4 @@ object ScaladocConfigs {
40164120 .withTargets((`scala-library-bootstrapped` / Compile / products).value.map(_.getAbsolutePath))
40174121 }
40184122
4019- def stableScala3 (version : String ) = Def .task {
4020- val scalaLibrarySrc = s " out/bootstrap/scala2-library-bootstrapped/scala- $version-bin-SNAPSHOT-nonbootstrapped/src_managed "
4021- val dottyLibrarySrc = " library/src"
4022- Scala3 .value
4023- .add(defaultSourceLinks(version = version))
4024- .add(ProjectVersion (version))
4025- .add(SnippetCompiler (
4026- List (
4027- s " $dottyLibrarySrc/scala/quoted=compile " ,
4028- s " $dottyLibrarySrc/scala/compiletime=compile " ,
4029- s " $dottyLibrarySrc/scala/util=compile " ,
4030- s " $dottyLibrarySrc/scala/util/control=compile "
4031- )
4032- ))
4033- .add(CommentSyntax (List (
4034- s " $dottyLibrarySrc=markdown " ,
4035- s " $scalaLibrarySrc=wiki " ,
4036- " wiki"
4037- )))
4038- .add(DocRootContent (s " $scalaLibrarySrc/rootdoc.txt " ))
4039- .withTargets(
4040- Seq (
4041- s " tmp/interfaces/target/classes " ,
4042- s " out/bootstrap/tasty-core-bootstrapped/scala- $version-bin-SNAPSHOT-nonbootstrapped/classes "
4043- )
4044- )
4045- .remove[SiteRoot ]
4046- .remove[ApiSubdirectory ]
4047- }
40484123}
0 commit comments