-
Notifications
You must be signed in to change notification settings - Fork 41
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
compileScala failed to get from cache due to compilePlayRoutes Task #109
Comments
I added the following snippet to my build.gradle to remove the comments from the generated route files that contain absolute paths and date stamps: compilePlayRoutes {
doLast {
fileTree("${buildDir}/src/play/routes").each { file ->
file.text = file.text.replaceAll("(?m)^// @(SOURCE|DATE):.*", "")
}
}
} With that work around in place caching works as expected. |
This should get fixed with Play 2.8.8: |
Is there any chance we could get an option to disable the absolute paths and date stamps generation from older versions? Something that could post-process the generated code to remove those lines built into the plugin by default. |
I can confirm that the generated This leads to a build cache miss when the project is built from 2 different locations. The relativization attempt assumes that the current working directory is the project directory which is not the case when using the Worker API ( I see 2 different options:
Both options have cons as I would prefer the Play compiler to remain build tool agnostic on one hand and post-processing files is far from being ideal on the other hand. Any thoughts @big-guy ? |
@jprinet post processing looks like the only way to me. AFAICT, those comments aren't meaningful? Like mentioned above, before Play 2.7, there was also a datestamp. I think we could put the post-processing in https://github.com/gradle/playframework/blob/master/src/main/java/org/gradle/playframework/tools/internal/routes/RoutesCompiler.java#L20 |
Sounds good 👍 |
In our internal fork we've been using the following code // Remove generation date, keep the source relative
try (Stream<Path> stream = Files.find(spec.getDestinationDir().toPath(), Integer.MAX_VALUE, (filePath, fileAttr) -> fileAttr.isRegularFile())) {
String sourceRegex = getSourceRegex(spec.getSourcesRoot());
stream.forEach(path -> {
try {
String source = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
// Upstream patches
// https://github.com/playframework/playframework/pull/10707
// https://github.com/playframework/twirl/pull/378
// the routes fix was back-ported to 2.8.x
// todo: run this on only on 2.7.x and below
// Fix from
// https://github.com/gradle/playframework/issues/109#issuecomment-594502896
source = source.replaceAll(sourceRegex, "");
source = source.replaceAll("(?m)^// @(DATE):.*", "");
Files.write(path, source.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
} catch (IOException e) {
throw new RuntimeException("Error invoking the Play routes compiler.", e);
} catch (UncheckedIOException e) {
throw new RuntimeException("Error invoking the Play routes compiler.", e.getCause());
} in the RoutesCompiler class as @big-guy mentioned above. // helper method
private static String getSourceRegex(File sourceRoot) {
String sourceRegex = sourceRoot.getAbsolutePath();
if (!sourceRegex.endsWith("/")) {
sourceRegex = sourceRegex + "/";
}
return sourceRegex;
} I can clean this up and throw it into a PR if you'd like. |
Which Play version are you guys using? |
Thanks, @Sineaggi for offering your help, this would definitely be appreciated. A couple of comments on your snippet:
@mkurz I was able to reproduce in OpenTelemetry build which is using 2.8.19 |
@jprinet wrt |
Yes, path relativization would definitely be better 👍 |
I do not understand why this is not working in Play 2.8.19. There should not be any date anymore and also the path should be relative. If the path is absolute then this is a bug in Play.
|
The |
So I checked again, once using sbt and once using gradle. Regarding
That is because of this line: new File(".").toURI.relativize(task.file.toURI).getPath.replace(File.separator, "/"), Assuming the project is located in But:
That is why when using gradle The However, the best solution probably is to also "relativize" the path instead of removing the line completly. Also, if you need help from Play side, what I can offer is that you pass the current project's folder via an Java property (e.g. new File(sys.props.get("gradle.play.project.home").getOrElse(".")).toURI.relativize(task.file.toURI).getPath.replace(File.separator, "/"), This way the only patch you need is basically just one line, like settings the java property around here and here just before you call the compile methods. this is how I tested (click to expand)$ sbt new playframework/play-scala-seed.g8
...
// using default values
...
Template applied in ./play-scala-seed
$ cd play-scala-seed
./play-scala-seed$ sbt compile
...
[info] compiling 7 Scala sources and 1 Java source to ./play-scala-seed/target/scala-2.13/classes ...
[success] Total time: 4 s, completed Mar 24, 2023, 9:37:29 PM
./play-scala-seed$ vim build.gradle # Adding the gradle build
./play-scala-seed$ gradle compilePlayRoutes
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
See https://docs.gradle.org/8.0.2/userguide/command_line_interface.html#sec:command_line_warnings
BUILD SUCCESSFUL in 855ms
1 actionable task: 1 executed
# Now you can diff the two folders ./target/scala-2.13/routes/main/ ./build/src/play/routes/
./play-scala-seed$ kompare ./target/scala-2.13/routes/main/ ./build/src/play/routes/
./play-scala-seed$ meld ./target/scala-2.13/routes/main/ ./build/src/play/routes/ And this is what my $ cat build.gradle
plugins {
id 'org.gradle.playframework' version '0.13'
}
repositories {
mavenCentral()
maven {
name "lightbend-maven-release"
url "https://repo.lightbend.com/lightbend/maven-releases"
}
ivy {
name "lightbend-ivy-release"
url "https://repo.lightbend.com/lightbend/ivy-releases"
layout "ivy"
}
}
play {
platform {
playVersion = '2.8.19'
scalaVersion = '2.13'
javaVersion = JavaVersion.VERSION_1_8
}
} |
Would it make sense to have the convention configured to true by default if the playVersion is below 2.8? |
@Sineaggi ..below 2.8.8... |
Similar to the existing code platform.getPlayVersion().map(playVersion -> !PlayMajorVersion.forPlayVersion(playVersion).hasSupportForStaticRoutesGenerator() maybe something like stripRoutesComments.convention(
platform.getPlayVersion().map(playVersion -> VersionNumber.parse(playVersion).compareTo(VersionNumber.parse("2.8.8")) >= 0);
); |
@mkurz Having this relativization fixed in the Play framework would certainly be better than post-processing files. The fix wouldn't be available to already released versions, but I don't see this as critical. Adding a system property would have some impact on caching as it can be part of the cache key. What about an additional optional parameter to the routes compiler? If we decide to go for a post-processing approach, and as this is not a critical fix, I would still make it an opt-in rather than having it true below 2.8.8 @Sineaggi. |
This is all internal between the Gradle task and the Play code, so caching wouldn't be impacted by this. We can set system properties or call new constructor for RoutesCompilerTask. We'd create a new RoutesCompilerAdapter that would only kick in for versions of Play that support the new constructor.
We shouldn't make this opt-in because it's just a foot gun. I don't think it's going to matter if it's removed because we don't do the remapping like @mkurz mentions AFAIK. If we want to be closer to the 2.8.8+ behavior, we could rewrite the line instead of removing it. This is also what mkurz suggested. We know the file path and could know the path to make it relative to. |
Sounds good, let's opt for the post-processing approach, it has the benefit of addressing all framework versions and being self-contained in the plugin. I'll adjust the |
So nothing you need from Play side. Have a nice day 😉 |
When I tested the new playFramework, I found the compileScala didn't work as expect. The following is what I did and what I found:
I found this issue might be related to compilePlayRoutes task after I analyzed the code. The is the code from PlayApplicationPlugin.java
mainScalaSourceDirectorySet.srcDir(getRoutesCompileTask(project).flatMap(task -> task.getOutputDirectory()));
The output of compilePlayRoutes is added to the scala source set. I assume the compilePlayRoutes task will call play's routesCompiler.scala. Link to the code
However play's RoutesCompiler will add source absolute path and timestamp to the generated file (Code). Finally it causes the compileScala re-run
Would you like to investigate ? Feel free to point it out if I am wrong.
The text was updated successfully, but these errors were encountered: