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 packagePrefix to SourceItem #109
Add packagePrefix to SourceItem #109
Conversation
abb6647
to
34347af
Compare
Thanks, looks good! Can you also add it to the specification and amend the generators? |
I added the comment in specification.md, also updated the generators. Would you be able to release this so I can proceed with other PRs? |
Thanks for the contribution! I don't fully understand the motivation of this change.
Why is the source set directory I think we should keep the fields in |
@jvican Thanks for looking at this! This is due to pants model, that we can put BUILD files in any package to customize the build (e.g. dependencies). For example we can have following files: src/main/bsp/BUILD Generally, if there is a build file on some level, the parent directory is mapped to a module and to a source root of this module. For such inner modules, that have mismatch of package structure and source root, the package prefix is the way to say how it should be interpreted. |
Thanks for the detailed response.
I think adding this information to the build target (scala and java build targets) instead of every source item is what makes the most sense. Then, build tools such as pants and bazel can export the right package prefix based on the source roots of the build target. |
I'm not sure. Wouldn't the prefix depend on the individual source root? Given that we can have sources in arbitrary places for any target. But also, I realized it shouldn't really be part of |
If I've understood correctly, a package only has one individual source root so this should be fine. |
A package may have multiple source roots. Perhaps this is not relevant to this use case, but we should consider it. |
Indeed, we can have individual files with different package prefix in the same directory with pants. So to respect the model, it should be at the level of SourceItem, perhaps handled with For now I am amending PRs with the version where I put this into ScalaBuildTarget. If we should go with SourceItem and it is acceptable to make it extensible in the way I mentioned, let me know I will update again. |
9acc525
to
c02662d
Compare
I would like to keep the source item abstraction as simple as possible and would like to avoid adding repeated, language-specific information to it that bloats up the abstraction, so I prefer adding this information to the scala build target. The case where a target has multiple source roots can be implemented by adding a list of source roots to a target and then having the tool consuming the information mapping every source to a source root based on the prefix. This is what makes the most sense to me. Most of the time, a build target only has one source root but when it does have more the tool consuming this information should be in charge of doing the work of mapping sources and source roots. |
Ok, cool! In that case, do you think we can proceed with merging these and releasing bsp so I can go further with the remaining 3 PRs? |
I agree, this idea sounds very practical. Can you sketch how this would look? a kind of mapping |
I agree with previous comments that it's undesirable to put this new field under Would it make sense to update export interface SourcesItem {
target: BuildTargetIdentifer;
/** The text documents or and directories that belong to this build target. */
sources: SourceItem[];
+ /** The root directories from where source files should be relativized.
+ *
+ * Example: ["file://Users/name/dev/metals/src/main/scala"]
+ */
+ roots?: Uri[];
} The contract would be that when relativizing a source file, the first root who owns that file would be used as a parent. The BSP spec currently doesn't talk about "packages", only URIs. It would be the job of a client like IntelliJ to infer the package name by relativizing a given source item to the root URI. |
I took a stab at implementing this change in Metals and the following logic seems to be a sufficient approximation for how Pants detects "source roots" def approximateSourceRoot(dir: Path): Option[Path] = {
val pattern = FileSystems.getDefault.getPathMatcher(
"glob:**/{main,test,tests,src,3rdparty,3rd_party,thirdparty,third_party}/{resources,scala,java,jvm,proto,python,protobuf,py}"
)
def loop(d: Path): Option[Path] = {
if (pattern.matches(d)) Some(d)
else {
Option(d.getParent()) match {
case Some(parent) => loop(parent)
case None => None
}
}
}
loop(dir)
}
approximateSourceRoot(
Paths.get("foobar/src/main/scala/com/foobar/").toAbsolutePath()
)
res0: Option[Path] = Some(/Users/lgeirsson/dev/metals/foobar/src/main/scala) This method attempts to reproduce the Python logic here Down the road, this method should not be necessary once this issue pantsbuild/pants#9266 is fixed in upstream Pants. |
Yes, I like this solution even better. |
I agree, I like this solution most so far |
c02662d
to
e75ba0a
Compare
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.
LGTM 👍 Thank you @lukaszwawrzyk for updating the PR
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.
Perfect 👌 Thanks for the contribution @lukaszwawrzyk
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.
Great, thanks for the update!
I'll work on getting a release out now |
A source set in Intellij has a property called packagePrefix so that if the source root is not located at root of package namespace it is know which package it belongs to.
For example:
for file
src/test/Test.scala
with contentIf the source set directory is
/src/test
, we should set package prefix totest
, otherwise Intellij would think thattest.Test
class is actually_root_.Test
.Related PRs for integration:
scalacenter/bloop#1183
scalameta/metals#1470
JetBrains/intellij-scala#503