@@ -3396,11 +3396,17 @@ object Build {
33963396 val testcasesSourceRoot = taskKey[String ](" Root directory where tests sources are generated" )
33973397 val testDocumentationRoot = taskKey[String ](" Root directory where tests documentation are stored" )
33983398 val generateSelfDocumentation = taskKey[Unit ](" Generate example documentation" )
3399- // Note: the two tasks below should be one, but a bug in Tasty prevents that
3400- val generateScalaDocumentation = inputKey[Unit ](" Generate documentation for dotty lib" )
3401- val generateStableScala3Documentation = inputKey[Unit ](" Generate documentation for stable dotty lib" )
34023399 val generateTestcasesDocumentation = taskKey[Unit ](" Generate documentation for testcases, useful for debugging tests" )
34033400
3401+ // Published on https://dotty.epfl.ch/ by nightly builds
3402+ // Contains additional internal/contributing docs
3403+ val generateScalaDocumentation = inputKey[Unit ](" Generate documentation for snapshot release" )
3404+
3405+ // Published on https://docs.scala-lang.org/api/all.html
3406+ val generateStableScala3Documentation = inputKey[Unit ](" Generate documentation for stable release" )
3407+
3408+ // Published on https://docs.scala-lang.org/scala3/reference/
3409+ // Does not produce API docs, contains additional redirects for improved stablity
34043410 val generateReferenceDocumentation = inputKey[Unit ](" Generate language reference documentation for Scala 3" )
34053411
34063412 lazy val `scaladoc-testcases` = project.in(file(" scaladoc-testcases" )).
@@ -3527,31 +3533,135 @@ object Build {
35273533 val outputDirOverride = extraArgs.headOption.fold(identity[GenerationConfig ](_))(newDir => {
35283534 config : GenerationConfig => config.add(OutputDir (newDir))
35293535 })
3530- val justAPIArg : Option [String ] = extraArgs.drop(1 ).find(_ == " --justAPI" )
3531- val justAPI = justAPIArg.fold(identity[GenerationConfig ](_))(_ => {
3532- config : GenerationConfig => config.remove[SiteRoot ]
3533- })
3534- val overrideFunc = outputDirOverride.andThen(justAPI)
3536+ val justAPI = extraArgs.contains(" --justAPI" )
3537+ def justAPIOverride (config : GenerationConfig ): GenerationConfig = {
3538+ if (! justAPI) config
3539+ else {
3540+ val siteRoot = IO .createTemporaryDirectory.getAbsolutePath()
3541+ config.add(SiteRoot (siteRoot))
3542+ }
3543+ }
3544+
3545+ // It would be the easiest to create a temp directory and apply patches there, but this task would be used frequently during development
3546+ // 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.
3547+ // Instead let's apply revertable patches to the files as part snapshot doc generation process
3548+ abstract class SourcePatch (val file : File ) {
3549+ def apply (): Unit
3550+ def revert (): Unit
3551+ }
3552+ val docs = file(" docs" )
3553+ val sourcePatches = if (justAPI) Nil else Seq (
3554+ // Generate full sidebar.yml based on template and reference content
3555+ new SourcePatch (docs / " sidebar.yml" ) {
3556+ val referenceSideBarCopy = IO .temporaryDirectory / " sidebar.yml.copy"
3557+ IO .copyFile(file, referenceSideBarCopy)
3558+
3559+ override def apply (): Unit = {
3560+ val yaml = new org.yaml.snakeyaml.Yaml ()
3561+ type YamlObject = java.util.Map [String , AnyRef ]
3562+ type YamlList [T ] = java.util.List [T ]
3563+ def loadYaml (file : File ): YamlObject = {
3564+ val reader = Files .newBufferedReader(file.toPath)
3565+ try yaml.load(reader).asInstanceOf [YamlObject ]
3566+ finally reader.close()
3567+ }
3568+ // Ensure to always operate on original (Map, List) instances
3569+ val template = loadYaml(docs / " sidebar.nightly.template.yml" )
3570+ template.get(" subsection" )
3571+ .asInstanceOf [YamlList [YamlObject ]]
3572+ .stream()
3573+ .filter(_.get(" title" ) == " Reference" )
3574+ .findFirst()
3575+ .orElseThrow(() => new IllegalStateException (" Reference subsection not found in sidebar.nightly.template.yml" ))
3576+ .putAll(loadYaml(referenceSideBarCopy))
3577+
3578+ val sidebarWriter = Files .newBufferedWriter(this .file.toPath)
3579+ try yaml.dump(template, sidebarWriter)
3580+ finally sidebarWriter.close()
3581+ }
3582+ override def revert (): Unit = IO .move(referenceSideBarCopy, file)
3583+ },
3584+ // Add patch about nightly version usage
3585+ new SourcePatch (docs / " _layouts" / " static-site-main.html" ) {
3586+ lazy val originalContent = IO .read(file)
3587+
3588+ val warningMessage = """ {% if page.nightlyOf %}
3589+ | <aside class="warning">
3590+ | <div class='icon'></div>
3591+ | <div class='content'>
3592+ | This is a nightly documentation. The content of this page may not be consistent with the current stable version of language.
3593+ | Click <a href="{{ page.nightlyOf }}">here</a> to find the stable version of this page.
3594+ | </div>
3595+ | </aside>
3596+ |{% endif %}""" .stripMargin
3597+
3598+ override def apply (): Unit = {
3599+ IO .write(file,
3600+ originalContent
3601+ .replace(" {{ content }}" , s " $warningMessage {{ content }} " )
3602+ .ensuring(_.contains(warningMessage), " patch to static-site-main layout not applied!" )
3603+ )
3604+ }
3605+ override def revert (): Unit = IO .write(file, originalContent)
3606+ }
3607+ )
35353608
35363609 val config = Def .task {
3537- overrideFunc(Scala3 .value)
3610+ outputDirOverride
3611+ .andThen(justAPIOverride)
3612+ .apply(Scala3 .value)
35383613 }
35393614
35403615 val writeAdditionalFiles = Def .task {
35413616 val dest = file(config.value.get[OutputDir ].get.value)
3542- if (justAPIArg.isEmpty ) {
3617+ if (! justAPI ) {
35433618 IO .write(dest / " versions" / " latest-nightly-base" , majorVersion)
35443619 // This file is used by GitHub Pages when the page is available in a custom domain
35453620 IO .write(dest / " CNAME" , " dotty.epfl.ch" )
35463621 }
35473622 }
3623+ val applyPatches = Def .task {
3624+ streams.value.log.info(s " Generating snapshot scaladoc, would apply patches to ${sourcePatches.map(_.file)}" )
3625+ sourcePatches.foreach(_.apply())
3626+ }
3627+ val revertPatches = Def .task {
3628+ streams.value.log.info(s " Generated snapshot scaladoc, reverting changes made to ${sourcePatches.map(_.file)}" )
3629+ sourcePatches.foreach(_.revert())
3630+ }
35483631
3549- writeAdditionalFiles.dependsOn(generateDocumentation(config))
3632+ writeAdditionalFiles.dependsOn(
3633+ revertPatches.dependsOn(
3634+ generateDocumentation(config)
3635+ .dependsOn(applyPatches)
3636+ )
3637+ )
35503638 }.evaluated,
35513639
35523640 generateStableScala3Documentation := Def .inputTaskDyn {
35533641 val extraArgs = spaceDelimited(" <version>" ).parsed
3554- val config = stableScala3(extraArgs.head)
3642+ val version = baseVersion
3643+ // In the early days of scaladoc there was a practice to precompile artifacts of Scala 3 and generate docs using different version of scaladoc
3644+ // It's no longer needed after its stablisation.
3645+ // Allow to use explcit version check to detect using incorrect revision during release process
3646+ extraArgs.headOption.foreach { explicitVersion =>
3647+ assert(
3648+ explicitVersion == version,
3649+ s " Version of the build ( $version) does not match the explicit verion ( $explicitVersion) "
3650+ )
3651+ }
3652+
3653+ val docs = IO .createTemporaryDirectory
3654+ IO .copyDirectory(file(" docs" ), docs)
3655+ IO .delete(docs / " _blog" )
3656+
3657+ val config = Def .task {
3658+ Scala3 .value
3659+ .add(ProjectVersion (version))
3660+ .add(Revision (version))
3661+ .add(OutputDir (s " scaladoc/output/ ${version}" ))
3662+ .add(SiteRoot (docs.getAbsolutePath))
3663+ .remove[ApiSubdirectory ]
3664+ }
35553665 generateDocumentation(config)
35563666 }.evaluated,
35573667
@@ -3566,20 +3676,13 @@ object Build {
35663676 generateStaticAssetsTask.value
35673677
35683678 // Move all the source files to a temporary directory and apply some changes specific to the reference documentation
3569- val temp = IO .createTemporaryDirectory
3570- IO .copyDirectory(file(" docs" ), temp / " docs" )
3571- IO .delete(temp / " docs" / " _blog" )
3572-
3573- // Overwrite the main layout and the sidebar
3574- IO .copyDirectory(
3575- file(" project" ) / " resources" / " referenceReplacements" ,
3576- temp / " docs" ,
3577- overwrite = true
3578- )
3679+ val docs = IO .createTemporaryDirectory
3680+ IO .copyDirectory(file(" docs" ), docs)
3681+ IO .delete(docs / " _blog" )
35793682
35803683 // Add redirections from previously supported URLs, for some pages
35813684 for (name <- Seq (" changed-features" , " contextual" , " dropped-features" , " metaprogramming" , " other-new-features" )) {
3582- val path = temp / " docs" / " _docs" / " reference" / name / s " ${name}.md "
3685+ val path = docs / " _docs" / " reference" / name / s " ${name}.md "
35833686 val contentLines = IO .read(path).linesIterator.to[collection.mutable.ArrayBuffer ]
35843687 contentLines.insert(1 , s " redirectFrom: / ${name}.html " ) // Add redirection
35853688 val newContent = contentLines.mkString(" \n " )
@@ -3589,12 +3692,12 @@ object Build {
35893692 val languageReferenceConfig = Def .task {
35903693 Scala3 .value
35913694 .add(OutputDir (" scaladoc/output/reference" ))
3592- .add(SiteRoot (s " ${temp .getAbsolutePath} /docs " ))
3695+ .add(SiteRoot (docs .getAbsolutePath))
35933696 .add(ProjectName (" Scala 3 Reference" ))
35943697 .add(ProjectVersion (baseVersion))
35953698 .remove[VersionsDictionaryUrl ]
35963699 .add(SourceLinks (List (
3597- s " ${temp .getAbsolutePath}=github://scala/scala3/language-reference-stable "
3700+ s " ${docs.getParentFile() .getAbsolutePath}=github://scala/scala3/language-reference-stable "
35983701 )))
35993702 .withTargets(List (" ___fake___.scala" ))
36003703 }
@@ -4081,6 +4184,7 @@ object ScaladocConfigs {
40814184 .add(DocumentSyntheticTypes (true ))
40824185 // .add(SnippetCompiler(List(
40834186 // s"$dottyLibRoot/src/scala=compile",
4187+ // s"$dottyLibRoot/src/scala/quoted=compile",
40844188 // s"$dottyLibRoot/src/scala/compiletime=compile",
40854189 // s"$dottyLibRoot/src/scala/util=compile",
40864190 // s"$dottyLibRoot/src/scala/util/control=compile"
@@ -4090,33 +4194,4 @@ object ScaladocConfigs {
40904194 .withTargets((`scala-library-bootstrapped` / Compile / products).value.map(_.getAbsolutePath))
40914195 }
40924196
4093- def stableScala3 (version : String ) = Def .task {
4094- val scalaLibrarySrc = s " out/bootstrap/scala2-library-bootstrapped/scala- $version-bin-SNAPSHOT-nonbootstrapped/src_managed "
4095- val dottyLibrarySrc = " library/src"
4096- Scala3 .value
4097- .add(defaultSourceLinks(version = version))
4098- .add(ProjectVersion (version))
4099- .add(SnippetCompiler (
4100- List (
4101- s " $dottyLibrarySrc/scala/quoted=compile " ,
4102- s " $dottyLibrarySrc/scala/compiletime=compile " ,
4103- s " $dottyLibrarySrc/scala/util=compile " ,
4104- s " $dottyLibrarySrc/scala/util/control=compile "
4105- )
4106- ))
4107- .add(CommentSyntax (List (
4108- s " $dottyLibrarySrc=markdown " ,
4109- s " $scalaLibrarySrc=wiki " ,
4110- " wiki"
4111- )))
4112- .add(DocRootContent (s " $scalaLibrarySrc/rootdoc.txt " ))
4113- .withTargets(
4114- Seq (
4115- s " tmp/interfaces/target/classes " ,
4116- s " out/bootstrap/tasty-core-bootstrapped/scala- $version-bin-SNAPSHOT-nonbootstrapped/classes "
4117- )
4118- )
4119- .remove[SiteRoot ]
4120- .remove[ApiSubdirectory ]
4121- }
41224197}
0 commit comments