-
-
Notifications
You must be signed in to change notification settings - Fork 390
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
Add a sourceGenerators
task to help out IDE config generation
#4621
Conversation
@Baccata one new development worth mentioning is that #4524 targeting 0.13.x, we've moved the computation of Following the naming convention would just define a |
@lihaoyi, with the difference that the case class SourceGenerator(task: T[Unit], sourceRoots: Seq[os.SubPath])
trait JavaModule {
def sourceGenerators : Seq[SourceGenerator]
} But, putting aside the details, I agree that source generators are better captured statically like the |
val dest = mill | ||
.eval | ||
.EvaluatorPaths | ||
.resolveDestPaths(workspace / "out", task) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't know whether there's a better way to do it, to be honest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is fine. A bit verbose but that's the best we got
/** | ||
* The folders containing all source files fed into the compiler | ||
*/ | ||
def allSources: T[Seq[PathRef]] = Task { sources() ++ generatedSources() } | ||
def allSources: T[Seq[PathRef]] = | ||
Task { sources() ++ generatedSources() ++ deferredGeneratedSources() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeps the current (0.12.x) behaviour of generatedSources
to avoid breaking the ecosystem
@@ -133,14 +137,19 @@ class BloopImpl(evs: () => Seq[Evaluator], wd: os.Path) extends ExternalModule { | |||
!module.asInstanceOf[outer.Module].skipBloop | |||
else true | |||
|
|||
private def deferredAllSources(m: JavaModule): T[Seq[PathRef]] = Task { | |||
m.sources() ++ m.generatedSources() ++ m.allDeferredSourceRoots() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeps the current (0.12.x) behaviour of generatedSources
being run to produce IDE config, in order to avoid breaking the ecosystem. In addition, adds roots that will be produced by deferredSourceGenerators
when allSources
/compile
is run.
See later changes for a showcase of what I meant in #4621 (comment) ... the names are horribly bad but will change them later |
@@ -234,12 +234,14 @@ private class MillBuildServer( | |||
case module: MillBuildRootModule => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why this warrants a specific case, considering it extends JavaModule anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be some left over from a time, where MillBuildRootModule
was either not a JavaModule
or needed different treatment. If both cases are identical now, we can merge them.
@lihaoyi, @lefou, I think this PR is just about ready, but I've got a failing integration test on my fork that I have no idea how to troubleshoot. Any chance you could provide guidance ? |
sourceGenerators
task to help out IDE config generation
@Baccata can you try reproducing the failure locally? You can run |
Yes, it reproduces locally. Still extremely puzzled as to what's wrong though. |
I'm also able to reproduce on the 0.12.x branch, so I presume it's nothing to do with this particular changeset. |
Oh I just realized this was targeting 0.12.x. Maybe its fixed by #4625 ? |
Okay I think this is ready. There's some android-specific job that keeps failing, but it seems to be failing on other PRs raised against 0.12.x, so I presume it's unrelated. |
Should I close this PR and re-open it anew to remove the noise of the previous conversations ? |
No leaving the PR as is is fine, I'll take a look when I have time |
* Computes the list of source roots that will be produced by [[sourceGenerators]] without | ||
* actually running the generators in question. | ||
*/ | ||
def predictedGeneratedSourceRoots: T[Seq[PathRef]] = T { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The terminology is kind of weird here, as are the types. How about
def deferredGeneratedSourcePaths: T[Seq[os.Path]]
I don't like predicted
, since it sounds like it could refer to all generated sources, which it doesn't. The earlier term deferred
is a bit better since it sounds more like it is a separate thing from the other generated sources.
If it's just returning the paths, we can just return os.Path
s rather than PathRef
s
Well my personal opinion is really that the current Therefore, I would rather the Now that being said, that's just a personal opinion. If yourself and Haoyi make an executive decision to make this a mix-in, I'll abide and will amend the contribution in consequence. |
For now lets go with a separate trait. I think it's still a bit early to deprecate the existing workflow and tell people to use the new one. We probably want someone using it for a while and happy with it before we deprecate the old way, which would probably put it some time after the 0.13.0 release |
@lihaoyi : just to be clear : you want a separate trait that EDIT : and yeah, I agree that it's premature to deprecate at this point |
I don't have a strong opinion between those two options. @lefou do you have a preference? |
TBH, I find the new proposed solution (although being a solution to some immediate issue) ugly and complicated. (I also don't think the current Therefore I tend to not force it on all users of |
mixin sounds good to me |
I agree I don't like the naming, but don't really want to bikeshed on it, as long as the maintainers are happy with it.
I think that's a mis-interpretation of the problem. To simplify it as intuitively as possible :
Saying that you don't think the current
Happy to abide 👌 |
Extracted as another trait in 2d54b8f |
My answer is of course "yes". I do think our IDE integration should not fail, if some source generators don't work. We want see some warnings, of course. Also, compilation most likely won't work, even if the IDE bypasses the build tool to compile things, but that not the question here. I think we need to solve the issue in the IDE integration, not in the task signature. If IDE integration just deals with a failed source generator and continues with either a stub-path or without the path of the generated sources at all (depends on how we fail or how we are able to recover). Once we repaired the source generator, we re-import and the missing generated sources should appear in the IDE. I don't see where in that picture a different task signature for |
The basic problem this PR is trying to solve is that currently, as I understand it, is that Mill does not provide the path to generated sources if generation fails: you only get a This PR doesn't change the idea of immutable/cacheable/reproducible results, all it does is let you list out which tasks will contain generated sources, and at what paths, without needing to actually run them. That is what allows the IDE to have paths it can use even if the tasks themselves fail |
Might be there is an unspoken assumption: We don't want to re-import/refresh the project in the IDE after we fixed source generation? Which means, all source paths need to stay stable. This is equivalent with what we modelled in |
I don't want to hold this PR any longer with discussions. The current solution as dedicated trait is isolated enough that it can be replaced with some later concept, once we have it. I think we need to sit another round on the design table and find out, how a nice solution could look like. I think #1779 might be a part of the solution. Just one last though. Have you considered to explicitly encode the fallback into the task result, e.g. def instableGeneratedSources: Task[Either[Seq[os.Path], Seq[PathRef]]] It's appealing as it is much less complex as a concept. Don't know, if it is enough to represent the problem? |
I think the issue with |
Do we make sure, the real implementation is returning the same |
The PR doesn't do such checks IIRC. It could, but it doesn't |
Actually that's why I've elected to not require the NamedTasks yield a I could change the interface to have it require |
I'd say for now just tag |
scalalib/src/mill/scalalib/DeferredGeneratedSourcesModule.scala
Outdated
Show resolved
Hide resolved
Module marked @experimental in 3b7b174 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
Thanks @Baccata ! I kicked off a publish run on the |
|
Context : #4530
DeferredGeneratedSourcesModule
that extendsJavaModule
, providing adef deferredGeneratedSourceTasks
alternative togeneratedSources
. This allows BSP/GenIdea/Bloop to predict source roots without actually running the code generation logic.def out
to theCtx
class, allowing to query the locationout
folder within tasks.Previous description (kept for the record) :
@lihaoyi, I want to open this PR to continue the discussion. At the time of writing this, this adds a
generatedSourceRoots
parameter for tasks, as you've described, and uses it to compute the source directories for the bloop configuration, as opposed to actually running theallSources
task. A similar change would need to be achieved inGenIdea
andBSP
.So now, the problem I see is as follows : in order for this to be useful, it needs to be applied to all source generators provided OOTB by the mill codebase, but also third party providers of source-generator (like smithy4s), as the ability to jump to the sources is paramount for the user experience in IDEs.
Applying this change is a fair bit of work in this codebase, and a big ask for the larger ecosystem, and although I think SBT's approach of treating all source generators lazily is preferable to mill's current approach of running all source generators eagerly, I don't think I can weigh the benefits of changing the approach against the cost induced by breaking IDE behaviour for existing plugins.
With that in mind here's what I think would be a good mitigation :
The
Bloop
,GenIdea
andBSP
then get amended to callsources()
,generatedSources()
andlazyGeneratedSourceRoots()
, but avoidsrunLazySourceGenerators
.This approach would allow to alleviate the pain point raised in the discussion above, whilst retaining the current behaviour of the ecosystem. Mill plugin providers could be encouraged to use
runLazySourceGenerators
instead ofgeneratedSources
, but users would have a recourse to turn eager source generators into lazy ones if they need it to be (provided awithGeneratedSourceRoots
is provided to them, that is)