Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generating and Attaching of Scaladocs are broken with Scala3 #604

Open
chr78rm opened this issue May 24, 2022 · 28 comments
Open

Generating and Attaching of Scaladocs are broken with Scala3 #604

chr78rm opened this issue May 24, 2022 · 28 comments

Comments

@chr78rm
Copy link

chr78rm commented May 24, 2022

The production of Scaladoc APIs are broken when using Scala3, e.g. with Scala 3.1.2:

<profile>
    <id>scala3-failure</id>
    <properties>
        <scala-maven-plugin.version>4.6.1</scala-maven-plugin.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>${scala-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>Scalac</id>
                        <goals>
                            <goal>compile</goal>
                            <goal>testCompile</goal>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <args>
                                <arg>-deprecation</arg>
                                <arg>-release:17</arg>
                                <arg>-encoding</arg>
                                <arg>utf-8</arg>
                            </args>
                        </configuration>
                    </execution>
                    <execution>
                        <id>Scaladoc-jar</id>
                        <goals>
                            <goal>doc-jar</goal>
                        </goals>
                        <phase>package</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala3-library_3</artifactId>
            <version>3.1.2</version>
        </dependency>
    </dependencies>
</profile>

This gives

$ mvn clean install -P scala3-failure
...
[INFO]
[INFO] --- maven-source-plugin:3.2.1:jar-no-fork (attach-sources) @ scaladoc-jar-test ---
[INFO] Building jar: C:\Users\Developer\Git\Git-2.36.0-64-bit\projects\scaladoc-jar-test\target\scaladoc-jar-test-0.0.1-sources.jar
[INFO]
[INFO] >>> scala-maven-plugin:4.6.1:doc-jar (Scaladoc-jar) > generate-sources @ scaladoc-jar-test >>>
[INFO]
[INFO] --- scala-maven-plugin:4.6.1:add-source (Scalac) @ scaladoc-jar-test ---
[INFO]
[INFO] <<< scala-maven-plugin:4.6.1:doc-jar (Scaladoc-jar) < generate-sources @ scaladoc-jar-test <<<
[INFO]
[INFO]
[INFO] --- scala-maven-plugin:4.6.1:doc-jar (Scaladoc-jar) @ scaladoc-jar-test ---
bad option '-doc-format:html' was ignored
bad option '-doc-title' was ignored
source file not found: scaladoc-jar-test 0.0.1 API
2 warnings found
1 error found
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
...

The issue can be reproduced with the build profile scala3-failure of the test project. The test project can be cloned by

git clone https://github.com/chr78rm/scaladoc-jar-test.git

The mentioned profile uses the currently promoted version (4.6.1) of the plugin and tries to attach scaladocs as depicted on the project site. I have investigated this a bit further. One reason why this cannot work is the wrong qualified class name given by the the method apidocMainClassName(). The correct qualified class name would be dotty.tools.scaladoc.Main. Using Scala3 this class is even separated from the scala compiler, that is an additional dependency (scaladoc_3) is needed to resolve this class. Unfortunately a potential fix in accordance with the outline of the given program structure of the plugin runs into classloader issues. scaladoc_3 uses the java.lang.ClassLoader.getResourceAsStream(String) method but it seems that the invocations prepared by e.g. JavaMainCallerByFork don't provide a class loader when calling getClassLoader(). I am not an expert in classloader issues but it might well be that this issue is inevitable when using the currently provided invocations within the scala_maven_executions package.

Nevertheless, I have prepared a possible fix within the forked repo

https://github.com/chr78rm/scala-maven-plugin

of your plugin. Checkout the branch scaladoc3. The prepared fix uses the ProcessBuilder of the JDK to invoke a forked process and reflects as far as possible the given outline of the plugin code structure. The mentioned classloader issue can be triggered by checking out the branch classloader-issue. Both mentioned branches of the fork produce an artifact of the plugin with version 4.6.2-EXPERIMENTAL. This version is used by the other build profiles of the test project.

@chr78rm
Copy link
Author

chr78rm commented Jun 3, 2022

I have updated the test project to use the currently promoted version 4.6.2 within the build profile scala3-failure. Your latest commits have been integrated into the fork of your plugin. The branches scaladoc3 and classloader-issue are producing the version 4.6.3-EXPERIMENTAL now. Again, these version is referenced by the other build profiles of the reproducer.

@slandelle
Copy link
Collaborator

@chr78rm Thanks for reporting.
Sadly, I can't review your fork:

  • lots of intermediate/trial-and-error/back-and-forth commits
  • not rebased on upstream's HEAD
  • is there an integration test proving your fix?

I'll only be able to review if you can provide a PR that fixes the above points (all the more as I personally use neither Scala 3 nor Scaladoc).
Regards

@chr78rm
Copy link
Author

chr78rm commented Jun 6, 2022

Thank you for your answer. I didn't want to put too much effort into this beforehand.

Please don't read too much into some of the commits on the branches. I needed to research your code and hence I had included some tracing statements at some time. After I understood the inner workings of the plugin well enough I had removed them again. Besides, I had updated the master branch of the forked repo to your latest commit (eac2c9b). After that, I integrated your latest commits including the fix for issue #600 into the scaladoc3 branch by working on the output of git diff master..scaladoc3 --name-only. That is to say the files listed by git diff master..scaladoc3 --name-only contain the relevant changes for the possible fix at this instant. All your commits up to (eac2c9b) are included in scaladoc3 now.

$ git diff master..scaladoc3 --name-only
pom.xml
src/main/java/scala_maven/ScalaDocMojo.java
src/main/java/scala_maven/ScalaMojoSupport.java
src/main/java/scala_maven_dependency/ArtifactIds.java
src/main/java/scala_maven_dependency/ArtifactIds4Scala2.java
src/main/java/scala_maven_dependency/ArtifactIds4Scala3.java
src/main/java/scala_maven_dependency/Context.java
src/main/java/scala_maven_dependency/Context4ScalaHome.java
src/main/java/scala_maven_dependency/Context4ScalaRemote.java
src/main/java/scala_maven_executions/ScalaDoc3Caller.java

I have attached a file with the full diffs to this comment but you might want to use an IDE for a better visual experience.

Additionally, I will replay the relevant diffs into a new branch rooted at your latest commit. I haven't looked into how you are organizing your integration tests yet. I'm using the mentioned test project as reference at this stage. E.g. the test project contains a build profile scala2 which can be used to verify that everything works in Scala2 as before. Another build profile works with Scala3.

Of course I can provide a pull request for this in due course.

diff-scaladoc3-master.txt

@hohonuuli
Copy link

hohonuuli commented Feb 9, 2023

Is there a way to disable arguments that are used to execute the scaladoc? Under the hood the Scala-maven-plugin scaladoc execution is running a command like:

 /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/bin/java -Xbootclasspath/a:/Users/brian/.m2/repository/com/google/protobuf/protobuf-java/3.7.0/protobuf-java-3.7.0.jar:[...] -classpath /Users/brian/.m2/repository/net/alchim31/maven/scala-maven-plugin/4.8.0/scala-maven-plugin-4.8.0.jar scala_maven_executions.MainWithArgsInFile dotty.tools.dotc.Main /private/var/folders/d7/4ps3zfnx08n8gxq0wc9ydddw0000gq/T/scala-maven-2306955749493420450.args

The problem I seem to hit is that the temp file (e.g. /private/var/folders/d7/4ps3zfnx08n8gxq0wc9ydddw0000gq/T/scala-maven-2306955749493420450.args) contains the following lines:

-doc-format:html
-doc-title
"scommons 0.0.4_3 API"

These flags are are no longer appropriate for scaladoc 3 and when included produce the following:

bad option '-doc-format:html' was ignored
bad option '-doc-title' was ignored
source file not found: scommons 0.0.4_3 API
2 warnings found
1 error found

When I manually edit those out of the args file and rerun the command above, it works fine. So being able to strip those out of the args file might resolve this issue.

@hohonuuli
Copy link

Code that produces the bad flag is here

@mnd999
Copy link

mnd999 commented Mar 20, 2023

The flags are old and deprecated but they shouldn't break anything according to scala/scala3#11907. The problem seems to be the newline that gets generated between -doc-title and the module name itself. If the offending lines in the file become as follows, we get warnings but it doesn't fail anymore:

-doc-format:html
-doc-title "scommons 0.0.4_3 API"

This would seem like a reasonably quick workaround to do.

@jam01
Copy link

jam01 commented Jun 29, 2024

Hi all, just hit this in 4.9.1. Is there any user-level workarounds?


edit: from what I've found so far, it seems in Scala 3 the plugin should be using a different class dotty.tools.scaladoc.Main? This is what gradle is using also


edit2: getting a little further with:

configuration:
  scaladocClassName: dotty.tools.scaladoc.Main
  dependencies:
    - groupId: org.scala-lang
      artifactId: scaladoc_3
      version: 3.3.3

forgive the yaml syntax (trying out polyglot)

I get the following with displayCmd

... scala_maven_executions.MainWithArgsInFile dotty.tools.scaladoc.Main /tmp/scala-maven-8998361167489940263.args
bad option '-doc-format:html' was ignored
scaladoc supports only .tasty and .jar files, following files will be ignored: ...
java.lang.NullPointerException: Cannot invoke "java.lang.ClassLoader.getResourceAsStream(String)" because the return value of "java.lang.Class.getClassLoader()" is null
	at dotty.tools.scaladoc.renderers.Resources.renderResource(Resources.scala:557)
	at dotty.tools.scaladoc.renderers.Resources.renderResource$(Resources.scala:20)
	at dotty.tools.scaladoc.renderers.Renderer.renderResource(Renderer.scala:20)
	at dotty.tools.scaladoc.renderers.HtmlRenderer.renderResources$$anonfun$1(HtmlRenderer.scala:74)
	at scala.collection.immutable.List.flatMap(List.scala:293)
	at scala.collection.immutable.List.flatMap(List.scala:79)
	at dotty.tools.scaladoc.renderers.HtmlRenderer.renderResources(HtmlRenderer.scala:74)
	at dotty.tools.scaladoc.renderers.HtmlRenderer.render(HtmlRenderer.scala:48)
	at dotty.tools.scaladoc.Scaladoc$.run(Scaladoc.scala:239)
	at dotty.tools.scaladoc.Scaladoc$.run$$anonfun$1(Scaladoc.scala:69)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.Option.map(Option.scala:242)
	at dotty.tools.scaladoc.Scaladoc$.run(Scaladoc.scala:73)
	at dotty.tools.scaladoc.Main.run(Main.scala:8)
	at dotty.tools.scaladoc.Main$.main(Main.scala:14)
	at dotty.tools.scaladoc.Main.main(Main.scala)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at scala_maven_executions.MainHelper.runMain(MainHelper.java:156)
	at scala_maven_executions.MainWithArgsInFile.main(MainWithArgsInFile.java:30)

edit3: adding args: ['-nobootcp'] prevents the error and the goal succeeds, but there's no actual docs in the -javadoc.jar. I'm confident it's because all the files passed listed are .scala which are not supported...


edit4: working configuration for scala 3.3.3

- id: attach-javadocs
  goals: ['doc-jar'] # on package
  configuration:
    args: ['-nobootcp'] # avoid NPE from getClass.getClassLoader
    scaladocClassName: dotty.tools.scaladoc.Main # scala3 class
    sourceDir: '${project.build.outputDirectory}' # use compiled classes
    includes: ['**/*.tasty'] # only tasty
    dependencies:
      - groupId: org.scala-lang
        artifactId: scaladoc_3
        version: 3.3.3

@chr78rm
Copy link
Author

chr78rm commented Jul 4, 2024

I can confirm that the configuration above does the trick for now. But it seems unreliable at best because it depends on an unsupported option (-nobootcp). Indeed I am getting the output: "bad option '-nobootcp' was ignored", but it wasn't actually ignored since removing the option causes the ClassLoader bug again.

The Compiler Options Lookup Table notes this option as not yet available in Scala 3.3.x and you cannot find this option within the ScalaDoc Settings at all. The same applies when listing the available options via scalac -help or scaladoc -help on the command line.

I had submitted a pull request (#611) two years ago which would have fixed this issue but the maintainers had chosen to ignore it.

The ScalaDoc generation additionally suffers from this bug at present: Scaladoc generates broken local links.

@slandelle
Copy link
Collaborator

slandelle commented Jul 4, 2024

I had submitted a pull request (#611) two years ago which would have fixed this issue but the maintainers had chosen to ignore it.

@chr78rm This is both not correct and offending.
I requested that you clean up your PR (squash commit, remove extra dependency to one of your personal projects) and rebase it as it was conflicting with the main branch before I could review.
This has not been done yet.

Please understand that I have some professional interest in maven + Scala 2 but have none for maven + Scala 3 and never will.
Still, I'm willing to spend some of my personal time to help solve other people's problems. But only to a certain extend.
Help me help you.

@chr78rm
Copy link
Author

chr78rm commented Jul 5, 2024

Please, calm down @slandelle . I have simply stated the fact that you chose to ignore the pull request, speak: to not integrate it - for whatever reasonable or unreasonable grounds you might have had. I really don't know how this comes as offending. Bye, Bye.

@slandelle
Copy link
Collaborator

I haven't chosen to ignore it. I've requested you to perform some changes before I could review it, which you haven't.

@johanhaleby
Copy link

I'm having the very same problem as we speak. I can't release my open-source project (rest-assured) because of this :( Will try the workarounds by @jam01 .

@slandelle
Copy link
Collaborator

@johanhaleby IMHO, if you want to provide modules for Scala 3, you should build and release them with sbt.

@johanhaleby
Copy link

@slandelle Yeah that might be so, but it would complicate my build process even further and I've not used sbt in 10+ years so I'm very rusty. I have other scala modules as well that use Scala 2, and I can generate javadoc there without any issues.

@johanhaleby
Copy link

It compiles and builds just fine btw, it's just javadoc generation that I struggle with. And I can't publish to maven central because of that.

@jam01
Copy link

jam01 commented Jul 5, 2024

Thank you for your work @slandelle .

I gave sbt a try and wow ... Literally every project I've seen is configured differently. Basically my decision with my project was, if Maven can do it I'll use Maven, if not I'll figure out sbt. Thankfully I was able to figure it out through this project.

Additionally, the upcoming Maven 4 features should really leave little to be missed between Maven and other build tools (other than the official support from the Scala team).

Right now the only thing I'm missing is the ability to test Scala.js code in a JS environment (which sbt supports). But I can live with that. (Also someone figured it out in Gradle so I might venture a PR at some point if I really needed it).

@johanhaleby
Copy link

To reproduce my problems:

  1. Checkout the repo: git clone [email protected]:rest-assured/rest-assured.git
  2. mvn clean install -Dmaven.test.skip=true
  3. cd modules/scala-extensions
  4. mvn clean package -Prelease

It'll end this error:

[INFO] --- scala:4.9.2:doc-jar (attach-javadocs) @ scala-extensions ---
bad option '-doc-format:html' was ignored
bad option '-doc-title' was ignored
source file not found: scala-extensions 5.4.1-SNAPSHOT API

@johanhaleby
Copy link

johanhaleby commented Jul 5, 2024

I've also tried porting @jam01's workaround to maven like this:

<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>4.9.2</version>
<executions>   
    <execution>
        <id>attach-javadocs</id>
        <goals>
            <goal>doc-jar</goal>
        </goals>
        <configuration>
            <scaladocClassName>dotty.tools.scaladoc.Main</scaladocClassName>
            <sourceDir>${project.build.outputDirectory}</sourceDir>
            <args>-nobootcp</args>
            <includes>
                <include>**/*.scala</include>
            </includes>
            <additionalDependencies>
                <dependency>
                    <groupId>org.scala-lang</groupId>
                    <artifactId>scaladoc_3</artifactId>
                    <version>3.4.2</version>
                </dependency>
            </additionalDependencies>
        </configuration>
    </execution>
</executions>

But now it fails with:

ava.lang.ClassNotFoundException: dotty.tools.scaladoc.Main
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at scala_maven_executions.MainHelper.runMain(MainHelper.java:144)
        at scala_maven_executions.MainWithArgsInFile.main(MainWithArgsInFile.java:30)

@slandelle
Copy link
Collaborator

Let me say things bluntly (my opinion only).

This project is currently understaffed and the current's staff interests don't align with yours.

We are currently 2 persons:

  • @davidB who's the owner but hasn't been using Scala for a decade and who's no longer active here
  • myself who is Gatling's CTO and as a result is only interested in this plugin for compiling Scala 2 code.

I will never ever have an interest in using this plugin for scaladoc, Scala 3, Scala.js, Scala native or Spark.
I'm willing to spend a bit of personal time reviewing clean PRs on topics that are of no concern to me but I won't investigate and fix such issues myself.

This code is open-source, if you don't want this plugin to die, I see 2 solutions:

  • contribute
  • hope the Scala Center takes over

@jam01
Copy link

jam01 commented Jul 5, 2024

That's fair, this is the nature of open source. I appreciate your disclaimer.

Scala 3, Scala.js (minus tests in JS) and scaladoc (with my overriding config) are already supported out of the box. The only reason I didn't submit a PR is because I found my config to be pretty simple to merit the PR work for me at this point (again the nature of open source).

Perhaps you'd consider closing this issue since there's a workaround.

@jam01
Copy link

jam01 commented Jul 5, 2024

@johanhaleby I tried to give your project a shot, but based on an error I got at compilation I think it requires Java 8 which I don't have locally.

That Main class is there on 3.4.2 so perhaps there's a dependency management issue? Also change your includes to be **/*.tasty instead of .scala.

@johanhaleby
Copy link

@slandelle I'm the first one to respect this, I know how difficult it can be to maintain an open-source project ❤️

@johanhaleby
Copy link

@jam01 Yeah it's still using Java 8. But the code in the module is a .scala file. Should I still use **/*.tasty?

@jam01
Copy link

jam01 commented Jul 5, 2024

@johanhaleby oh I think your issue is you're using the wrong "dependencies" element, it shoud be dependencies and not additionalDependencies see here.

Yes, you should still use tasty.

@johanhaleby
Copy link

johanhaleby commented Jul 5, 2024

@jam01 Nice find, thank you! I changed to this:

 <execution>
    <id>attach-javadocs</id>
    <goals>
        <goal>doc-jar</goal>
    </goals>
    <configuration>
        <scaladocClassName>dotty.tools.scaladoc.Main</scaladocClassName>
        <sourceDir>${project.build.outputDirectory}</sourceDir>
        <args>-nobootcp</args>
        <includes>
            <include>**/*.tasty</include>
        </includes>
        <dependencies>
            <dependency>
                <groupId>org.scala-lang</groupId>
                <artifactId>scaladoc_3</artifactId>
                <version>3.4.2</version>
            </dependency>
        </dependencies>
    </configuration>
</execution>

but now it fails with:

java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at scala_maven_executions.MainHelper.runMain(MainHelper.java:156)
        at scala_maven_executions.MainWithArgsInFile.main(MainWithArgsInFile.java:30)
Caused by: java.lang.AbstractMethodError: Method dotty/tools/scaladoc/ScaladocSettings.dotty$tools$dotc$config$YSettings$_setter_$YccNoAbbrev_$eq(Ldotty/tools/dotc/config/Settings$Setting;)V is abstract
        at dotty.tools.scaladoc.ScaladocSettings.dotty$tools$dotc$config$YSettings$_setter_$YccNoAbbrev_$eq(ScaladocSettings.scala)
        at dotty.tools.dotc.config.YSettings.$init$(ScalaSettings.scala:316)
        at dotty.tools.scaladoc.ScaladocSettings.<init>(ScaladocSettings.scala:7)
        at dotty.tools.scaladoc.Scaladoc$.extract(Scaladoc.scala:99)
        at dotty.tools.scaladoc.Scaladoc$.run(Scaladoc.scala:53)
        at dotty.tools.scaladoc.Main.run(Main.scala:8)
        at dotty.tools.scaladoc.Main$.main(Main.scala:14)
        at dotty.tools.scaladoc.Main.main(Main.scala)

😢

@johanhaleby
Copy link

My bad! I had a different version of scaladoc_3 than the scala compiler. Now it freaking works!!!

Thanks A LOT!!! You definitely made my day.

@mcallisto
Copy link

Hello @jam01

can you please elaborate further on Scala.js support out of the box?

Scala 3, Scala.js (minus tests in JS) and scaladoc (with my overriding config) are already supported out of the box.

If scala-maven-plugin can compile and package Scala.js can you provide / point to a sample POM file or any useful reference?

@jam01
Copy link

jam01 commented Sep 8, 2024

See if this helps https://github.com/jam01/json-schema/blob/0.1.0/js/pom.yaml

Also, consider opening a new issue as to not pollute this one that's about docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants