@@ -2,7 +2,6 @@ package mill.api
22
33import mill .api .DummyOutputStream
44import mill .api .daemon .internal .PathRefApi
5- import mill .constants .PathVars
65import upickle .ReadWriter as RW
76
87import java .nio .file as jnio
@@ -14,9 +13,9 @@ import scala.util.DynamicVariable
1413import scala .util .hashing .MurmurHash3
1514
1615/**
17- * A wrapper around `os.Path` that calculates it's hashcode based
18- * on the contents of the filesystem underneath it. Used to ensure filesystem
19- * changes can bust caches which are keyed off hashcodes.
16+ * A wrapper around `os.Path` that calculates a `sig` (which ends up in the [[ hashCode ]])
17+ * based on the contents of the filesystem underneath it.
18+ * Used to ensure filesystem changes can bust caches which are keyed off hashcodes.
2019 */
2120case class PathRef private [mill] (
2221 path : os.Path ,
@@ -26,11 +25,15 @@ case class PathRef private[mill] (
2625) extends PathRefApi {
2726 private [mill] def javaPath = path.toNIO
2827
29- private [mill] val mappedPath : String = PathRef .encodeKnownRootsInPath(path)
28+ /**
29+ * The path with common mapped path roots replaced, to make it relocatable.
30+ * See [[MappedRoots ]].
31+ */
32+ private val mappedPath : String = MappedRoots .encodeKnownRootsInPath(path)
3033
3134 /**
3235 * Apply the current contextual path mapping to this PathRef.
33- * Updates [[mappedPath ]] but does not recalculate the sig` .
36+ * Updates [[mappedPath ]] but does not recalculate the [[ sig ]] .
3437 */
3538 def remap : PathRef = PathRef (path, quick, sig, revalidate)
3639
@@ -216,88 +219,18 @@ object PathRef {
216219 }
217220 }
218221
219- private [api] type MappedRoots = Seq [(key : String , path : os.Path )]
220-
221- object mappedRoots {
222- private [PathRef ] val rootMapping : DynamicVariable [MappedRoots ] = DynamicVariable (Seq ())
223-
224- def get : MappedRoots = rootMapping.value
225-
226- def toMap : Map [String , os.Path ] = get.map(m => (m.key, m.path)).toMap
227-
228- def withMillDefaults [T ](
229- outPath : os.Path ,
230- workspacePath : os.Path = BuildCtx .workspaceRoot,
231- homePath : os.Path = os.home
232- )(thunk : => T ): T = withMapping(
233- Seq (
234- (" MILL_OUT" , outPath),
235- (" WORKSPACE" , workspacePath),
236- // TODO: add coursier here
237- (" HOME" , homePath)
238- )
239- )(thunk)
240-
241- def withMapping [T ](mapping : MappedRoots )(thunk : => T ): T = withMapping(_ => mapping)(thunk)
242-
243- def withMapping [T ](mapping : MappedRoots => MappedRoots )(thunk : => T ): T = {
244- val newMapping = mapping(rootMapping.value)
245- var seenKeys = Set [String ]()
246- var seenPaths = Set [os.Path ]()
247- newMapping.foreach { case m =>
248- require(! m.key.startsWith(" $" ), " Key must not start with a `$`." )
249- require(m.key != PathVars .ROOT , s " Invalid key, ' ${PathVars .ROOT }' is a reserved key name. " )
250- require(
251- ! seenKeys.contains(m.key),
252- s " Key must be unique, but ' ${m.key}' was given multiple times. "
253- )
254- require(
255- ! seenPaths.contains(m.path),
256- s " Paths must be unique, but ' ${m.path}' was given multiple times. "
257- )
258- seenKeys += m.key
259- seenPaths += m.path
260- }
261- rootMapping.withValue(newMapping)(thunk)
262- }
263- }
264-
265- private [api] def encodeKnownRootsInPath (p : os.Path ): String = {
266- // TODO: Do we need to check for '$' and mask it ?
267- mappedRoots.get.collectFirst {
268- case rep if p.startsWith(rep.path) =>
269- s " $$ ${rep.key}${
270- if (p != rep.path) {
271- s " / ${p.subRelativeTo(rep.path).toString()}"
272- } else " "
273- }"
274- }.getOrElse(p.toString)
275- }
276-
277- private [api] def decodeKnownRootsInPath (encoded : String ): String = {
278- if (encoded.startsWith(" $" )) {
279- val offset = 1 // "$".length
280- mappedRoots.get.collectFirst {
281- case mapping if encoded.startsWith(mapping.key, offset) =>
282- s " ${mapping.path.toString}${encoded.substring(mapping.key.length + offset)}"
283- }.getOrElse(encoded)
284- } else {
285- encoded
286- }
287- }
288-
289222 /**
290223 * Default JSON formatter for [[PathRef ]].
291224 */
292225 implicit def jsonFormatter : RW [PathRef ] = upickle.readwriter[String ].bimap[PathRef ](
293226 p => {
294227 storeSerializedPaths(p)
295- p.toStringPrefix + encodeKnownRootsInPath(p.path)
228+ p.toStringPrefix + MappedRoots . encodeKnownRootsInPath(p.path)
296229 },
297230 {
298231 case s " $prefix: $valid0: $hex: $pathVal" if prefix == " ref" || prefix == " qref" =>
299232
300- val path = os.Path (decodeKnownRootsInPath(pathVal))
233+ val path = os.Path (MappedRoots . decodeKnownRootsInPath(pathVal))
301234 val quick = prefix match {
302235 case " qref" => true
303236 case " ref" => false
@@ -316,7 +249,7 @@ object PathRef {
316249 pr
317250 case s =>
318251 mill.api.BuildCtx .withFilesystemCheckerDisabled(
319- PathRef (os.Path (decodeKnownRootsInPath(s), currentOverrideModulePath.value))
252+ PathRef (os.Path (MappedRoots . decodeKnownRootsInPath(s), currentOverrideModulePath.value))
320253 )
321254 }
322255 )
0 commit comments