Skip to content

Commit

Permalink
feat!: Added advanced filters (#24)
Browse files Browse the repository at this point in the history
* feat: Added CopyFilter

* feat(CopyTask.cs): Changed type of Filter property

* feat(IClient.cs): Added filter to the list files method

* feat(Config.cs): Conversion to new Filter

* feat(Clients): New implementation

* feat(Program.cs): New filter system
  • Loading branch information
FRFlo authored Mar 11, 2024
1 parent 2f529b6 commit 4b073e0
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 16 deletions.
2 changes: 1 addition & 1 deletion Copy/Clients/Exchange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public bool DoFileExist(string path)
throw new NotImplementedException();
}

public string[] ListFiles(string path)
public string[] ListFiles(string path, CopyFilter filter)
{
throw new NotImplementedException();
}
Expand Down
10 changes: 8 additions & 2 deletions Copy/Clients/FTP.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Copy.Types;
using FluentFTP;
using System.Net;
using System.Text.RegularExpressions;

namespace Copy.Clients
{
Expand Down Expand Up @@ -37,15 +38,20 @@ public bool DoFileExist(string path)
return FtpClient.FileExists(path);
}

public string[] ListFiles(string path)
public string[] ListFiles(string path, CopyFilter filter)
{
if (!FtpClient.DirectoryExists(path))
{
Logger.Error($"Directory {path} does not exist");
throw new DirectoryNotFoundException($"Directory {path} does not exist");
}

FtpListItem[] files = FtpClient.GetListing(path);
Regex nameRegex = new(filter.Name);
Regex authorRegex = new(filter.Author);

FtpListItem[] files = FtpClient.GetListing(path)
.Where(f => nameRegex.IsMatch(f.Name) && authorRegex.IsMatch(f.RawOwner) && f.Created >= filter.CreatedAfter && (ulong)f.Size <= filter.MaxSize && (ulong)f.Size >= filter.MinSize)
.ToArray();
return files.Select(f => Path.Combine(path, f.Name)).ToArray();
}

Expand Down
18 changes: 16 additions & 2 deletions Copy/Clients/Local.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Copy.Types;
using System.Runtime.Versioning;
using System.Security.Principal;
using System.Text.RegularExpressions;

namespace Copy.Clients
{
Expand Down Expand Up @@ -28,15 +31,26 @@ public bool DoFileExist(string path)
return File.Exists(path);
}

public string[] ListFiles(string path)
[SupportedOSPlatform("windows")]
public string[] ListFiles(string path, CopyFilter filter)
{
if (!Directory.Exists(path))
{
Logger.Error($"Directory {path} does not exist");
throw new DirectoryNotFoundException($"Directory {path} does not exist");
}

return Directory.GetFiles(path);
Regex nameRegex = new(filter.Name);
Regex authorRegex = new(filter.Author);

return Directory.GetFiles(path)
.Where(f =>
{
FileInfo fileInfo = new(f);
bool authorMatch = authorRegex.IsMatch(fileInfo.GetAccessControl().GetOwner(typeof(NTAccount))?.Value ?? throw new FileOwnerNotFoundException($"Impossible to get owner of {f}"));
return nameRegex.IsMatch(Path.GetFileName(f)) && authorMatch && File.GetCreationTime(f) >= filter.CreatedAfter && (ulong)fileInfo.Length <= filter.MaxSize && (ulong)fileInfo.Length >= filter.MinSize;
})
.ToArray();
}

public Stream GetFile(string path)
Expand Down
11 changes: 9 additions & 2 deletions Copy/Clients/SFTP.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Copy.Types;
using Renci.SshNet;
using System.Text.RegularExpressions;

namespace Copy.Clients
{
Expand All @@ -23,15 +24,21 @@ public SFTP(Client credentials)
SftpClient.Connect();
}

public string[] ListFiles(string path)
public string[] ListFiles(string path, CopyFilter filter)
{
if (!SftpClient.Exists(path))
{
Logger.Error($"Directory {path} does not exist");
throw new DirectoryNotFoundException($"Directory {path} does not exist");
}

var files = SftpClient.ListDirectory(path);
if (filter.Author != ".*") Logger.Warn($"Filtering by author is not supported by SFTP");

Regex nameRegex = new(filter.Name);
Regex authorRegex = new(filter.Author);

var files = SftpClient.ListDirectory(path)
.Where(f => nameRegex.IsMatch(f.Name) && f.LastWriteTime >= filter.CreatedAfter && (ulong)f.Length <= filter.MaxSize && (ulong)f.Length >= filter.MinSize);
return files.Select(f => f.FullName.Remove(0, 1)).ToArray();
}

Expand Down
10 changes: 8 additions & 2 deletions Copy/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,21 @@ public static string GetDefault()
Source = "source",
Destination = "destination",
Client = "SFTP",
Filter = "*.txt"
Filter = new CopyFilter()
{
Name = ".*\\.txt"
}
},
new CopyTask()
{
Source = "source",
Destination = "destination",
Client = "Local",
Delete = true,
Filter = "*.txt"
Filter = new CopyFilter()
{
Name = ".*\\.txt"
}
},
new CopyTask()
{
Expand Down
8 changes: 3 additions & 5 deletions Copy/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Copy.Clients;
using Copy.Types;
using System.Text.RegularExpressions;

namespace Copy
{
Expand Down Expand Up @@ -63,10 +62,9 @@ public static void Main(string[] args)
throw new ClientNotFoundException($"Client {task.Source} not found");
}

Regex filter = new(task.Filter);
IEnumerable<string> files = client.ListFiles(task.Source).Where(f => filter.IsMatch(f));
string[] files = client.ListFiles(task.Source, task.Filter);

Logger.Info($"Treating {files.Count()} files");
Logger.Info($"Treating {files.Length} files");

foreach (string file in files)
{
Expand All @@ -86,7 +84,7 @@ public static void Main(string[] args)
Logger.Debug($"Copied {file} to {task.Destination}");
}

Logger.Info($"Copied {files.Count()} files from {task.Source} to {task.Destination} using {task.Client}");
Logger.Info($"Copied {files.Length} files from {task.Source} to {task.Destination} using {task.Client}");
}

Logger.Info("All tasks executed");
Expand Down
36 changes: 36 additions & 0 deletions Copy/Types/CopyFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Newtonsoft.Json;

namespace Copy.Types
{
/// <summary>
/// Filter for files to copy.
/// </summary>
public class CopyFilter
{
/// <summary>
/// Pattern the name of the files must match.
/// </summary>
[JsonProperty(PropertyName = "Name", Required = Required.DisallowNull)]
public string Name { get; set; } = ".*";
/// <summary>
/// Pattern the author of the files must match.
/// </summary>
[JsonProperty(PropertyName = "Author", Required = Required.DisallowNull)]
public string Author { get; set; } = ".*";
/// <summary>
/// Date the files must be created after.
/// </summary>
[JsonProperty(PropertyName = "CreatedAfter", Required = Required.DisallowNull)]
public DateTime CreatedAfter { get; set; } = DateTime.MinValue;
/// <summary>
/// Size the files must not exceed.
/// </summary>
[JsonProperty(PropertyName = "MaxSize", Required = Required.DisallowNull)]
public ulong MaxSize { get; set; } = ulong.MaxValue;
/// <summary>
/// Size the files must exceed.
/// </summary>
[JsonProperty(PropertyName = "MinSize", Required = Required.DisallowNull)]
public ulong MinSize { get; set; } = 0;
}
}
2 changes: 1 addition & 1 deletion Copy/Types/CopyTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ public class CopyTask
/// Filter for files to copy.
/// </summary>
[JsonProperty(PropertyName = "Filter", Required = Required.DisallowNull)]
public string Filter { get; set; } = ".*";
public CopyFilter Filter { get; set; } = new();
}
}
8 changes: 8 additions & 0 deletions Copy/Types/Exceptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@
internal class ClientNotFoundException(string message) : Exception(message)
{
}

/// <summary>
/// Exception thrown when a file owner is not found.
/// </summary>
/// <param name="message">The message to display.</param>
internal class FileOwnerNotFoundException(string message) : Exception(message)
{
}
}
3 changes: 2 additions & 1 deletion Copy/Types/IClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ internal interface IClient : IDisposable
/// List files in a directory.
/// </summary>
/// <param name="path">Path to the directory.</param>
/// <param name="filter">Filter for files to list.</param>
/// <returns>Array of file names.</returns>
string[] ListFiles(string path);
string[] ListFiles(string path, CopyFilter filter);
/// <summary>
/// Check if a file exists.
/// </summary>
Expand Down

0 comments on commit 4b073e0

Please sign in to comment.