diff --git a/TASKS.md b/TASKS.md
new file mode 100644
index 0000000..a501258
--- /dev/null
+++ b/TASKS.md
@@ -0,0 +1,6 @@
+# Tasks
+
+- [ ] Does not return a proper code when failing
+- [ ] CopyFiles sample does not generate data
+- [ ] ReadFiles should have With methods
+- [ ] WriteFiles should have With methods
diff --git a/examples/CopyFiles/CopyFiles.csproj b/examples/CopyFiles/CopyFiles.csproj
index 1d2d39a..e7b804a 100644
--- a/examples/CopyFiles/CopyFiles.csproj
+++ b/examples/CopyFiles/CopyFiles.csproj
@@ -1,8 +1,30 @@
-
-
-
- Exe
- net5.0
-
-
-
+
+
+
+ Exe
+ net5.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
diff --git a/examples/CopyFiles/CopyFilesModule.cs b/examples/CopyFiles/CopyFilesModule.cs
new file mode 100644
index 0000000..d14902b
--- /dev/null
+++ b/examples/CopyFiles/CopyFilesModule.cs
@@ -0,0 +1,20 @@
+using Autofac;
+
+namespace CopyFiles
+{
+ public class CopyFilesModule : Module
+ {
+ ///
+ protected override void Load(ContainerBuilder builder)
+ {
+ // This just registers all the non-static classes as singletons
+ // within the system. We use lifetimes in other components depending
+ // on how they are used, but in this case, we don't need it.
+ builder
+ .RegisterAssemblyTypes(this.GetType().Assembly)
+ .AsSelf()
+ .AsImplementedInterfaces()
+ .SingleInstance();
+ }
+ }
+}
diff --git a/examples/CopyFiles/CopyFilesPipeline.cs b/examples/CopyFiles/CopyFilesPipeline.cs
new file mode 100644
index 0000000..b1d270d
--- /dev/null
+++ b/examples/CopyFiles/CopyFilesPipeline.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+using Gallium;
+
+using Nitride.IO.Contents;
+using Nitride.Pipelines;
+
+namespace CopyFiles
+{
+ ///
+ /// The single pipeline used by the CopyFiles project.
+ ///
+ public class CopyFilesPipeline : PipelineBase
+ {
+ private readonly ReadFiles readFiles;
+
+ private readonly WriteFiles writeFiles;
+
+ public CopyFilesPipeline(
+ ReadFiles readFiles,
+ WriteFiles writeFiles)
+ {
+ // While we can configure these during runtime, it seems cleaner to
+ // build them up during the constructor to call out the ones that
+ // require runtime data.
+ this.readFiles = readFiles;
+ this.writeFiles = writeFiles;
+ }
+
+ ///
+ public override Task> RunAsync(
+ IEnumerable entities)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/examples/CopyFiles/CopyFilesProgram.cs b/examples/CopyFiles/CopyFilesProgram.cs
new file mode 100644
index 0000000..dbd4516
--- /dev/null
+++ b/examples/CopyFiles/CopyFilesProgram.cs
@@ -0,0 +1,55 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+
+using Autofac;
+
+using MfGames.IO.Extensions;
+
+using Nitride;
+using Nitride.IO;
+
+namespace CopyFiles
+{
+ ///
+ /// Main entry point into the CopyFiles sample generator.
+ ///
+ public static class CopyFilesProgram
+ {
+ public static async Task Main(string[] args)
+ {
+ // All of the builder methods are fluent in that they return the
+ // builder to allow them to be chained. However, for documentation
+ // purposes, we are going to split them apart to explain the details.
+ var builder = new NitrideBuilder(args);
+
+ // Filesystem access is provided by Zio, which allows for mutliple
+ // folders to be combined together into a single unified file
+ // system. At the moment, we set the "root" directory which will
+ // contains all the paths, both input and output.
+ DirectoryInfo rootDir = typeof(CopyFilesProgram)
+ .GetDirectory()
+ !.FindGitRoot()
+ !.GetDirectory("examples/CopyFiles");
+
+ builder.WithRootDirectory(rootDir);
+
+ // Like Serilog, we use a number of extension methods on the builder
+ // to inject functionality such as plugins and extensions. In this
+ // case, we only need the Nitride.IO module so we use the `UseIO`
+ // to inject the requisite modules and configure it.
+ builder.UseIO();
+
+ // We use Autofac for the bulk of our registration handling. This
+ // was mainly because we are more comfortable with Autofac, but it
+ // also has a clean interface for handling some of the more esoteric
+ // problems we've encountered.
+ builder.ConfigureContainer(
+ x => x.RegisterModule());
+
+ // Finally, we build the site generator object and run it.
+ return await builder.BuildAsync();
+ }
+ }
+}
diff --git a/examples/CopyFiles/CopyFilesTest.cs b/examples/CopyFiles/CopyFilesTest.cs
new file mode 100644
index 0000000..9514c80
--- /dev/null
+++ b/examples/CopyFiles/CopyFilesTest.cs
@@ -0,0 +1,68 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Threading.Tasks;
+
+using CliWrap;
+
+using MfGames.IO.Extensions;
+
+using Nitride.Tests;
+
+using Xunit;
+using Xunit.Abstractions;
+
+namespace CopyFiles
+{
+ ///
+ /// Tests the execution of the tool and ensures it is working correctly.
+ ///
+ public class CopyFilesTest : NitrideTestsBase
+ {
+ public CopyFilesTest(ITestOutputHelper output)
+ : base(output)
+ {
+ }
+
+ [Fact]
+ public async Task Run()
+ {
+ // Figure out the paths for this test.
+ DirectoryInfo rootDir = typeof(CopyFilesProgram)
+ .GetDirectory()
+ !.FindGitRoot()
+ !.GetDirectory("examples/CopyFiles");
+ DirectoryInfo outputDir = rootDir.GetDirectory("output");
+ FileInfo projectFile = rootDir.GetFile("CopyFiles.csproj");
+
+ this.Logger.Error("A {0}", rootDir);
+
+ // Clear out the output directory if we have an old one.
+ if (outputDir.Exists)
+ {
+ outputDir.Delete(true);
+ }
+
+ // Execute the generator. This will throw if there is an exception.
+ await Cli
+ .Wrap("dotnet")
+ .WithArguments(
+ x => x
+ .Add("run")
+ .Add("--project")
+ .Add(projectFile.FullName)
+ .Add("--")
+ .Add("build"))
+ .ExecuteAsync();
+
+ // Make sure we have our output.
+ FileInfo aFile = outputDir.GetFile("a.txt");
+
+ Assert.True(aFile.Exists);
+
+ string aText = aFile.ReadAllText().Trim();
+
+ Assert.Equal("This is the 'A' file.", aText);
+ }
+ }
+}
diff --git a/examples/CopyFiles/Program.cs b/examples/CopyFiles/Program.cs
deleted file mode 100644
index fca05cd..0000000
--- a/examples/CopyFiles/Program.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using System;
-
-namespace CopyFiles
-{
- class Program
- {
- static void Main(string[] args)
- {
- Console.WriteLine("Hello World!");
- }
- }
-}
diff --git a/examples/CopyFiles/README.md b/examples/CopyFiles/README.md
new file mode 100644
index 0000000..62abd69
--- /dev/null
+++ b/examples/CopyFiles/README.md
@@ -0,0 +1,6 @@
+# Copy Files
+
+This is probably the most basic generator possible. It simply copies files from
+the input and places them into the output. However, it also demonstrates a
+basic setup including creating a pipeline, wiring everything up with modules,
+and configuring everything.
diff --git a/examples/CopyFiles/input/a.txt b/examples/CopyFiles/input/a.txt
new file mode 100644
index 0000000..e8dd0e9
--- /dev/null
+++ b/examples/CopyFiles/input/a.txt
@@ -0,0 +1 @@
+This is the 'A' file.