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

Mill support: enable importing projects which contain build.mill(.scala) but not wrapper script #674

Open
wants to merge 4 commits into
base: idea243.x
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class MillProjectInstaller extends BspProjectInstallProvider {

override def canImport(workspace: File): Boolean =
Option(workspace) match {
case Some(directory) if directory.isDirectory => isBspCompatible(directory) || isLegacyBspCompatible(directory)
case Some(directory) if directory.isDirectory => isBspCompatible(directory) || isLegacyBspCompatible(directory) || BspUtil.findFileByName(directory, "build.mill").isDefined || BspUtil.findFileByName(directory, "build.mill.scala").isDefined || BspUtil.findFileByName(directory, "build.sc").isDefined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. The line with the condition is too long and could be better formatted (every || condition on a new line)

  2. Given that just on a single line the same patter is repeated 3 times: BspUtil.findFileByName(directory, fileName).isDefined it's worth extracting into a method.
    I looked into the implementation of findFileByName and it calls listFiles every time.
    So it's worth having another method, something like def directoryContainsFile(directory: Path, fileNames: Seq[String]): Boolean that would do one iteration over the directory files.

Copy link
Member

@unkarjedy unkarjedy Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU BspUtil.findFileByName(directory, "build.sc").isDefined checks for the "old mill"?
But we already have isLegacyBspCompatible method, so this line isn't needed, is it?
AFAIU isLegacyBspCompatible also avoids some false positives when a directory has build.sc file which doesn't represent a mill build file by checking for a magic line import $ivy.com.lihaoyi::mill-contrib-bsp:$MILL_VERSION

Copy link

@lefou lefou Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

y checking for a magic line import $ivy.com.lihaoyi::mill-contrib-bsp:$MILL_VERSION``

That line isn't required for BSP to work as intended for many Mill versions.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead, just looking for Mill imports or uses might be a better heuristic.

Finding a .mill-version (or .config/mill-version) file next to build.sc is also strong indicator that you found a Mill project.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, got it.

My main point is that the new code: BspUtil.findFileByName(directory, "build.sc").isDefined
makes the isLegacyBspCompatible method call redundant.
Inside that method there is BspUtil.findFileByName(workspace, "build.sc").exists(<has some magic line>).
So isLegacyBspCompatible || BspUtil.findFileByName(directory, "build.sc").isDefined
is in practice the same as BspUtil.findFileByName(directory, "build.sc").isDefined.

I would remove the new bit and enhance the isLegacyBspCompatible method according to your vision in the comment above.
If the name is not the most appropriate, in your opinion, then feel free to propose a better one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(BTW, thanks for contributing!)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no point in making it even more sophisticated. Once there is a file build.mill (or build.mill.scala), we can be fairly certain that we're dealing with a Mill project. No need to search for .mill-version or anything like that.

Copy link

@lefou lefou Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, the .mill-version lookup was only suggested in case you need to disambiguate the purpose of a detected build.sc, since it is common for various tools: Mill, but also Scala-CLI, Ammonite, workbooks.

case _ => false
}

Expand All @@ -34,7 +34,8 @@ class MillProjectInstaller extends BspProjectInstallProvider {
Success(Seq(file.getAbsolutePath, "-i", "mill.bsp.BSP/install"))
case Some(file) if isLegacyMill =>
Success(Seq(file.getAbsolutePath, "-i", "mill.contrib.BSP/install"))
case _ => Failure(new IllegalStateException("Unable to install BSP as this is not a Mill project"))
case None =>
sideeffffect marked this conversation as resolved.
Show resolved Hide resolved
Success(Seq("mill", "-i", "mill.bsp.BSP/install"))
unkarjedy marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down