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

Gradle plugin initializes the output directory too eagerly #556

Closed
netvl opened this issue Jan 3, 2020 · 5 comments
Closed

Gradle plugin initializes the output directory too eagerly #556

netvl opened this issue Jan 3, 2020 · 5 comments
Labels
Milestone

Comments

@netvl
Copy link

netvl commented Jan 3, 2020

Describe the bug

Any changes of the Project.outputDir property by another plugin (loaded after the Dokka plugin) or by my own build configuration are not reflected in the default dokka task configuration, resulting in pollution of the project work tree.

Expected behaviour

If I change the output directory for my build, the dokka task should output its results there.

To Reproduce

  1. Add the Dokka build plugin to any Gradle/Kotlin project.
  2. Write something like project.buildDir = "$projectDir/output" after application of the Dokka plugin.
  3. Run ./gradlew dokka and observe that the output is produced not to $projectDir/output but to $projectDir/build, which is the default build directory in Gradle.

Dokka configuration

Dokka configuration does not matter, and this can be reproduced without any configuration.

Installation

  • Operating system: macOS
  • Build tool: Gradle v5.6.4
  • Dokka version: 0.10.0

Additional context

At the moment, the output directory of the dokka task is initialized by directly assigning a String property to a value derived from project.buildDir within the plugin application code. This interacts poorly with build setups where the build directory differs from the default one: if I have a plugin which is applied after Dokka and which modifies the build directory, then the dokka task will still output to the default directory, polluting the project work tree. Same if I modify the build directory in my script - the most important thing is that this modification happens after the Dokka plugin application.

I believe that the proper solution here is to rely on the lazy configuration mechanisms in Gradle, and e.g. change the DokkaTask.outputDirectory type to DirectoryProperty, with the default value derived from project.layout.buildDirectory.

@netvl netvl added the bug label Jan 3, 2020
@kamildoleglo kamildoleglo added this to the 0.11.0 milestone Feb 10, 2020
@kamildoleglo
Copy link
Contributor

I believe that 1.4.10 migrated to Gradle properties, which should fix this issue

@netvl
Copy link
Author

netvl commented Apr 1, 2021

@kamildoleglo I have yet to test it, but looking at the implementation, this does not seem to be the case.

In AbstractDokkaTask, the output directory's convention is set directly to the result of the the defaultDokkaOutputDirectory() function:

val outputDirectory: Property<File> = project.objects.safeProperty<File>()
.safeConvention(defaultDokkaOutputDirectory())

which is defined to return a simple File value:

internal fun Task.defaultDokkaOutputDirectory(): File {
return defaultDokkaOutputDirectory(project.buildDir, name)
}
internal fun defaultDokkaOutputDirectory(buildDir: File, taskName: String): File {
val formatClassifier = taskName.removePrefix("dokka").decapitalize()
return File(buildDir, "dokka${File.separator}$formatClassifier")
}

Ergo, at the point when the task is configured, the value of this property will be set to the value of buildDir at the point when task configuration is invoked. Sure, since the plugin uses lazy task instantiation rather than direct configuration, this may happen after the buildDir is overridden, but there is no hard guarantee.

Instead, defaultDokkaOutputDirectory() should return a Provider<File> or something like it, derived from project.layout.buildDirectory property. This will ensure that the build directory will be resolved to the correct value at the point where the value of the outputDirectory property is used, which would happen at the task execution time.

@kamildoleglo
Copy link
Contributor

convention() method returns a Property<> though. Provider<File> is read-only AFAIK so it won't do.
I'm fairly confident this will work as expected, Gradle properties are lazily evaluated, so at any point in the configuration phase you can set a value, regardless of the one set via convention

@netvl
Copy link
Author

netvl commented May 16, 2021

@kamildoleglo it does not matter what the convention() method returns, matters what is passed to it instead, and when convention() is called. In the current implementation, the value passed to it is computed at the same time it is called, that is, when the extension object is created. This means that project.buildDir value used for its computation may not be up to date.

Compare:

val property1 = objects.property<File>()
  .convention(project.buildDir)

val property2 = objects.property<File>()
  .convention(objects.provider { project.buildDir })

the first case is what essentially implemented now. The second is what I essentially proposed. The second variant handles changes to buildDir regardless of when it is changed; the first one will only set the correct convention value if the order of the plugins application is correct (dokka plugin is applied last).

Also, the fact that the user can override the convention value is kind of irrelevant, because my point is that the convention value itself is not entirely correct)

Note that you can pass a provider into the convention() method; that’s what I suggested, not replacing Property with Provider, of course)

@netvl
Copy link
Author

netvl commented May 16, 2021

So the idea is to make defaultDokkaOutputDirectory() return a Provider <File> and pass it to the convention() method.

btw, you might consider using RegularFileProperty instead of Property<File>, I believe it is recommended instead of the generic property.

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

No branches or pull requests

3 participants