Skip to content

Commit 598aaea

Browse files
authored
Replace import $file syntax with flat package namespacing (#4462)
Fixes #4459 Fixes #3894 With this PR, all `.mill` files in a folder are in the same flat `package` namespace, similar to how normal Scala files work. The previous `import $file` syntax was inherited from Ammonite, and unfortunately never took off across the Scala community. In effect this makes `.mill` files behave almost exactly like `.scala` files, which is part of the longer term goal of removing special handling for `.mill` files. The code generation for the helper files is not changed at all in this PR, rather we just make use of Scala 3's `export` clauses to make them available under the main `build.mill`/`package.mill` file as well There is the caveat that the `package object`s in `.mill` files can be referenced via `build.foo.bar` without the trailing `.package`. Implementing this caveat is the cause of a lot of the hackiness in the codegen, which will hopefully go away once the upstream language feature lands scala/improvement-proposals#100 We leave the codegenned `import _root_.{build_ => $file}` in place so `import $file` will continue to work to ease in the migration, but are no longer the recommended way of referencing helper files
1 parent 23563b4 commit 598aaea

File tree

17 files changed

+50
-103
lines changed

17 files changed

+50
-103
lines changed

Diff for: docs/modules/ROOT/pages/large/multi-file-builds.adoc

-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,5 @@ include::partial$example/large/multi/10-multi-file-builds.adoc[]
99

1010
include::partial$example/large/multi/11-helper-files.adoc[]
1111

12-
== Legacy `.sc` extension
13-
14-
include::partial$example/large/multi/12-helper-files-sc.adoc[]
1512

1613

Diff for: example/large/multi/11-helper-files/build.mill

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
package build
66
import $packages._
77
import mill._, scalalib._
8-
import $file.foo.versions
9-
import $file.util.MyModule
8+
import foo.versions
109

1110
object `package` extends RootModule with MyModule {
1211
def forkEnv = Map(

Diff for: example/large/multi/11-helper-files/foo/package.mill

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package build.foo
22
import mill._, scalalib._
3-
import $file.util
4-
import $file.foo.versions.myProjectVersion
5-
object `package` extends RootModule with build_.util.MyModule {
3+
import versions.myProjectVersion
4+
object `package` extends RootModule with build.MyModule {
65
def forkEnv = Map(
7-
"MY_SCALA_VERSION" -> util.myScalaVersion,
6+
"MY_SCALA_VERSION" -> build.myScalaVersion,
87
"MY_PROJECT_VERSION" -> myProjectVersion
98
)
109
}

Diff for: example/large/multi/13-helper-files-mill-scala/build.mill.scala renamed to example/large/multi/12-helper-files-mill-scala/build.mill.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
package build
22
import $packages._
33
import mill._, scalalib._
4-
import $file.foo.versions
5-
import $file.util.MyModule
64

75
object `package` extends RootModule with MyModule {
86
def forkEnv = Map(
97
"MY_SCALA_VERSION" -> build.scalaVersion(),
10-
"MY_PROJECT_VERSION" -> versions.myProjectVersion
8+
"MY_PROJECT_VERSION" -> build.foo.myProjectVersion
119
)
1210
}
1311
///** See Also: util.mill.scala */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package build.foo
2+
import mill._, scalalib._
3+
object `package` extends RootModule with build.MyModule {
4+
def forkEnv = Map(
5+
"MY_SCALA_VERSION" -> build.myScalaVersion,
6+
"MY_PROJECT_VERSION" -> myProjectVersion
7+
)
8+
}

Diff for: example/large/multi/12-helper-files-sc/build.sc

-35
This file was deleted.

Diff for: example/large/multi/12-helper-files-sc/foo/package.sc

-9
This file was deleted.

Diff for: example/large/multi/12-helper-files-sc/foo/versions.sc

-1
This file was deleted.

Diff for: example/large/multi/12-helper-files-sc/util.sc

-7
This file was deleted.

Diff for: example/large/multi/13-helper-files-mill-scala/foo/package.mill.scala

-10
This file was deleted.

Diff for: example/large/multi/13-helper-files-mill-scala/foo/src/Foo.scala

-8
This file was deleted.

Diff for: example/large/multi/13-helper-files-mill-scala/src/Main.scala

-6
This file was deleted.

Diff for: runner/src/mill/runner/CodeGen.scala

+37-15
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ object CodeGen {
5151
}
5252
.distinct
5353

54-
val pkg = packageSegments.drop(1).dropRight(1)
54+
val pkgSegments = packageSegments.drop(1).dropRight(1)
5555

5656
def pkgSelector0(pre: Option[String], s: Option[String]) =
57-
(pre ++ pkg ++ s).map(backtickWrap).mkString(".")
57+
(pre ++ pkgSegments ++ s).map(backtickWrap).mkString(".")
5858
def pkgSelector2(s: Option[String]) = s"_root_.${pkgSelector0(Some(globalPackagePrefix), s)}"
5959
val (childSels, childAliases0) = childNames
6060
.map { c =>
@@ -67,7 +67,7 @@ object CodeGen {
6767
}.unzip
6868
val childAliases = childAliases0.mkString("\n")
6969

70-
val pkgLine = s"package ${pkgSelector0(Some(globalPackagePrefix), None)}"
70+
val pkg = pkgSelector0(Some(globalPackagePrefix), None)
7171

7272
val aliasImports = Seq(
7373
// `$file` as an alias for `build_` to make usage of `import $file` when importing
@@ -87,7 +87,7 @@ object CodeGen {
8787

8888
val parts =
8989
if (!isBuildScript) {
90-
s"""$pkgLine
90+
s"""package $pkg
9191
|$aliasImports
9292
|object ${backtickWrap(scriptPath.last.split('.').head)} {
9393
|$markerComment
@@ -103,11 +103,16 @@ object CodeGen {
103103
scriptPath,
104104
scriptFolderPath,
105105
childAliases,
106-
pkgLine,
106+
pkg,
107107
aliasImports,
108108
scriptCode,
109109
markerComment,
110-
parser
110+
parser,
111+
scriptSources
112+
.map(_.path)
113+
.filter(_ != scriptPath)
114+
.filter(p => (p / os.up) == (scriptPath / os.up))
115+
.map(_.last.split('.').head)
111116
)
112117
}
113118

@@ -124,19 +129,25 @@ object CodeGen {
124129
scriptPath: os.Path,
125130
scriptFolderPath: os.Path,
126131
childAliases: String,
127-
pkgLine: String,
132+
pkg: String,
128133
aliasImports: String,
129134
scriptCode: String,
130135
markerComment: String,
131-
parser: MillScalaParser
136+
parser: MillScalaParser,
137+
siblingScripts: Seq[String]
132138
) = {
133139
val segments = scriptFolderPath.relativeTo(projectRoot).segments
134140

135-
val prelude = {
141+
val exportSiblingScripts =
142+
siblingScripts.map(s => s"export $pkg.${backtickWrap(s)}.*").mkString("\n")
143+
144+
val importSiblingScripts = siblingScripts
145+
.map(s => s"import $pkg.${backtickWrap(s)}.*").mkString("\n")
146+
147+
val prelude =
136148
s"""import MillMiscInfo._
137149
|import _root_.mill.main.TokenReaders.given, _root_.mill.api.JsonFormatters.given
138150
|""".stripMargin
139-
}
140151

141152
val miscInfo =
142153
if (segments.nonEmpty) subfolderMiscInfo(scriptFolderPath, segments)
@@ -196,23 +207,32 @@ object CodeGen {
196207
newScriptCode = objectData.name.applyTo(newScriptCode, wrapperObjectName)
197208
newScriptCode = objectData.obj.applyTo(newScriptCode, "abstract class")
198209

199-
s"""$pkgLine
210+
s"""package $pkg
200211
|$miscInfo
201212
|$aliasImports
213+
|$importSiblingScripts
202214
|$prelude
203215
|$markerComment
204216
|$newScriptCode
205217
|object $wrapperObjectName extends $wrapperObjectName {
206218
| ${childAliases.linesWithSeparators.mkString(" ")}
219+
| $exportSiblingScripts
207220
| ${millDiscover(segments.nonEmpty)}
208221
|}""".stripMargin
209222

210223
case None =>
211-
s"""$pkgLine
224+
s"""package $pkg
212225
|$miscInfo
213226
|$aliasImports
227+
|$importSiblingScripts
214228
|$prelude
215-
|${topBuildHeader(segments, scriptFolderPath, millTopLevelProjectRoot, childAliases)}
229+
|${topBuildHeader(
230+
segments,
231+
scriptFolderPath,
232+
millTopLevelProjectRoot,
233+
childAliases,
234+
exportSiblingScripts
235+
)}
216236
|$markerComment
217237
|$scriptCode
218238
|}""".stripMargin
@@ -263,7 +283,8 @@ object CodeGen {
263283
segments: Seq[String],
264284
scriptFolderPath: os.Path,
265285
millTopLevelProjectRoot: os.Path,
266-
childAliases: String
286+
childAliases: String,
287+
exportSiblingScripts: String
267288
): String = {
268289
val extendsClause =
269290
if (segments.nonEmpty) s"extends _root_.mill.main.SubfolderModule "
@@ -277,8 +298,9 @@ object CodeGen {
277298
// path dependent types no longer match, e.g. for TokenReaders of custom types.
278299
// perhaps we can patch mainargs to substitute prefixes when summoning TokenReaders?
279300
// or, add an optional parameter to Discover.apply to substitute the outer class?
280-
s"""object ${wrapperObjectName} extends $wrapperObjectName {
301+
s"""object ${wrapperObjectName} extends $wrapperObjectName {
281302
| ${childAliases.linesWithSeparators.mkString(" ")}
303+
| $exportSiblingScripts
282304
| ${millDiscover(segments.nonEmpty)}
283305
|}
284306
|abstract class $wrapperObjectName $extendsClause { this: $wrapperObjectName.type =>

0 commit comments

Comments
 (0)