@@ -7,6 +7,7 @@ import mill.api.internal.{ResolveChecker, Resolved, RootModule0}
77import mill .api .daemon .Watchable
88import mill .exec .{Execution , PlanImpl }
99import mill .internal .PrefixLogger
10+ import mill .internal .MillPathSerializer
1011import mill .resolve .Resolve
1112import mill .api .internal .ParseArgs
1213
@@ -40,6 +41,17 @@ final class EvaluatorImpl(
4041 new ScriptModuleInit ()
4142 )
4243 override val staticBuildOverrides = execution.staticBuildOverrides
44+ private val millPathSerializer = new MillPathSerializer (MillPathSerializer .defaultMapping(workspace))
45+
46+ MillPathSerializer .setupSymlinks(os.pwd, workspace)
47+
48+ private object SetupSymlinkSpawnHook extends (os.Path => Unit ) {
49+ def apply (p : os.Path ): Unit = MillPathSerializer .setupSymlinks(p, workspace)
50+ override def toString (): String = " SetupSymlinkSpawnHook"
51+ }
52+
53+ private def withPathSerialization [T ](t : => T ): T =
54+ os.Path .pathSerializer.withValue(millPathSerializer)(t)
4355
4456 def workspace = execution.workspace
4557 def baseLogger = execution.baseLogger
@@ -204,10 +216,10 @@ final class EvaluatorImpl(
204216 }
205217 }
206218
207- val filePath = os.Path (module.moduleCtx.fileName).relativeTo(workspace)
208-
219+ val normalizedFileName = module.moduleCtx.fileName.replace('\\ ' , '/' )
209220 val isRootBuildFile =
210- filePath == os.sub / " mill-build/build.mill" || filePath == os.sub / " build.mill.yaml"
221+ normalizedFileName.endsWith(" /mill-build/build.mill" ) ||
222+ normalizedFileName.endsWith(" /build.mill.yaml" )
211223
212224 val millKeys = mill.constants.ConfigConstants .all()
213225 val validKeys =
@@ -291,105 +303,107 @@ final class EvaluatorImpl(
291303 logger : Logger = baseLogger,
292304 serialCommandExec : Boolean = false ,
293305 selectiveExecution : Boolean = false
294- ): Evaluator .Result [T ] = {
295- val selectiveExecutionEnabled = selectiveExecution && ! tasks.exists(_.isExclusiveCommand)
296-
297- val (selectedTasks, selectiveResults, maybeNewMetadata) =
298- if (! selectiveExecutionEnabled) (tasks, Map .empty, None )
299- else {
300- val (named, unnamed) =
301- tasks.partitionMap { case n : Task .Named [? ] => Left (n); case t => Right (t) }
302- val newComputedMetadata = this .selective.computeMetadata(named)
303-
304- val selectiveExecutionStoredData = for {
305- _ <- Option .when(os.exists(outPath / OutFiles .millSelectiveExecution))(())
306- changedTasks <- this .selective.computeChangedTasks0(named, newComputedMetadata)
307- } yield changedTasks
308-
309- selectiveExecutionStoredData match {
310- case None =>
311- // Ran when previous selective execution metadata is not available, which happens the first time you run
312- // selective execution.
313- (tasks, Map .empty, Some (newComputedMetadata.metadata))
314- case Some (changedTasks) =>
315- val selectedSet = changedTasks.downstreamTasks.map(_.ctx.segments.render).toSet
316-
317- (
318- unnamed ++ named.filter(t =>
319- t.isExclusiveCommand || selectedSet(t.ctx.segments.render)
320- ),
321- newComputedMetadata.results,
322- Some (newComputedMetadata.metadata)
323- )
306+ ): Evaluator .Result [T ] = os.ProcessOps .spawnHook.withValue(SetupSymlinkSpawnHook ) {
307+ withPathSerialization {
308+ val selectiveExecutionEnabled = selectiveExecution && ! tasks.exists(_.isExclusiveCommand)
309+
310+ val (selectedTasks, selectiveResults, maybeNewMetadata) =
311+ if (! selectiveExecutionEnabled) (tasks, Map .empty, None )
312+ else {
313+ val (named, unnamed) =
314+ tasks.partitionMap { case n : Task .Named [? ] => Left (n); case t => Right (t) }
315+ val newComputedMetadata = this .selective.computeMetadata(named)
316+
317+ val selectiveExecutionStoredData = for {
318+ _ <- Option .when(os.exists(outPath / OutFiles .millSelectiveExecution))(())
319+ changedTasks <- this .selective.computeChangedTasks0(named, newComputedMetadata)
320+ } yield changedTasks
321+
322+ selectiveExecutionStoredData match {
323+ case None =>
324+ // Ran when previous selective execution metadata is not available, which happens the first time you run
325+ // selective execution.
326+ (tasks, Map .empty, Some (newComputedMetadata.metadata))
327+ case Some (changedTasks) =>
328+ val selectedSet = changedTasks.downstreamTasks.map(_.ctx.segments.render).toSet
329+
330+ (
331+ unnamed ++ named.filter(t =>
332+ t.isExclusiveCommand || selectedSet(t.ctx.segments.render)
333+ ),
334+ newComputedMetadata.results,
335+ Some (newComputedMetadata.metadata)
336+ )
337+ }
324338 }
325- }
326-
327- val evaluated : ExecutionResults = execution.executeTasks(
328- goals = selectedTasks,
329- reporter = reporter,
330- testReporter = testReporter,
331- logger = logger,
332- serialCommandExec = serialCommandExec
333- )
334339
335- val allResults = evaluated.transitiveResults ++ selectiveResults
336-
337- @ scala.annotation.nowarn(" msg=cannot be checked at runtime" )
338- val watched = allResults.collect {
339- case (_ : Task .Sources , ExecResult .Success (Val (ps : Seq [PathRef ]))) =>
340- ps.map(r => Watchable .Path .from(r))
341- case (_ : Task .Source , ExecResult .Success (Val (p : PathRef ))) =>
342- Seq (Watchable .Path .from(p))
343- case (t : Task .Input [_], result) =>
344-
345- val ctx = new mill.api.TaskCtx .Impl (
346- args = Vector (),
347- dest0 = () => null ,
348- log = logger,
349- env = this .execution.env,
350- reporter = reporter,
351- testReporter = testReporter,
352- workspace = workspace,
353- _systemExitWithReason = (reason, exitCode) =>
354- throw Exception (s " systemExit called: reason= $reason, exitCode= $exitCode" ),
355- fork = null ,
356- jobs = execution.effectiveThreadCount,
357- offline = offline,
358- useFileLocks = useFileLocks
359- )
360- val pretty = t.ctx0.fileName + " :" + t.ctx0.lineNum
361- Seq (Watchable .Value (
362- () => t.evaluate(ctx).hashCode(),
363- result.map(_.value).hashCode(),
364- pretty
365- ))
366- }.flatten.toVector
367-
368- for (newMetadata <- maybeNewMetadata) {
369- val failingTaskNames = allResults
370- .collect { case (t : Task .Named [_], r) if r.asSuccess.isEmpty => t.ctx.segments.render }
371- .toSet
340+ val evaluated : ExecutionResults = execution.executeTasks(
341+ goals = selectedTasks,
342+ reporter = reporter,
343+ testReporter = testReporter,
344+ logger = logger,
345+ serialCommandExec = serialCommandExec
346+ )
372347
373- // For tasks that were not successful, force them to re-run next time even
374- // if not changed so the user can see that there are still failures remaining
375- selective.saveMetadata(newMetadata.copy(forceRunTasks = failingTaskNames))
376- }
348+ val allResults = evaluated.transitiveResults ++ selectiveResults
349+
350+ @ scala.annotation.nowarn(" msg=cannot be checked at runtime" )
351+ val watched = allResults.collect {
352+ case (_ : Task .Sources , ExecResult .Success (Val (ps : Seq [PathRef ]))) =>
353+ ps.map(r => Watchable .Path .from(r))
354+ case (_ : Task .Source , ExecResult .Success (Val (p : PathRef ))) =>
355+ Seq (Watchable .Path .from(p))
356+ case (t : Task .Input [_], result) =>
357+
358+ val ctx = new mill.api.TaskCtx .Impl (
359+ args = Vector (),
360+ dest0 = () => null ,
361+ log = logger,
362+ env = this .execution.env,
363+ reporter = reporter,
364+ testReporter = testReporter,
365+ workspace = workspace,
366+ _systemExitWithReason = (reason, exitCode) =>
367+ throw Exception (s " systemExit called: reason= $reason, exitCode= $exitCode" ),
368+ fork = null ,
369+ jobs = execution.effectiveThreadCount,
370+ offline = offline,
371+ useFileLocks = useFileLocks
372+ )
373+ val pretty = t.ctx0.fileName + " :" + t.ctx0.lineNum
374+ Seq (Watchable .Value (
375+ () => t.evaluate(ctx).hashCode(),
376+ result.map(_.value).hashCode(),
377+ pretty
378+ ))
379+ }.flatten.toVector
380+
381+ for (newMetadata <- maybeNewMetadata) {
382+ val failingTaskNames = allResults
383+ .collect { case (t : Task .Named [_], r) if r.asSuccess.isEmpty => t.ctx.segments.render }
384+ .toSet
385+
386+ // For tasks that were not successful, force them to re-run next time even
387+ // if not changed so the user can see that there are still failures remaining
388+ selective.saveMetadata(newMetadata.copy(forceRunTasks = failingTaskNames))
389+ }
377390
378- evaluated.transitiveFailing.size match {
379- case 0 =>
380- Evaluator .Result (
381- watched,
382- mill.api.Result .Success (evaluated.values.map(_._1.asInstanceOf [T ])),
383- selectedTasks,
384- evaluated
385- )
386- case _ =>
387- Evaluator .Result (
388- watched,
389- mill.internal.Util .formatFailing(evaluated),
390- selectedTasks,
391- evaluated
392- )
391+ evaluated.transitiveFailing.size match {
392+ case 0 =>
393+ Evaluator .Result (
394+ watched,
395+ mill.api.Result .Success (evaluated.values.map(_._1.asInstanceOf [T ])),
396+ selectedTasks,
397+ evaluated
398+ )
399+ case _ =>
400+ Evaluator .Result (
401+ watched,
402+ mill.internal.Util .formatFailing(evaluated),
403+ selectedTasks,
404+ evaluated
405+ )
406+ }
393407 }
394408 }
395409
0 commit comments