From 05f73107a916ee499c807b7f030535ea8df52714 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Thu, 22 Jul 2021 23:02:02 +0200 Subject: [PATCH 1/4] API pages are not top level --- scaladoc-testcases/src/docs/tests/Adoc.scala | 4 +++ .../src/resources/tests/Adoc.scala | 4 +++ .../scaladoc/renderers/HtmlRenderer.scala | 32 +++++++++++------ .../tools/scaladoc/renderers/Locations.scala | 11 +++--- .../tools/scaladoc/renderers/Resources.scala | 36 ++++++++++--------- .../scaladoc/site/StaticSiteContext.scala | 14 +++++--- .../conflicts-pages/docs/tests/Adoc.md | 1 + .../resources/tests/Adoc.html | 1 + .../dotty/tools/scaladoc/BaseHtmlTest.scala | 2 -- ...ernalLocationProviderIntegrationTest.scala | 3 +- .../dotty/tools/scaladoc/RaportingTest.scala | 34 +++++++++++++++++- .../AbstractMemberSignaturesTest.scala | 2 +- .../scaladoc/signatures/SignatureTest.scala | 2 +- .../tools/scaladoc/site/NavigationTest.scala | 20 +++++------ .../scaladoc/site/SiteGeneratationTest.scala | 21 +++++------ .../tasty/comments/IntegrationTest.scala | 6 ++-- .../test/dotty/tools/scaladoc/testUtils.scala | 9 +++-- 17 files changed, 134 insertions(+), 68 deletions(-) create mode 100644 scaladoc-testcases/src/docs/tests/Adoc.scala create mode 100644 scaladoc-testcases/src/resources/tests/Adoc.scala create mode 100644 scaladoc/test-documentations/conflicts-pages/docs/tests/Adoc.md create mode 100644 scaladoc/test-documentations/conflicts-resources/resources/tests/Adoc.html diff --git a/scaladoc-testcases/src/docs/tests/Adoc.scala b/scaladoc-testcases/src/docs/tests/Adoc.scala new file mode 100644 index 000000000000..af93f9eddfa0 --- /dev/null +++ b/scaladoc-testcases/src/docs/tests/Adoc.scala @@ -0,0 +1,4 @@ +package docs.tests + +class Adoc: + def foo = 123 diff --git a/scaladoc-testcases/src/resources/tests/Adoc.scala b/scaladoc-testcases/src/resources/tests/Adoc.scala new file mode 100644 index 000000000000..492d9637fdfd --- /dev/null +++ b/scaladoc-testcases/src/resources/tests/Adoc.scala @@ -0,0 +1,4 @@ +package resources.tests + +class Adoc: + def foo = 123 \ No newline at end of file diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala index 08e35dc3024c..9ae88f729425 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala @@ -58,19 +58,18 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx val hiddenPages: Seq[Page] = staticSite match - case None => - Seq(navigablePage.copy( // Add index page that is a copy of api/index.html - link = navigablePage.link.copy(dri = docsRootDRI), - children = Nil - )) + case None => Nil case Some(siteContext) => - (siteContext.orphanedTemplates :+ siteContext.indexTemplate()).map(templateToPage(_, siteContext)) + val actualIndexTemplate = siteContext.indexTemplates() match + case Nil if effectiveMembers.isEmpty => Seq(siteContext.emptyIndexTemplate) + case templates => templates + + (siteContext.orphanedTemplates ++ actualIndexTemplate).map(templateToPage(_, siteContext)) /** * Here we have to retrive index pages from hidden pages and replace fake index pages in navigable page tree. */ - private def getAllPages: Seq[Page] = - + val allPages: Seq[Page] = def traversePages(page: Page): (Page, Seq[Page]) = val (newChildren, newPagesToRemove): (Seq[Page], Seq[Page]) = page.children.map(traversePages(_)).foldLeft((Seq[Page](), Seq[Page]())) { case ((pAcc, ptrAcc), (p, ptr)) => (pAcc :+ p, ptrAcc ++ ptr) @@ -83,9 +82,22 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx val (newNavigablePage, pagesToRemove) = traversePages(navigablePage) - newNavigablePage +: hiddenPages.filterNot(pagesToRemove.contains) + val all = newNavigablePage +: hiddenPages.filterNot(pagesToRemove.contains) + // We need to check for conflicts only if we have top-level member called blog or docs + val hasPotentialConflict = + rootPackage.members.exists(m => m.name.startsWith("docs") || m.name.startsWith("blog")) + + if hasPotentialConflict then + def walk(page: Page): Unit = + if page.link.dri.isStaticFile then + val dest = absolutePath(page.link.dri) + if apiPaths.contains(dest) then + report.error(s"Conflict between static page and API member for $dest") + page.children.foreach(walk) + + all.foreach (walk) - val allPages = getAllPages + all def renderContent(page: Page) = page.content match case m: Member => diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala index ba01279930fc..1304a8459dc0 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala @@ -19,6 +19,10 @@ val UnresolvedLocationLink = "#" trait Locations(using ctx: DocContext): def effectiveMembers: Map[DRI, Member] + // We generate this collection only if there may be a conflict with resources. + // Potentially can be quite big. + lazy val apiPaths = effectiveMembers.keySet.filterNot(_.isStaticFile).map(absolutePath) + var cache = new JHashMap[DRI, Seq[String]]() // TODO verify if location exisits @@ -27,17 +31,16 @@ trait Locations(using ctx: DocContext): case null => val path = dri match case `docsRootDRI` => List("docs", "index") - case `apiPageDRI` => List("api", "index") + case `apiPageDRI` => + if ctx.staticSiteContext.fold(false)(_.hasIndexFile) then List("api", "index") else List("index") case dri if dri.isStaticFile => Paths.get(dri.location).iterator.asScala.map(_.toString).toList case dri => val loc = dri.location - val fqn = loc.split(Array('.')).toList match + loc.split(Array('.')).toList match case "" :: Nil => "_empty_" :: Nil case "" :: tail => "_empty_" :: tail case other => other - - Seq("api") ++ fqn cache.put(dri, path) path case cached => cached diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala index 99051b20645d..93f45be0a3fb 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala @@ -171,19 +171,23 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: ) def renderResource(resource: Resource): Seq[String] = - resource match - case Resource.Text(path, content) => - Seq(write(path, content)) - case Resource.Classpath(path, name) => - getClass.getClassLoader.getResourceAsStream(name) match - case null => - report.error(s"Unable to find $name on classpath") - Nil - case is => - try Seq(copy(is, path)) finally is.close() - case Resource.File(path, file) => - Seq(copy(file, path)) - case Resource.URL(url) => - Nil - case Resource.URLToCopy(url, dest) => - Seq(copy(new URL(url).openStream(), dest)) + if resource.path.endsWith(".html") && apiPaths.contains(resource.path) then + report.error(s"Conflict between resource and API member for ${resource.path}") + Nil + else + resource match + case Resource.Text(path, content) => + Seq(write(path, content)) + case Resource.Classpath(path, name) => + getClass.getClassLoader.getResourceAsStream(name) match + case null => + report.error(s"Unable to find $name on classpath") + Nil + case is => + try Seq(copy(is, path)) finally is.close() + case Resource.File(path, file) => + Seq(copy(file, path)) + case Resource.URL(url) => + Nil + case Resource.URLToCopy(url, dest) => + Seq(copy(new URL(url).openStream(), dest)) diff --git a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala index 00526bf623b1..8bf88cf47fee 100644 --- a/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala +++ b/scaladoc/src/dotty/tools/scaladoc/site/StaticSiteContext.scala @@ -19,17 +19,21 @@ class StaticSiteContext( var memberLinkResolver: String => Option[DRI] = _ => None - def indexTemplate(): LoadedTemplate = + private def indexFiles = val files = List(new File(root, "index.html"), new File(root, "index.md")).filter { _.exists() } if files.size > 1 then val msg = s"ERROR: Multiple root index pages found: ${files.map(_.getAbsolutePath)}" report.error(msg) + files - files.flatMap(loadTemplate(_, isBlog = false)).headOption.getOrElse { - val fakeFile = new File(root, "index.html") - LoadedTemplate(emptyTemplate(fakeFile, "index"), List.empty, fakeFile) - } + def hasIndexFile = indexFiles.nonEmpty + + def emptyIndexTemplate = + val fakeFile = new File(root, "index.html") + LoadedTemplate(emptyTemplate(fakeFile, "index"), List.empty, fakeFile) + + def indexTemplates(): Seq[LoadedTemplate] = indexFiles.flatMap(loadTemplate(_, isBlog = false)) lazy val layouts: Map[String, TemplateFile] = val layoutRoot = new File(root, "_layouts") diff --git a/scaladoc/test-documentations/conflicts-pages/docs/tests/Adoc.md b/scaladoc/test-documentations/conflicts-pages/docs/tests/Adoc.md new file mode 100644 index 000000000000..a0879c956838 --- /dev/null +++ b/scaladoc/test-documentations/conflicts-pages/docs/tests/Adoc.md @@ -0,0 +1 @@ +# Trying to override a api page! \ No newline at end of file diff --git a/scaladoc/test-documentations/conflicts-resources/resources/tests/Adoc.html b/scaladoc/test-documentations/conflicts-resources/resources/tests/Adoc.html new file mode 100644 index 000000000000..482b8942606e --- /dev/null +++ b/scaladoc/test-documentations/conflicts-resources/resources/tests/Adoc.html @@ -0,0 +1 @@ +I am causing conflicts! \ No newline at end of file diff --git a/scaladoc/test/dotty/tools/scaladoc/BaseHtmlTest.scala b/scaladoc/test/dotty/tools/scaladoc/BaseHtmlTest.scala index 82713d0505f7..b5590f51cbce 100644 --- a/scaladoc/test/dotty/tools/scaladoc/BaseHtmlTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/BaseHtmlTest.scala @@ -41,8 +41,6 @@ class BaseHtmlTest: finally IO.delete(dest.toFile) - val testDocPath = Paths.get(BuildInfo.testDocumentationRoot) - class DocumentContext(d: Document, path: Path): import collection.JavaConverters._ diff --git a/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala b/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala index 9c10a557b9de..41cfe662187b 100644 --- a/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala @@ -60,7 +60,7 @@ abstract class ExternalLocationProviderIntegrationTest( ) override def runTest = afterRendering { - val output = summon[DocContext].args.output.toPath.resolve("api") + val output = summon[DocContext].args.output.toPath val linksBuilder = List.newBuilder[String] def processFile(path: Path): Unit = @@ -72,7 +72,6 @@ abstract class ExternalLocationProviderIntegrationTest( linksBuilder ++= hrefValues } - println(output) IO.foreachFileIn(output, processFile) val links = linksBuilder.result val errors = expectedLinks.flatMap(expect => Option.when(!links.contains(expect))(expect)) diff --git a/scaladoc/test/dotty/tools/scaladoc/RaportingTest.scala b/scaladoc/test/dotty/tools/scaladoc/RaportingTest.scala index a73f026f7774..656e7dbaf9e5 100644 --- a/scaladoc/test/dotty/tools/scaladoc/RaportingTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/RaportingTest.scala @@ -44,7 +44,7 @@ class ReportingTest: finally Files.delete(notTasty) @Test - def verbosePrintsDokkaMessage = + def testSuccessfulDocsGeneration = val ctx = testContext ctx.setSetting(ctx.settings.verbose, true) checkReportedDiagnostics(ctx = ctx){ diag => @@ -53,3 +53,35 @@ class ReportingTest: assertMessagesAbout(diag.infoMsgs)("generation completed successfully") } + + @Test + def testErrorInCaseOfAssetShadowing = + val ctx = testContext + ctx.setSetting(ctx.settings.verbose, true) + val docsRoot = testDocPath.resolve("conflicts-resources").toString + checkReportedDiagnostics(_.copy( + docsRoot = Some(docsRoot), + tastyFiles = tastyFiles("tests", rootPck = "resources") + )){ diag => + assertNoWarning(diag) + val Seq(msg) = diag.errorMsgs.map(_.toLowerCase) + Seq("conflict","api", "resource", "resources/tests/adoc.html").foreach(word => + Assert.assertTrue(s"Error message: $msg should contains $word", msg.contains(word))) + } + + @Test + def testErrorInCaseOfDocsShadowing = + val ctx = testContext + ctx.setSetting(ctx.settings.verbose, true) + val docsRoot = testDocPath.resolve("conflicts-pages").toString + checkReportedDiagnostics(_.copy( + docsRoot = Some(docsRoot), + tastyFiles = tastyFiles("tests", rootPck = "docs") + )){ diag => + assertNoWarning(diag) + val Seq(msg) = diag.errorMsgs.map(_.toLowerCase) + Seq("conflict","api", "static", "page", "docs/tests/adoc.html") + .foreach( word => + Assert.assertTrue(s"Error message: $msg should contains $word", msg.contains(word)) + ) + } \ No newline at end of file diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/AbstractMemberSignaturesTest.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/AbstractMemberSignaturesTest.scala index 0d47c9ee6560..9a9556b868d7 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/AbstractMemberSignaturesTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/AbstractMemberSignaturesTest.scala @@ -26,7 +26,7 @@ class AbstractMembers extends ScaladocTest("abstractmembersignatures"): } private def signaturesFromDocumentation()(using DocContext): Map[String, List[(String, String)]] = - val output = summon[DocContext].args.output.toPath.resolve("api") + val output = summon[DocContext].args.output.toPath val signatures = List.newBuilder[(String, (String, String))] def processFile(path: Path): Unit = val document = Jsoup.parse(IO.read(path)) diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala index 05fa7164508e..8c381a5710d5 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala @@ -104,7 +104,7 @@ abstract class SignatureTest( } private def signaturesFromDocumentation()(using DocContext): Seq[String] = - val output = summon[DocContext].args.output.toPath.resolve("api") + val output = summon[DocContext].args.output.toPath val signatures = List.newBuilder[String] def processFile(path: Path): Unit = if filterFunc(path) then diff --git a/scaladoc/test/dotty/tools/scaladoc/site/NavigationTest.scala b/scaladoc/test/dotty/tools/scaladoc/site/NavigationTest.scala index 63b96d64db5b..86ffb829db58 100644 --- a/scaladoc/test/dotty/tools/scaladoc/site/NavigationTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/site/NavigationTest.scala @@ -30,17 +30,17 @@ class NavigationTest extends BaseHtmlTest: )), NavMenuTestEntry("Adoc", "Adoc.html", Seq()), NavMenuTestEntry("API", "../api/index.html", Seq( - NavMenuTestEntry("tests.site", "../api/tests/site.html", Seq( - NavMenuTestEntry("BrokenLink", "../api/tests/site/BrokenLink.html", Nil), - NavMenuTestEntry("BrokenLinkWiki", "../api/tests/site/BrokenLinkWiki.html", Nil), - NavMenuTestEntry("OtherPackageLink", "../api/tests/site/OtherPackageLink.html", Nil), - NavMenuTestEntry("OtherPackageLinkWiki", "../api/tests/site/OtherPackageLinkWiki.html", Nil), - NavMenuTestEntry("SamePackageLink", "../api/tests/site/SamePackageLink.html", Nil), - NavMenuTestEntry("SamePackageLinkWiki", "../api/tests/site/SamePackageLinkWiki.html", Nil), - NavMenuTestEntry("SomeClass", "../api/tests/site/SomeClass.html", Nil) + NavMenuTestEntry("tests.site", "../tests/site.html", Seq( + NavMenuTestEntry("BrokenLink", "../tests/site/BrokenLink.html", Nil), + NavMenuTestEntry("BrokenLinkWiki", "../tests/site/BrokenLinkWiki.html", Nil), + NavMenuTestEntry("OtherPackageLink", "../tests/site/OtherPackageLink.html", Nil), + NavMenuTestEntry("OtherPackageLinkWiki", "../tests/site/OtherPackageLinkWiki.html", Nil), + NavMenuTestEntry("SamePackageLink", "../tests/site/SamePackageLink.html", Nil), + NavMenuTestEntry("SamePackageLinkWiki", "../tests/site/SamePackageLinkWiki.html", Nil), + NavMenuTestEntry("SomeClass", "../tests/site/SomeClass.html", Nil) )), - NavMenuTestEntry("tests.site.some.other", "../api/tests/site/some/other.html", Seq( - NavMenuTestEntry("SomeOtherPackage", "../api/tests/site/some/other/SomeOtherPackage.html", Nil), + NavMenuTestEntry("tests.site.some.other", "../tests/site/some/other.html", Seq( + NavMenuTestEntry("SomeOtherPackage", "../tests/site/some/other/SomeOtherPackage.html", Nil), )) )), )) diff --git a/scaladoc/test/dotty/tools/scaladoc/site/SiteGeneratationTest.scala b/scaladoc/test/dotty/tools/scaladoc/site/SiteGeneratationTest.scala index 89baf7f90a4a..7ed53bf2e132 100644 --- a/scaladoc/test/dotty/tools/scaladoc/site/SiteGeneratationTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/site/SiteGeneratationTest.scala @@ -45,18 +45,19 @@ class SiteGeneratationTest extends BaseHtmlTest: def testApiPages( mainTitle: String = "API", - parents: Seq[String] = Seq(projectName))(using ProjectContext) = - checkFile("api/index.html")( + parents: Seq[String] = Seq(projectName), + hasToplevelIndexIndex: Boolean = true)(using ProjectContext) = + checkFile((if hasToplevelIndexIndex then "api/" else "" )+ "index.html")( title = mainTitle, header = projectName, parents = parents ) - checkFile("api/tests/site.html")( + checkFile("tests/site.html")( title = "tests.site", header = "tests.site", parents = parents :+ mainTitle ) - checkFile("api/tests/site/SomeClass.html")( + checkFile("tests/site/SomeClass.html")( title = "SomeClass", header = "SomeClass", parents = parents ++ Seq(mainTitle, "tests.site") @@ -70,12 +71,12 @@ class SiteGeneratationTest extends BaseHtmlTest: testApiPages() withHtmlFile("docs/Adoc.html"){ content => - content.assertAttr("p a","href", "../api/tests/site/SomeClass.html") + content.assertAttr("p a","href", "../tests/site/SomeClass.html") } - withHtmlFile("api/tests/site/SomeClass.html"){ content => + withHtmlFile("tests/site/SomeClass.html"){ content => content.assertAttr(".breadcrumbs a","href", - "../../../docs/index.html", "../../index.html", "../site.html", "SomeClass.html" + "../../docs/index.html", "../../api/index.html", "../site.html", "SomeClass.html" ) } } @@ -84,18 +85,18 @@ class SiteGeneratationTest extends BaseHtmlTest: def noGlobalIndexTest() = withGeneratedSite(testDocPath.resolve("noGlobalIndex")){ testDocPages() testDocIndexPage() - testApiPages() + testApiPages(hasToplevelIndexIndex = false) } @Test def noIndexesTest() = withGeneratedSite(testDocPath.resolve("noIndexes")){ testDocPages() - testApiPages() + testApiPages(hasToplevelIndexIndex = false) } @Test def noExistingDocs() = withGeneratedSite(testDocPath.resolve("noExisting")){ - testApiPages(mainTitle = projectName, parents = Nil) + testApiPages(mainTitle = projectName, parents = Nil, hasToplevelIndexIndex = false) } @Test diff --git a/scaladoc/test/dotty/tools/scaladoc/tasty/comments/IntegrationTest.scala b/scaladoc/test/dotty/tools/scaladoc/tasty/comments/IntegrationTest.scala index 0a5329cf6333..71f4b42f3320 100644 --- a/scaladoc/test/dotty/tools/scaladoc/tasty/comments/IntegrationTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/tasty/comments/IntegrationTest.scala @@ -18,11 +18,11 @@ abstract class BaseIntegrationTest(pck: String) extends BaseHtmlTest: "", "" // each represent a link ) - withHtmlFile(s"api/tests/$pck/BrokenLinks.html")(checkUnresolved) + withHtmlFile(s"tests/$pck/BrokenLinks.html")(checkUnresolved) val otherPackagePath = "../commonlinks/SomeOtherPackage.html" - withHtmlFile(s"api/tests/$pck/OtherPackageLink.html")(checkDocLinks(otherPackagePath)) + withHtmlFile(s"tests/$pck/OtherPackageLink.html")(checkDocLinks(otherPackagePath)) // OtherPackageMembers - does not work, TODO? - withHtmlFile(s"api/tests/$pck/SamePackageLink.html")(checkDocLinks("SomeClass.html")) + withHtmlFile(s"tests/$pck/SamePackageLink.html")(checkDocLinks("SomeClass.html")) // SamePackageMembers - does not work, TODO? } diff --git a/scaladoc/test/dotty/tools/scaladoc/testUtils.scala b/scaladoc/test/dotty/tools/scaladoc/testUtils.scala index 5d2191c22c40..21ed7398f74e 100644 --- a/scaladoc/test/dotty/tools/scaladoc/testUtils.scala +++ b/scaladoc/test/dotty/tools/scaladoc/testUtils.scala @@ -7,6 +7,7 @@ import dotty.tools.dotc.interfaces.Diagnostic.{ERROR, INFO, WARNING} import dotty.tools.scaladoc.test.BuildInfo import org.junit.Assert._ import java.io.File +import java.nio.file.Paths case class ReportedDiagnostics(errors: List[Diagnostic], warnings: List[Diagnostic], infos: List[Diagnostic]): @@ -57,14 +58,14 @@ def testArgs(files: Seq[File] = Nil, dest: File = new File("notUsed")) = Scalado docsRoot = Some(""), ) -def testContext = +def testContext = val ctx = (new ContextBase).initialCtx.fresh.setReporter(new TestReporter) ctx.setSetting(ctx.settings.usejavacp, true) ctx def testDocContext(files: Seq[File] = Nil) = DocContext(testArgs(files), testContext) -def tastyFiles(name: String, allowEmpty: Boolean = false) = +def tastyFiles(name: String, allowEmpty: Boolean = false, rootPck: String = "tests") = def listFilesSafe(dir: File) = Option(dir.listFiles).getOrElse { throw AssertionError(s"$dir not found. The test name is incorrect or scaladoc-testcases were not recompiled.") } @@ -73,7 +74,9 @@ def tastyFiles(name: String, allowEmpty: Boolean = false) = case f if f.getName endsWith ".tasty" => f :: Nil case _ => Nil } - val files = BuildInfo.test_testcasesOutputDir.flatMap(p => collectFiles(File(s"$p/tests/$name"))) + val outputDir = BuildInfo.test_testcasesOutputDir + val files = outputDir.flatMap(p => collectFiles(File(s"$p/$rootPck/$name"))) assert(files.nonEmpty || allowEmpty) files.toSeq +def testDocPath = Paths.get(BuildInfo.testDocumentationRoot) \ No newline at end of file From 8f78f332157ce624e1113f9692b931c0da5ffaf7 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Fri, 23 Jul 2021 00:05:46 +0200 Subject: [PATCH 2/4] Add -Ylegacy-api-layout to retain previous layout of API Add option to build 'flat' scaladoc package using `generateScalaDocumentation [output] --justAPI` --- project/Build.scala | 22 +++++++++++-------- .../src/dotty/tools/scaladoc/Scaladoc.scala | 6 +++-- .../tools/scaladoc/ScaladocSettings.scala | 3 +++ .../tools/scaladoc/renderers/Locations.scala | 7 ++++-- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 9527c1449782..1511bab57b33 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1325,6 +1325,7 @@ object Build { generateScalaDocumentation := Def.inputTaskDyn { val extraArgs = spaceDelimited("[output]").parsed val dest = file(extraArgs.headOption.getOrElse("scaladoc/output/scala3")).getAbsoluteFile + val justAPI = extraArgs.drop(1).headOption == Some("--justAPI") val majorVersion = (LocalProject("scala3-library-bootstrapped") / scalaBinaryVersion).value val dottyJars: Seq[java.io.File] = Seq( @@ -1346,21 +1347,24 @@ object Build { val dottyLibRoot = projectRoot.relativize(dottyManagesSources.toPath.normalize()) + def generateDocTask = + generateDocumentation( + roots, "Scala 3", dest.getAbsolutePath, "master", + Seq( + "-comment-syntax", "wiki", + s"-source-links:docs=github://lampepfl/dotty/master#docs", + "-doc-root-content", docRootFile.toString, + "-Ydocument-synthetic-types" + ) ++ (if (justAPI) Nil else Seq("-siteroot", "docs", "-Ylegacy-api-layout"))) + if (dottyJars.isEmpty) Def.task { streams.value.log.error("Dotty lib wasn't found") } + else if (justAPI) generateDocTask else Def.task{ IO.write(dest / "versions" / "latest-nightly-base", majorVersion) // This file is used by GitHub Pages when the page is available in a custom domain IO.write(dest / "CNAME", "dotty.epfl.ch") - }.dependsOn(generateDocumentation( - roots, "Scala 3", dest.getAbsolutePath, "master", - Seq( - "-comment-syntax", "wiki", - "-siteroot", "docs", - s"-source-links:docs=github://lampepfl/dotty/master#docs", - "-doc-root-content", docRootFile.toString, - "-Ydocument-synthetic-types" - ))) + }.dependsOn(generateDocTask) }.evaluated, generateTestcasesDocumentation := Def.taskDyn { diff --git a/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala b/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala index fca0f2b04270..34dffdf3ee2d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala @@ -58,7 +58,8 @@ object Scaladoc: snippetCompilerDebug: Boolean = false, noLinkWarnings: Boolean = false, versionsDictionaryUrl: Option[String] = None, - generateInkuire : Boolean = false + generateInkuire : Boolean = false, + legacyAPILayout : Boolean = false ) def run(args: Array[String], rootContext: CompilerContext): Reporter = @@ -223,7 +224,8 @@ object Scaladoc: noLinkWarnings.get, snippetCompilerDebug.get, versionsDictionaryUrl.nonDefault, - generateInkuire.get + generateInkuire.get, + legacyAPILayout.get, ) (Some(docArgs), newContext) } diff --git a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala index b5b725ffcca0..862a7eecbfe7 100644 --- a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala +++ b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala @@ -120,5 +120,8 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings: val generateInkuire: Setting[Boolean] = BooleanSetting("-Ygenerate-inkuire", "Generates InkuireDB and enables Hoogle-like searches", false) + val legacyAPILayout: Setting[Boolean] = + BooleanSetting("-Ylegacy-api-layout", "Keep all api member inside `api` directory", false) + def scaladocSpecificSettings: Set[Setting[_]] = Set(sourceLinks, syntax, revision, externalDocumentationMappings, socialLinks, skipById, skipByRegex, deprecatedSkipPackages, docRootContent, snippetCompiler, snippetCompilerDebug, generateInkuire) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala index 1304a8459dc0..b54589db3449 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala @@ -32,15 +32,18 @@ trait Locations(using ctx: DocContext): val path = dri match case `docsRootDRI` => List("docs", "index") case `apiPageDRI` => - if ctx.staticSiteContext.fold(false)(_.hasIndexFile) then List("api", "index") else List("index") + if ctx.args.legacyAPILayout || ctx.staticSiteContext.fold(false)(_.hasIndexFile) + then List("api", "index") + else List("index") case dri if dri.isStaticFile => Paths.get(dri.location).iterator.asScala.map(_.toString).toList case dri => val loc = dri.location - loc.split(Array('.')).toList match + val fqn = loc.split(Array('.')).toList match case "" :: Nil => "_empty_" :: Nil case "" :: tail => "_empty_" :: tail case other => other + if ctx.args.legacyAPILayout then "api" :: fqn else fqn cache.put(dri, path) path case cached => cached From 8a2325d70ac2834ed16ad7a8f7c4b6bde1ee2fbc Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Fri, 23 Jul 2021 12:12:24 +0200 Subject: [PATCH 3/4] Fix sbt tests and make error messages more helpul in case of conflicts in docs --- sbt-test/sbt-dotty/scaladoc/build.sbt | 2 +- scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala | 2 +- scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala | 3 +++ scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/sbt-test/sbt-dotty/scaladoc/build.sbt b/sbt-test/sbt-dotty/scaladoc/build.sbt index ff6cdffbfc12..eec38852797f 100644 --- a/sbt-test/sbt-dotty/scaladoc/build.sbt +++ b/sbt-test/sbt-dotty/scaladoc/build.sbt @@ -6,6 +6,6 @@ TaskKey[Unit]("checkScaladocOptions") := { } TaskKey[Unit]("checkHtmlFiles") := { - val helloHtml = (Compile / doc / target).value / "api" / "hello.html" + val helloHtml = (Compile / doc / target).value / "hello.html" assert(helloHtml.exists) } diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala index 9ae88f729425..92e85d36b1b8 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala @@ -92,7 +92,7 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx if page.link.dri.isStaticFile then val dest = absolutePath(page.link.dri) if apiPaths.contains(dest) then - report.error(s"Conflict between static page and API member for $dest") + report.error(s"Conflict between static page and API member for $dest. $pathsConflictResoultionMsg") page.children.foreach(walk) all.foreach (walk) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala index b54589db3449..f6d17def7d49 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala @@ -25,6 +25,9 @@ trait Locations(using ctx: DocContext): var cache = new JHashMap[DRI, Seq[String]]() + private[renderers] def pathsConflictResoultionMsg = + "Using `-Ylegacy-api-layout` flag will move all API documentaiton into `api` subdirectory and will fix this conflict." + // TODO verify if location exisits def rawLocation(dri: DRI): Seq[String] = cache.get(dri) match diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala index 93f45be0a3fb..43278fe7f396 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Resources.scala @@ -172,7 +172,7 @@ trait Resources(using ctx: DocContext) extends Locations, Writer: def renderResource(resource: Resource): Seq[String] = if resource.path.endsWith(".html") && apiPaths.contains(resource.path) then - report.error(s"Conflict between resource and API member for ${resource.path}") + report.error(s"Conflict between resource and API member for ${resource.path}. $pathsConflictResoultionMsg") Nil else resource match From 49f2d03a6372e8d7af0c90eac831627c077862e8 Mon Sep 17 00:00:00 2001 From: Krzysztof Romanowski Date: Fri, 23 Jul 2021 16:28:44 +0200 Subject: [PATCH 4/4] rename legacyAPILayout to apiSubdirectory --- project/Build.scala | 2 +- scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala | 4 ++-- scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala | 4 ++-- .../src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala | 8 +++++++- .../src/dotty/tools/scaladoc/renderers/Locations.scala | 6 +++--- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/project/Build.scala b/project/Build.scala index 1511bab57b33..b850680d79f2 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -1355,7 +1355,7 @@ object Build { s"-source-links:docs=github://lampepfl/dotty/master#docs", "-doc-root-content", docRootFile.toString, "-Ydocument-synthetic-types" - ) ++ (if (justAPI) Nil else Seq("-siteroot", "docs", "-Ylegacy-api-layout"))) + ) ++ (if (justAPI) Nil else Seq("-siteroot", "docs", "-Yapi-subdirectory"))) if (dottyJars.isEmpty) Def.task { streams.value.log.error("Dotty lib wasn't found") } else if (justAPI) generateDocTask diff --git a/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala b/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala index 34dffdf3ee2d..20dc4f288d44 100644 --- a/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala +++ b/scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala @@ -59,7 +59,7 @@ object Scaladoc: noLinkWarnings: Boolean = false, versionsDictionaryUrl: Option[String] = None, generateInkuire : Boolean = false, - legacyAPILayout : Boolean = false + apiSubdirectory : Boolean = false ) def run(args: Array[String], rootContext: CompilerContext): Reporter = @@ -225,7 +225,7 @@ object Scaladoc: snippetCompilerDebug.get, versionsDictionaryUrl.nonDefault, generateInkuire.get, - legacyAPILayout.get, + apiSubdirectory.get, ) (Some(docArgs), newContext) } diff --git a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala index 862a7eecbfe7..c9561d7eb56d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala +++ b/scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala @@ -120,8 +120,8 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings: val generateInkuire: Setting[Boolean] = BooleanSetting("-Ygenerate-inkuire", "Generates InkuireDB and enables Hoogle-like searches", false) - val legacyAPILayout: Setting[Boolean] = - BooleanSetting("-Ylegacy-api-layout", "Keep all api member inside `api` directory", false) + val apiSubdirectory: Setting[Boolean] = + BooleanSetting("-Yapi-subdirectory", "Keep all api member inside `api` directory", false) def scaladocSpecificSettings: Set[Setting[_]] = Set(sourceLinks, syntax, revision, externalDocumentationMappings, socialLinks, skipById, skipByRegex, deprecatedSkipPackages, docRootContent, snippetCompiler, snippetCompilerDebug, generateInkuire) diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala index 92e85d36b1b8..c35f98c24a6d 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/HtmlRenderer.scala @@ -58,8 +58,14 @@ class HtmlRenderer(rootPackage: Member, val members: Map[DRI, Member])(using ctx val hiddenPages: Seq[Page] = staticSite match - case None => Nil + case None => + Seq(navigablePage.copy( // Add index page that is a copy of api/index.html + link = navigablePage.link.copy(dri = docsRootDRI), + children = Nil + )) case Some(siteContext) => + // In case that we do not have an index page and we do not have any API entries + // we want to create empty index page, so there is one val actualIndexTemplate = siteContext.indexTemplates() match case Nil if effectiveMembers.isEmpty => Seq(siteContext.emptyIndexTemplate) case templates => templates diff --git a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala index f6d17def7d49..e65ae4260590 100644 --- a/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala +++ b/scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala @@ -26,7 +26,7 @@ trait Locations(using ctx: DocContext): var cache = new JHashMap[DRI, Seq[String]]() private[renderers] def pathsConflictResoultionMsg = - "Using `-Ylegacy-api-layout` flag will move all API documentaiton into `api` subdirectory and will fix this conflict." + "Using `-Yapi-subdirectory` flag will move all API documentation into `api` subdirectory and will fix this conflict." // TODO verify if location exisits def rawLocation(dri: DRI): Seq[String] = @@ -35,7 +35,7 @@ trait Locations(using ctx: DocContext): val path = dri match case `docsRootDRI` => List("docs", "index") case `apiPageDRI` => - if ctx.args.legacyAPILayout || ctx.staticSiteContext.fold(false)(_.hasIndexFile) + if ctx.args.apiSubdirectory || ctx.staticSiteContext.fold(false)(_.hasIndexFile) then List("api", "index") else List("index") case dri if dri.isStaticFile => @@ -46,7 +46,7 @@ trait Locations(using ctx: DocContext): case "" :: Nil => "_empty_" :: Nil case "" :: tail => "_empty_" :: tail case other => other - if ctx.args.legacyAPILayout then "api" :: fqn else fqn + if ctx.args.apiSubdirectory then "api" :: fqn else fqn cache.put(dri, path) path case cached => cached