This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-nitride-cil/examples/CopyFiles/CopyFilesPipeline.cs
D. Moonfire 2892ec3445
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
feat!: added cancellation token support to pipelines and operations
2023-01-17 19:24:09 -06:00

112 lines
4.5 KiB
C#

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using MfGames.Gallium;
using MfGames.Nitride;
using MfGames.Nitride.IO.Contents;
using MfGames.Nitride.IO.Directories;
using MfGames.Nitride.IO.Paths;
using MfGames.Nitride.Pipelines;
namespace CopyFiles;
/// <summary>
/// The single pipeline used by the CopyFiles project.
/// </summary>
public class CopyFilesPipeline : PipelineBase
{
private readonly AddPathPrefix addPathPrefix;
private readonly ClearDirectory clearDirectory;
private readonly ReadFiles readFiles;
private readonly RemovePathPrefix removePathPrefix;
private readonly WriteFiles writeFiles;
public CopyFilesPipeline(
ReadFiles readFiles,
ClearDirectory clearDirectory,
WriteFiles writeFiles,
RemovePathPrefix removePathPrefix,
AddPathPrefix addPathPrefix)
{
// 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.WithPattern("/input/**/*.txt");
this.clearDirectory = clearDirectory.WithPath("/output");
this.writeFiles = writeFiles;
this.removePathPrefix = removePathPrefix.WithPathPrefix("/input");
this.addPathPrefix = addPathPrefix.WithPathPrefix("/output");
}
/// <inheritdoc />
public override IAsyncEnumerable<Entity> RunAsync(
IEnumerable<Entity> _,
CancellationToken cancellationToken = default)
{
// We don't care about the incoming entities which means we can
// ignore them and use the entities from the ReadFiles operation
// or we can union the entities pass in with the ReadFiles in case
// we want to merge them.
//
// This will read all the files of the given pattern and return them
// as an IEnumerable<Entity> with the Zio components (UPath and
// binary contents) set. As a note, this doesn't actually read the
// file, just create a pointer to where the file could be read from.
//
// The path component will always be the relative path to the root,
// so `/input/a.txt` in this case since we only have one file.
IEnumerable<Entity> entities = this.readFiles.Run();
// Change the path. The path (Zio.UPath component) stays with the
// entity which is why there is no root directory in the writeFiles
// operation. Instead, we need to remove the `/input` and replace it
// with the `/output`.
//
// We can do that with a RemovePathPrefix followed by an
// AddPathPrefix, or use the more complex version of ChangePaths.
// In this case, we are going for easy to learn, so we'll do the
// pair.
//
// We are going to use the chain extension to make it easier to
// read. Coming out of this, we will have one entity that fulfills:
//
// entity.Get<UPath> == "/output/a.txt"
entities = entities
.Run(this.removePathPrefix, cancellationToken)
.Run(this.addPathPrefix, cancellationToken);
// Then we write out the files to the output. First we make sure we
// clear out the output. This operation performs an action when it
// it is first entered, but otherwise passes all the inputs through.
//
// We can call the clear directory in three ways. The first is to call
// the operation with:
//
// this.clearDirectory.Run()
//
// The other is to pass in the entities and get a new list of
// modified ones out. In this case, clear doesn't make any changes,
// but Entity objects are immutable, so we always work on the list
// returned.
//
// entities = this.clearDirectory.Run(entity)
//
// The third way is to use an extension on entities which lets us
// chain calls, ala Gulp's pipelines. The below code does this along
// with writing the files to the output.
entities = entities
.Run(this.clearDirectory, cancellationToken)
.Run(this.writeFiles, cancellationToken);
// If we are chaining this pipeline into another, we return the
// entities. Otherwise, we can just return an empty list. The
// pipeline is async, so it is wrapped in a task, but most
// operations are not (or are both).
return entities.ToAsyncEnumerable();
}
}