Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/copy file plugin #225

Merged
merged 3 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFile_v1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using Nox.Cli.Abstractions;
using Nox.Cli.Abstractions.Extensions;

namespace Nox.Cli.Plugin.File;

public class FileCopyFile_v1: INoxCliAddin
{
public NoxActionMetaData Discover()
{
return new NoxActionMetaData
{
Name = "file/copy-file@v1",
Author = "Jan Schutte",
Description = "Copy a file from one folder to another.",

Inputs =
{
["source-path"] = new NoxActionInput {
Id = "source-path",
Description = "The path to the file to copy",
Default = string.Empty,
IsRequired = true
},

["target-path"] = new NoxActionInput {
Id = "target-path",
Description = "The path of the folder into which to copy the source file",
Default = string.Empty,
IsRequired = true
},
["is-overwrite"] = new NoxActionInput {
Id = "is-overwrite",
Description = "Indicate whether the copy must overwrite the target file, if it exists.",
Default = false,
IsRequired = false
}
}
};
}

private string? _sourcePath;
private string? _targetPath;
private bool? _isOverwrite;

public Task BeginAsync(IDictionary<string,object> inputs)
{
_sourcePath = inputs.Value<string>("source-path");
_targetPath = inputs.Value<string>("target-path");
_isOverwrite = inputs.ValueOrDefault<bool>("is-overwrite", this);
return Task.CompletedTask;
}

public Task<IDictionary<string, object>> ProcessAsync(INoxWorkflowContext ctx)
{
var outputs = new Dictionary<string, object>();

ctx.SetState(ActionState.Error);

if (string.IsNullOrEmpty(_sourcePath) ||
string.IsNullOrEmpty(_targetPath))
{
ctx.SetErrorMessage("The File copy-file action was not initialized");
}
else
{
try
{
var fullSourcePath = Path.GetFullPath(_sourcePath);
var filename = Path.GetFileName(fullSourcePath);
if (!System.IO.File.Exists(fullSourcePath))
{
ctx.SetErrorMessage($"Source file: {fullSourcePath} does not exist!");
}
else
{
var isValid = true;
var fullTargetPath = Path.Combine(Path.GetFullPath(_targetPath), filename);
Directory.CreateDirectory(Path.GetDirectoryName(fullTargetPath)!);
var createDate = DateTime.Now;
if (System.IO.File.Exists(fullTargetPath))
{
if (_isOverwrite!.Value)
{
createDate = System.IO.File.GetCreationTime(fullTargetPath);
System.IO.File.Delete(fullTargetPath);
}
else
{
ctx.SetErrorMessage($"File: {fullTargetPath} already exists, and is-overwrite was not specified.");
isValid = false;
}

}
if (isValid)
{
System.IO.File.Copy(fullSourcePath, fullTargetPath);
System.IO.File.SetCreationTime(fullTargetPath, createDate);
ctx.SetState(ActionState.Success);
}
}

}
catch (Exception ex)
{
ctx.SetErrorMessage(ex.Message);
}
}

return Task.FromResult<IDictionary<string, object>>(outputs);
}

public Task EndAsync()
{
return Task.CompletedTask;
}
}
54 changes: 50 additions & 4 deletions src/Nox.Cli.Plugins/Nox.Cli.Plugin.File/FileCopyFolder_v1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,34 @@ public NoxActionMetaData Discover()
Default = true,
IsRequired = false
},
["is-overwrite"] = new NoxActionInput {
Id = "is-overwrite",
Description = "Indicate whether the copy must overwrite the target path.",
Default = false,
IsRequired = false
}
}
};
}

private string? _sourcePath;
private string? _targetPath;
private bool? _isRecursive;
private bool? _isOverwrite;

public Task BeginAsync(IDictionary<string,object> inputs)
{
_sourcePath = inputs.Value<string>("source-path");
_targetPath = inputs.Value<string>("target-path");
_isRecursive = inputs.ValueOrDefault<bool>("is-recursive", this);
_isOverwrite = inputs.ValueOrDefault<bool>("is-overwrite", this);
return Task.CompletedTask;
}

public Task<IDictionary<string, object>> ProcessAsync(INoxWorkflowContext ctx)
{
var outputs = new Dictionary<string, object>();
var isValid = true;

ctx.SetState(ActionState.Error);

Expand All @@ -70,6 +79,7 @@ public Task<IDictionary<string, object>> ProcessAsync(INoxWorkflowContext ctx)
if (!Directory.Exists(fullSourcePath))
{
ctx.SetErrorMessage($"Folder {fullSourcePath} does not exist!");
isValid = false;
}
else
{
Expand All @@ -78,8 +88,24 @@ public Task<IDictionary<string, object>> ProcessAsync(INoxWorkflowContext ctx)
{
Directory.CreateDirectory(fullTargetPath);
}
CopyFiles(fullSourcePath, fullTargetPath);
ctx.SetState(ActionState.Success);
else
{
if (_isOverwrite!.Value)
{
PurgeFolder(fullTargetPath);
}
else
{
ctx.SetErrorMessage($"Folder {fullTargetPath} already exists, and is-overwrite was not specified.");
isValid = false;
}
}

if (isValid)
{
CopyFiles(fullSourcePath, fullTargetPath);
ctx.SetState(ActionState.Success);
}
}

}
Expand All @@ -103,10 +129,16 @@ private void CopyFiles(string sourceFolder, string targetFolder)

foreach (var file in di.GetFiles())
{
var targetFilePath = Path.Combine(targetFolder, file.Name);
if (System.IO.File.Exists(targetFilePath)) System.IO.File.Delete(targetFilePath);
var targetFilePath = Path.Combine(targetFolder, file.Name);
var createDate = DateTime.Now;
if (System.IO.File.Exists(targetFilePath))
{
createDate = System.IO.File.GetCreationTime(targetFilePath);
System.IO.File.Delete(targetFilePath);
}
Directory.CreateDirectory(targetFolder);
file.CopyTo(targetFilePath);
System.IO.File.SetCreationTime(targetFilePath, createDate);
}

if (_isRecursive == true)
Expand All @@ -117,4 +149,18 @@ private void CopyFiles(string sourceFolder, string targetFolder)
}
}
}

private void PurgeFolder(string path)
{
var di = new DirectoryInfo(path);
foreach (var file in di.GetFiles())
{
file.Delete();
}

foreach (var dir in di.GetDirectories())
{
dir.Delete(true);
}
}
}
11 changes: 6 additions & 5 deletions src/Nox.Cli.Variables/ClientVariableProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,15 +217,18 @@ private object ReplaceVariable(object value, bool isIfCondition = false, bool is
{
var result = value;

var match = _variableRegex.Match(result.ToString()!);
var matches = _variableRegex.Matches(result.ToString()!);

while (match.Success)
foreach (var match in matches.ToList())
{
var fullPhrase = match.Groups[0].Value;

var variable = match.Groups["variable"].Value;

if (isServer && _serverVariables.Contains(variable)) return result;
if (isServer && _serverVariables.Contains(variable))
{
continue;
}

var resolvedValue = LookupValue(variable);

Expand Down Expand Up @@ -259,8 +262,6 @@ private object ReplaceVariable(object value, bool isIfCondition = false, bool is
}
result = result.ToString()!.Replace(fullPhrase, "NULL");
}

match = _variableRegex.Match(result.ToString()!);
}

return result;
Expand Down
12 changes: 11 additions & 1 deletion src/Nox.Cli.Variables/ServerVariableProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,17 @@ private void ResolveServerVariables()
{
//Find the variable value
var lookupValue = LookupValue(match.Groups[2].Value);
if (lookupValue != null) item.Value = lookupValue;
if (lookupValue != null)
{
if (lookupValue is string)
{
item.Value = item.Value.ToString()!.Replace(match.Value, lookupValue.ToString());
}
else
{
item.Value = lookupValue;
}
}
}
}
}
Expand Down
102 changes: 102 additions & 0 deletions src/Plugin.File.Tests/CopyFileTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using Moq;
using Nox.Cli.Abstractions.Caching;
using Nox.Cli.Actions;
using Nox.Cli.Configuration;
using Nox.Cli.Plugin.File;
using Nox.Cli.Variables.Secrets;
using Nox.Secrets.Abstractions;
using Nox.Solution;
using Xunit;

namespace Plugin.File.Tests;

public class CopyFileTests
{
[Fact]
public async Task Can_copy_a_File_if_destination_folder_does_not_exist()
{
var path = "./files/copy-file";
//Ensure the target folder does not exist
Helpers.PurgeFolderRecursive(Path.Combine(path, "new-target"), true);

var plugin = new FileCopyFile_v1();
var inputs = new Dictionary<string, object>
{
{"source-path", Path.Combine(path, "source/Sample.txt")},
{"target-path", Path.Combine(path, "new-target")}
};
await plugin.BeginAsync(inputs);
var wfConfig = new WorkflowConfiguration();
var sln = Mock.Of<NoxSolution>();
var orgResolver = Mock.Of<IOrgSecretResolver>();
var cacheMan = Mock.Of<INoxCliCacheManager>();
var lteConfig = Mock.Of<LocalTaskExecutorConfiguration>();
var secretsResolver = Mock.Of<INoxSecretsResolver>();
var ctx = new NoxWorkflowContext(wfConfig, sln, orgResolver, cacheMan, lteConfig, secretsResolver);
await plugin.ProcessAsync(ctx);
Assert.True(System.IO.File.Exists(Path.Combine(path, "new-target/Sample.txt")));
}

[Fact]
public async Task Must_not_copy_if_destination_folder_exists_and_overwrite_not_specified()
{
var path = "./files/copy-file";
//Ensure the target folder exists
Helpers.PurgeFolderRecursive(Path.Combine(path, "new-target"), true);
Directory.CreateDirectory(Path.Combine(path, "new-target"));
await System.IO.File.WriteAllTextAsync(Path.Combine(path, "new-target/Sample.txt"), "Hello World");

var plugin = new FileCopyFile_v1();
var inputs = new Dictionary<string, object>
{
{"source-path", Path.Combine(path, "source/Sample.txt")},
{"target-path", Path.Combine(path, "new-target")}
};
await plugin.BeginAsync(inputs);
var wfConfig = new WorkflowConfiguration();
var sln = Mock.Of<NoxSolution>();
var orgResolver = Mock.Of<IOrgSecretResolver>();
var cacheMan = Mock.Of<INoxCliCacheManager>();
var lteConfig = Mock.Of<LocalTaskExecutorConfiguration>();
var secretsResolver = Mock.Of<INoxSecretsResolver>();
var ctx = new NoxWorkflowContext(wfConfig, sln, orgResolver, cacheMan, lteConfig, secretsResolver);
await plugin.ProcessAsync(ctx);
await plugin.EndAsync();
Assert.True(System.IO.File.Exists(Path.Combine(path, "new-target/Sample.txt")));
var fileSize = new FileInfo(Path.Combine(path, "new-target/Sample.txt")).Length;
Assert.Equal(11, fileSize);
}

[Fact]
public async Task Can_copy_a_File_if_destination_folder_exists_and_overwrite_specified()
{
var path = "./files/copy-file";
//Ensure the target folder exists
Helpers.PurgeFolderRecursive(Path.Combine(path, "new-target"), true);
Directory.CreateDirectory(Path.Combine(path, "new-target"));
await System.IO.File.WriteAllTextAsync(Path.Combine(path, "new-target/Sample.txt"), "Hello World");

var plugin = new FileCopyFile_v1();
var inputs = new Dictionary<string, object>
{
{"source-path", Path.Combine(path, "source/Sample.txt")},
{"target-path", Path.Combine(path, "new-target")},
{"is-overwrite", true}
};
await plugin.BeginAsync(inputs);
var wfConfig = new WorkflowConfiguration();
var sln = Mock.Of<NoxSolution>();
var orgResolver = Mock.Of<IOrgSecretResolver>();
var cacheMan = Mock.Of<INoxCliCacheManager>();
var lteConfig = Mock.Of<LocalTaskExecutorConfiguration>();
var secretsResolver = Mock.Of<INoxSecretsResolver>();
var ctx = new NoxWorkflowContext(wfConfig, sln, orgResolver, cacheMan, lteConfig, secretsResolver);
await plugin.ProcessAsync(ctx);
await plugin.EndAsync();
Assert.True(System.IO.File.Exists(Path.Combine(path, "new-target/Sample.txt")));
var fileSize = new FileInfo(Path.Combine(path, "new-target/Sample.txt")).Length;
Assert.Equal(0, fileSize);
}


}
2 changes: 1 addition & 1 deletion src/Plugin.File.Tests/FolderRenameTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public async Task Can_Rename_a_Folder()

if (Directory.Exists(Path.Combine(path, "Sample-After")))
{
Directory.Delete(Path.Combine(path, "Sample-After"));
Helpers.PurgeFolderRecursive(Path.Combine(path, "Sample-After"), true);
}

CopyRecursively(Path.Combine(path, "Sample"), Path.Combine(path, "Sample-Before"));
Expand Down
Loading
Loading