diff --git a/example/fundamentals/tasks/3-anonymous-tasks/build.mill b/example/fundamentals/tasks/3-anonymous-tasks/build.mill index 0451d79ebabd..9d95f3f825d3 100644 --- a/example/fundamentals/tasks/3-anonymous-tasks/build.mill +++ b/example/fundamentals/tasks/3-anonymous-tasks/build.mill @@ -23,6 +23,17 @@ def printFileData(fileName: String) = Task.Command { // anywhere and passed around any way you want, until you finally make use of them // within a downstream task or command. // +// Anonymous tasks work well when parameters are known at task definition time. Dynamically +// generated inputs can not be used with Anonymous Tasks, since mill wouldn't be able to build +// the dependency tree. We need to know the parameters before creating the task, but the tasks +// need to be created before we can start evaluation, we have a classic hen-or-egg problem. +// Common strategies around this are: +// 1. Define the values outside of a task, so Mill knows how to create the anonymous +// tasks before evaluation starts. +// 2. Put the value itself into a task, so it can be properly ordered to be evaluated +// before it's dependencies. +// 3. Make it not a task but a normal def +// // While an anonymous task ``foo``'s own output is not cached, if it is used in a // downstream task `baz` and the upstream task `bar` hasn't changed, // ``baz``'s cached output will be used and ``foo``'s evaluation will be skipped diff --git a/example/fundamentals/tasks/8-inheritance-and-chaining/build.mill b/example/fundamentals/tasks/8-inheritance-and-chaining/build.mill new file mode 100644 index 000000000000..bc6073c865ed --- /dev/null +++ b/example/fundamentals/tasks/8-inheritance-and-chaining/build.mill @@ -0,0 +1,62 @@ +package build +import mill.* +import mill.api.TaskCtx + +trait BaseModule extends Module { + def generate = Task { + val output = Task.dest / "generated.txt" + os.write(output, "hello") + PathRef(output) + } +} + +// This module uses the base implementation unchanged +// Calling generate here will create: +// out/moduleA/generate.dest/generated.txt +object moduleA extends BaseModule + +// When overriding tasks, never modify the parent task's output. +// Instead, create new output in your own task's destination folder +// Here we will generate two files in the output: +// out/moduleB/generate.super/BaseModule.dest/generated.txt (parent output) +// out/moduleB/generate.dest/processed.txt (this module's output) +// Note: We can not over write the original contents of +// generated.txt, because it is in a different output destination +object moduleB extends BaseModule { + override def generate = Task { + val parentResult = super.generate() + val parentContent = os.read(parentResult.path) + val processed = parentContent + .replaceAll("hello", "world") + .trim + + writeData(processed, "processed.txt") + } + + // Helper function for writing data within a task context + // Note: This is a regular function, not a Task, so it can accept + // runtime parameters. It uses implicit TaskCtx to access Task.dest + private def writeData(data: String, name: String)(implicit ctx: TaskCtx): PathRef = { + val outputPath = ctx.dest / name + os.write(outputPath, data) + PathRef(outputPath) + } +} + +// We can also acheive similar results by chaining tasks together. +object moduleC extends BaseModule { + override def generate = Task { + processGenerated() + } + + def processGenerated = Task { + val parentResult = super.generate() + val parentContent = os.read(parentResult.path) + val processed = parentContent + .replaceAll("hello", "world") + .trim + val outputPath = Task.dest / "processed.txt" + os.write(outputPath, processed) + PathRef(outputPath) + } +} diff --git a/website/docs/modules/ROOT/pages/fundamentals/tasks.adoc b/website/docs/modules/ROOT/pages/fundamentals/tasks.adoc index b12f332297ef..28f72d93c1e1 100644 --- a/website/docs/modules/ROOT/pages/fundamentals/tasks.adoc +++ b/website/docs/modules/ROOT/pages/fundamentals/tasks.adoc @@ -52,3 +52,7 @@ include::partial$example/fundamentals/tasks/6-workers.adoc[] include::partial$example/fundamentals/tasks/3-anonymous-tasks.adoc[] +=== Inheritance and Chaining of Tasks + +include::partial$example/fundamentals/tasks/8-inheritance-and-chaining.adoc[] +