diff --git a/.gitignore b/.gitignore
index aa33348..b85a546 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,8 @@ bld/
# Visual Studio 2015/2017 cache/options directory
.vs/
+.idea/
+.vscode/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
diff --git a/src/BinaryPatrick.Prune.csproj b/src/BinaryPatrick.Prune.csproj
index 055a062..9351a66 100644
--- a/src/BinaryPatrick.Prune.csproj
+++ b/src/BinaryPatrick.Prune.csproj
@@ -8,7 +8,7 @@
enable
prune
BinaryPatrick
- Copyright 2023-2024
+ Copyright 2023-2025
1.1.0
@@ -18,11 +18,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/src/Interfaces/IDirectoryService.cs b/src/Interfaces/IDirectoryService.cs
index 57326a2..3223c2a 100644
--- a/src/Interfaces/IDirectoryService.cs
+++ b/src/Interfaces/IDirectoryService.cs
@@ -8,7 +8,7 @@ public interface IDirectoryService
{
/// Retrieves files using the arguments provided for , , and
/// Files matching the search path and pattern
- IEnumerable GetFiles();
+ ICollection GetFiles();
/// Deletes the given files when is
/// Files to be deleted
diff --git a/src/Models/PruneOptions.cs b/src/Models/PruneOptions.cs
index b5f786e..58c168f 100644
--- a/src/Models/PruneOptions.cs
+++ b/src/Models/PruneOptions.cs
@@ -33,6 +33,12 @@ public class PruneOptions
///
[Option('s', "silent", Required = false, HelpText = "Disable all logging", SetName = OptionsSetName.LoggingSilent, Default = false)]
public bool IsSilent { get; set; } = false;
+
+ ///
+ /// Disables logging
+ ///
+ [Option('z', "utc", Required = false, HelpText = "Use UTC Timezone for evaluating file time", Default = false)]
+ public bool UseUtc { get; set; } = false;
///
/// File name prefix to use when matching archives
@@ -43,7 +49,7 @@ public class PruneOptions
///
/// File extension to use when matching archives
///
- [Option('e', "ext", Required = false, HelpText = "File extension to use when matching archives, i.e. img, txt, tar.gz (do not include dot)")]
+ [Option('e', "ext", Required = false, HelpText = "File extension to use when matching archives, i.e. img, txt, tar.gz (do not include leading dot)")]
public string? FileExtension { get; set; }
///
diff --git a/src/Models/RetentionSorter.cs b/src/Models/RetentionSorter.cs
index af1b84b..480e315 100644
--- a/src/Models/RetentionSorter.cs
+++ b/src/Models/RetentionSorter.cs
@@ -8,26 +8,28 @@ namespace BinaryPatrick.Prune.Models;
public class RetentionSorter : IRetentionSorter, IInitializedRetentionSorter, ILastSortedRetentionSorter, IHourlySortedRetentionSorter, IDailySortedRetentionSorter, IWeeklySortedRetentionSorter, IMonthlySortedRetentionSorter, ISortedRetentionSorter
{
private readonly IConsoleLogger logger;
+ private readonly TimeSpan offset;
private readonly IEnumerator enumerator;
private DateTimeOffset lastTimestamp;
- ///
+ ///
public IRetentionSortResult Result { get; } = new RetentionSortResult();
/// Initializes a new instance of the class
- public RetentionSorter(IConsoleLogger logger, IEnumerable files)
+ public RetentionSorter(IConsoleLogger logger, IEnumerable files, TimeSpan offset)
{
logger.LogTrace($"Constructing {nameof(RetentionSorter)}");
this.logger = logger;
+ this.offset = offset;
lastTimestamp = DateTimeOffset.MinValue;
enumerator = files
.OrderByDescending(x => x.LastModified)
.GetEnumerator();
}
- ///
+ ///
public ILastSortedRetentionSorter KeepLast(uint count)
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(KeepLast)}");
@@ -40,14 +42,14 @@ public ILastSortedRetentionSorter KeepLast(uint count)
while (Result.Last.Count < count && enumerator.MoveNext())
{
Result.Last.Add(enumerator.Current);
- lastTimestamp = enumerator.Current.LastModified;
+ lastTimestamp = enumerator.Current.LastModified.ToOffset(offset);
LogKeeping(LabelConstant.KeepLast, enumerator.Current.Name);
}
return this;
}
- ///
+ ///
public IHourlySortedRetentionSorter KeepHourly(uint count)
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(KeepHourly)}");
@@ -59,7 +61,7 @@ public IHourlySortedRetentionSorter KeepHourly(uint count)
while (Result.Hourly.Count < count && enumerator.MoveNext())
{
- DateTimeOffset timestamp = enumerator.Current.LastModified;
+ DateTimeOffset timestamp = enumerator.Current.LastModified.ToOffset(offset);
if (timestamp.Year != lastTimestamp.Year || timestamp.Month != lastTimestamp.Month || timestamp.Day != lastTimestamp.Day || timestamp.Hour != lastTimestamp.Hour)
{
Result.Hourly.Add(enumerator.Current);
@@ -78,7 +80,7 @@ public IHourlySortedRetentionSorter KeepHourly(uint count)
return this;
}
- ///
+ ///
public IDailySortedRetentionSorter KeepDaily(uint count)
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(KeepDaily)}");
@@ -90,7 +92,7 @@ public IDailySortedRetentionSorter KeepDaily(uint count)
while (Result.Daily.Count < count && enumerator.MoveNext())
{
- DateTimeOffset timestamp = enumerator.Current.LastModified;
+ DateTimeOffset timestamp = enumerator.Current.LastModified.ToOffset(offset);
if (timestamp.Year != lastTimestamp.Year || timestamp.Month != lastTimestamp.Month || timestamp.Day != lastTimestamp.Day)
{
Result.Daily.Add(enumerator.Current);
@@ -109,7 +111,7 @@ public IDailySortedRetentionSorter KeepDaily(uint count)
return this;
}
- ///
+ ///
public IWeeklySortedRetentionSorter KeepWeekly(uint count)
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(KeepWeekly)}");
@@ -121,7 +123,7 @@ public IWeeklySortedRetentionSorter KeepWeekly(uint count)
while (Result.Weekly.Count < count && enumerator.MoveNext())
{
- DateTimeOffset timestamp = enumerator.Current.LastModified;
+ DateTimeOffset timestamp = enumerator.Current.LastModified.ToOffset(offset);
if (ISOWeek.GetYear(timestamp.DateTime) != ISOWeek.GetYear(lastTimestamp.DateTime) || ISOWeek.GetWeekOfYear(timestamp.DateTime) != ISOWeek.GetWeekOfYear(lastTimestamp.DateTime))
{
Result.Weekly.Add(enumerator.Current);
@@ -141,7 +143,7 @@ public IWeeklySortedRetentionSorter KeepWeekly(uint count)
}
- ///
+ ///
public IMonthlySortedRetentionSorter KeepMonthly(uint count)
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(KeepMonthly)}");
@@ -153,7 +155,7 @@ public IMonthlySortedRetentionSorter KeepMonthly(uint count)
while (Result.Monthly.Count < count && enumerator.MoveNext())
{
- DateTimeOffset timestamp = enumerator.Current.LastModified;
+ DateTimeOffset timestamp = enumerator.Current.LastModified.ToOffset(offset);
if (timestamp.Year != lastTimestamp.Year || timestamp.Month != lastTimestamp.Month)
{
Result.Monthly.Add(enumerator.Current);
@@ -172,7 +174,7 @@ public IMonthlySortedRetentionSorter KeepMonthly(uint count)
return this;
}
- ///
+ ///
public ISortedRetentionSorter KeepYearly(uint count)
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(KeepYearly)}");
@@ -184,7 +186,7 @@ public ISortedRetentionSorter KeepYearly(uint count)
while (Result.Yearly.Count < count && enumerator.MoveNext())
{
- DateTimeOffset timestamp = enumerator.Current.LastModified;
+ DateTimeOffset timestamp = enumerator.Current.LastModified.ToOffset(offset);
if (timestamp.Year != lastTimestamp.Year)
{
Result.Yearly.Add(enumerator.Current);
@@ -204,7 +206,7 @@ public ISortedRetentionSorter KeepYearly(uint count)
return this;
}
- ///
+ ///
public ISortedRetentionSorter PruneRemaining()
{
logger.LogTrace($"Entering {nameof(RetentionSorter)}.{nameof(PruneRemaining)}");
diff --git a/src/Services/DirectoryService.cs b/src/Services/DirectoryService.cs
index 246c443..fd4066d 100644
--- a/src/Services/DirectoryService.cs
+++ b/src/Services/DirectoryService.cs
@@ -22,7 +22,7 @@ public DirectoryService(IConsoleLogger logger, PruneOptions options)
}
///
- public IEnumerable GetFiles()
+ public ICollection GetFiles()
{
logger.LogTrace($"Entering {nameof(DirectoryService)}.{nameof(GetFiles)}");
diff --git a/src/Services/PruneService.cs b/src/Services/PruneService.cs
index 0448ed2..caa8d48 100644
--- a/src/Services/PruneService.cs
+++ b/src/Services/PruneService.cs
@@ -34,8 +34,8 @@ public void PruneFiles()
return;
}
- IEnumerable files = directoryService.GetFiles();
- if (!files.Any())
+ ICollection files = directoryService.GetFiles();
+ if (files.Count == 0)
{
return;
}
diff --git a/src/Services/RetentionSorterFactory.cs b/src/Services/RetentionSorterFactory.cs
index f7e9881..6e8e547 100644
--- a/src/Services/RetentionSorterFactory.cs
+++ b/src/Services/RetentionSorterFactory.cs
@@ -7,12 +7,14 @@ namespace BinaryPatrick.Prune.Services;
public class RetentionSorterFactory : IRetentionSorterFactory
{
private readonly IConsoleLogger logger;
+ private readonly PruneOptions options;
/// Initializes a new instance of the class
- public RetentionSorterFactory(IConsoleLogger logger)
+ public RetentionSorterFactory(IConsoleLogger logger, PruneOptions options)
{
logger.LogTrace($"Constructing {nameof(RetentionSorterFactory)}");
this.logger = logger;
+ this.options = options;
}
///
@@ -20,6 +22,7 @@ public IInitializedRetentionSorter CreateRetentionSorter(IEnumerable
{
logger.LogTrace($"Entering {nameof(RetentionSorterFactory)}.{nameof(CreateRetentionSorter)}");
- return new RetentionSorter(logger, files);
+ TimeSpan offset = options.UseUtc ? TimeZoneInfo.Utc.BaseUtcOffset : TimeZoneInfo.Local.BaseUtcOffset;
+ return new RetentionSorter(logger, files, offset);
}
}
diff --git a/tests/BinaryPatrick.Prune.Unit.csproj b/tests/BinaryPatrick.Prune.Unit.csproj
index de16109..4b589c1 100644
--- a/tests/BinaryPatrick.Prune.Unit.csproj
+++ b/tests/BinaryPatrick.Prune.Unit.csproj
@@ -10,16 +10,16 @@
-
+
-
+
-
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepDaily.cs b/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepDaily.cs
index 08c2b2f..c675d18 100644
--- a/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepDaily.cs
+++ b/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepDaily.cs
@@ -15,7 +15,7 @@ public void KeepDaily_WithZero_ShouldNotTake()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(15, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
int keep = 0;
// Act
@@ -41,7 +41,7 @@ public void KeepDaily_With1_ShouldTake1()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(15, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
int keep = 1;
// Act
@@ -72,7 +72,7 @@ public void KeepDaily_WithN_ShouldTakeN(int keep)
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 23, 59, 59, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(fileCount, startTime, TimeSpan.FromHours(6));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
// Act
retentionSorter.KeepDaily((uint)keep);
@@ -90,15 +90,38 @@ public void KeepDaily_WithN_ShouldTakeN(int keep)
result.Unmatched.Should().NotBeEmpty();
}
- [Fact]
- public void KeepDaily_WithMinuteIncrements_ShouldTake2()
+ [Theory]
+ [InlineData(0)]
+ [InlineData(1)]
+ [InlineData(2)]
+ [InlineData(3)]
+ [InlineData(4)]
+ [InlineData(5)]
+ [InlineData(6)]
+ [InlineData(7)]
+ [InlineData(8)]
+ [InlineData(9)]
+ [InlineData(10)]
+ [InlineData(11)]
+ [InlineData(12)]
+ [InlineData(13)]
+ [InlineData(14)]
+ [InlineData(15)]
+ [InlineData(16)]
+ [InlineData(17)]
+ [InlineData(18)]
+ [InlineData(19)]
+ [InlineData(20)]
+ [InlineData(21)]
+ [InlineData(23)]
+ public void KeepDaily_WithMinuteIncrements_ShouldTake2(int hours)
{
+ TimeSpan offset = TimeSpan.FromHours(8);
// Arrange
- int hours = Random.Shared.Next(0, 23);
- DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, hours, 0, 0, TimeSpan.Zero);
+ DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, hours, 0, 0, offset);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(1500, startTime, TimeSpan.FromMinutes(1));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, offset);
// Act
retentionSorter.KeepDaily(2);
@@ -109,9 +132,7 @@ public void KeepDaily_WithMinuteIncrements_ShouldTake2()
result.Daily.Should().HaveCount(2);
result.Daily[0].LastModified.Should().BeExactly(startTime);
- result.Daily[1].LastModified.Should().BeExactly(startTime.AddHours(-hours).AddMinutes(-1));
-
- result.Unmatched.Should().NotBeEmpty();
+ result.Daily[1].LastModified.Should().BeExactly(startTime.AddHours(-startTime.Hour).AddMinutes(-1));
}
[Fact]
@@ -122,7 +143,7 @@ public void KeepDaily_WithPrevious_ShouldTake1()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 1, minutesPastHour, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(70, startTime, TimeSpan.FromMinutes(1));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
// Act
retentionSorter.KeepLast(1).KeepHourly(1);
diff --git a/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepHourly.cs b/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepHourly.cs
index f97e003..393534a 100644
--- a/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepHourly.cs
+++ b/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepHourly.cs
@@ -15,7 +15,7 @@ public void KeepHourly_WithZero_ShouldNotTake()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(15, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
int keep = 0;
// Act
@@ -41,7 +41,7 @@ public void KeepHourly_With1_ShouldTake1()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(15, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
int keep = 1;
// Act
@@ -72,7 +72,7 @@ public void KeepHourly_WithN_ShouldTakeN(int keep)
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 23, 59, 59, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(fileCount, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
// Act
retentionSorter.KeepHourly((uint)keep);
@@ -98,7 +98,7 @@ public void KeepHourly_WithMinuteIncrements_ShouldTake2()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 1, minutes, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(70, startTime, TimeSpan.FromMinutes(1));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
// Act
retentionSorter.KeepHourly(2);
@@ -122,7 +122,7 @@ public void KeepHourly_WithPrevious_ShouldTake1()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 1, minutesPastHour, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(70, startTime, TimeSpan.FromMinutes(1));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
// Act
retentionSorter.KeepLast(1).KeepHourly(1);
diff --git a/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepLast.cs b/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepLast.cs
index e67240c..be7d5ff 100644
--- a/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepLast.cs
+++ b/tests/Tests/RetentionSorterTests/RetentionSorterTests.KeepLast.cs
@@ -15,7 +15,7 @@ public void KeepLast_WithZero_ShouldNotTake()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(15, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
int keep = 0;
// Act
@@ -41,7 +41,7 @@ public void KeepLast_With1_ShouldTake1()
DateTimeOffset startTime = new DateTimeOffset(2023, 1, 1, 0, 0, 0, TimeSpan.Zero);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(15, startTime, TimeSpan.FromMinutes(15));
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
int keep = 1;
// Act
@@ -73,7 +73,7 @@ public void KeepLast_WithN_ShouldTakeN(int keep)
TimeSpan timeBetween = TimeSpan.FromMinutes(15);
IEnumerable files = FileInfoMockFactory.GetFileInfoCollectionFake(fileCount, startTime, timeBetween);
- RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files);
+ RetentionSorter retentionSorter = new RetentionSorter(consoleLoggerMock.Object, files, TimeSpan.Zero);
// Act
retentionSorter.KeepLast((uint)keep);
diff --git a/tests/Tests/RetentionSorterTests/RetentionSorterTests.cs b/tests/Tests/RetentionSorterTests/RetentionSorterTests.cs
index ea45b92..4a1be5f 100644
--- a/tests/Tests/RetentionSorterTests/RetentionSorterTests.cs
+++ b/tests/Tests/RetentionSorterTests/RetentionSorterTests.cs
@@ -112,7 +112,7 @@ private void RunSimulation(int keepLast, int keepHourly, int keepDaily, int keep
.Concat(result.Daily).Concat(result.Weekly)
.Concat(result.Monthly).Concat(result.Yearly);
- RetentionSorter sorter = new RetentionSorter(consoleLoggerMock.Object, retained);
+ RetentionSorter sorter = new RetentionSorter(consoleLoggerMock.Object, retained, TimeSpan.Zero);
sorter.KeepLast((uint)keepLast).KeepHourly((uint)keepHourly)
.KeepDaily((uint)keepDaily).KeepWeekly((uint)keepWeekly)
.KeepMonthly((uint)keepMonthly).KeepYearly((uint)keepYearly);