109 lines
4.3 KiB
C#
109 lines
4.3 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
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> _)
|
|
{
|
|
// 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)
|
|
.Run(this.addPathPrefix);
|
|
|
|
// 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)
|
|
.Run(this.writeFiles);
|
|
|
|
// 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();
|
|
}
|
|
}
|