Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
pd-buildserver committed Dec 12, 2023
2 parents 819f793 + a97dbce commit c0e8ea7
Show file tree
Hide file tree
Showing 28 changed files with 258 additions and 83 deletions.
15 changes: 10 additions & 5 deletions src/Tetrifact.Core/ArchiveService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,19 @@ public int GetPackageArchiveStatus(string packageId)
string archivePath = this.GetPackageArchivePath(packageId);
string temptPath = this.GetPackageArchiveTempPath(packageId);

// archive doesn't exist and isn't being created
if (!_fileSystem.File.Exists(archivePath) && !_fileSystem.File.Exists(temptPath))
return 0;
bool archiveExists = _fileSystem.File.Exists(archivePath);
bool archiveTemptExists = _fileSystem.File.Exists(temptPath);

// archive exists already
if (archiveExists)
return 2;

if (_fileSystem.File.Exists(temptPath))
// archive is being created
if (archiveTemptExists)
return 1;

return 2;
// neither archive nor temp file exists
return 0;
}

/// <summary>
Expand Down
122 changes: 122 additions & 0 deletions src/Tetrifact.Core/DateTimeSpanExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
using System;

namespace Tetrifact.Core
{
/// <summary>
/// Extensions for datetime and timespan
/// </summary>
public static class DateTimeSpanExtensions
{
public static string Ago(this DateTime? beforeUtc)
{
if (beforeUtc == null)
return string.Empty;

return _agoLocalTime(beforeUtc.Value);
}

public static string ToIso(this DateTime date)
{
string iso = date
.ToLocalTime()
.ToString("s") // convert to ymdhms
.Replace("T", " "); // replace T after ymd

return iso
.Substring(0, iso.Length - 3); // remove sec
}

public static string ToHumanString(this TimeSpan ts, bool shorten = false)
{
return _ago(ts, shorten);
}

public static string ToHumanString(this TimeSpan? ts, bool shorten = false)
{
if (ts == null)
return string.Empty;
return _ago(ts.Value, shorten);
}

public static string Ago(this DateTime beforeUtc, bool shorten = false)
{
return _agoLocalTime(beforeUtc, shorten);
}

private static string _agoLocalTime(DateTime beforeUtc, bool shorten = false)
{
return _ago(DateTime.Now.ToLocalTime() - beforeUtc.ToLocalTime(), shorten);
}

private static string _ago(TimeSpan ts, bool shorten)
{
int count = 0;
string unit = string.Empty;
string pluralMod = string.Empty;
if (ts.TotalDays > 364)
{
count = (int)Math.Round(ts.TotalDays / 364, 0);
unit = shorten ? "y" : "year";
pluralMod = shorten ? string.Empty : "s";
return $"{count} {unit}" + (count == 1 ? "" : pluralMod);
}

if (ts.TotalHours >= 24)
{
count = (int)Math.Round(ts.TotalDays, 0);
unit = shorten ? "d" : "day";
pluralMod = shorten ? string.Empty : "s";
return $"{count} {unit}" + (count == 1 ? "" : pluralMod);
}

if (ts.TotalMinutes >= 60)
{
count = (int)Math.Round(ts.TotalHours, 0);
unit = shorten ? "h" : "hour";
pluralMod = shorten ? string.Empty : "s";
return $"{count} {unit}" + (count == 1 ? "" : pluralMod);
}

if (ts.TotalSeconds >= 60)
{
count = (int)Math.Round(ts.TotalMinutes, 0);
unit = shorten ? "m" : "minute";
pluralMod = shorten ? string.Empty : "s";
return $"{count} {unit}" + (count == 1 ? "" : pluralMod);
}

count = (int)Math.Round(ts.TotalSeconds, 0);
unit = shorten ? "s" : "second";
pluralMod = shorten ? string.Empty : "s";
return $"{count} {unit}" + (count == 1 ? "" : pluralMod);
}

/// <summary>
/// Generates a human-friendly date in in local time. Assumes input is UTC.
/// </summary>
/// <param name="dateUtc"></param>
/// <param name="shorten"></param>
/// <returns></returns>
public static string ToHumanString(this DateTime dateUtc, bool shorten = true)
{
DateTime date = dateUtc.ToLocalTime();
string format = "yy-MM-dd HH:mm";
// for date great than a day since, we don't care about time
if (shorten && (DateTime.Now.ToLocalTime() - date).TotalHours > 24)
format = "yy-MM-dd";

string shortened = date.ToString(format)
.Replace(".", ":"); // .net in its infinite stupidity ignores the ":" in the format string and forces fullstops, replace those

return shortened;
}

public static string ToHumanString(this DateTime? dateUtc)
{
if (!dateUtc.HasValue)
return string.Empty;

return ToHumanString(dateUtc.Value);
}
}
}
40 changes: 20 additions & 20 deletions src/Tetrifact.Core/IndexReadService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ public void Initialize()
Directory.CreateDirectory(_settings.PackageDiffsPath);
}

public bool PackageExists(string packageId)
bool IIndexReadService.PackageExists(string packageId)
{
return this.GetManifest(packageId) != null;
return ((IIndexReadService)this).GetManifest(packageId) != null;
}

public void WriteManifest(string packageId, Manifest manifest)
void IIndexReadService.WriteManifest(string packageId, Manifest manifest)
{
string targetFolder = Path.Join(_settings.PackagePath, packageId);
string packageTempPath = Path.Join(targetFolder, "~manifest.json");
Expand Down Expand Up @@ -94,7 +94,7 @@ public void WriteManifest(string packageId, Manifest manifest)
_fileSystem.File.Move(packageHeadTempPath, packageHeadPath);
}

public void UpdatePackageCreateDate(string packageId, string createdUtcDate)
void IIndexReadService.UpdatePackageCreateDate(string packageId, string createdUtcDate)
{
DateTime created;

Expand All @@ -107,37 +107,37 @@ public void UpdatePackageCreateDate(string packageId, string createdUtcDate)
throw new FormatException($"{createdUtcDate} could not be parsed into a datetime");
}

Manifest manifest = this.GetManifest(packageId);
Manifest manifest = ((IIndexReadService)this).GetManifest(packageId);
if (manifest == null)
throw new PackageNotFoundException(packageId);

manifest.CreatedUtc = created;

this.WriteManifest(packageId, manifest);
((IIndexReadService)this).WriteManifest(packageId, manifest);
}

public IEnumerable<string> GetAllPackageIds()
IEnumerable<string> IIndexReadService.GetAllPackageIds()
{
IEnumerable<string> rawList = _fileSystem.Directory.GetDirectories(_settings.PackagePath);
return rawList.Select(r => Path.GetFileName(r));
}

public bool PackageNameInUse(string id)
bool IIndexReadService.PackageNameInUse(string id)
{
string packagePath = Path.Join(_settings.PackagePath, id);
return _fileSystem.Directory.Exists(packagePath);
}

public virtual Manifest GetExpectedManifest(string packageId)
Manifest IIndexReadService.GetExpectedManifest(string packageId)
{
Manifest manifest = this.GetManifest(packageId);
Manifest manifest = ((IIndexReadService)this).GetManifest(packageId);
if (manifest == null)
throw new PackageNotFoundException(packageId);

return manifest;
}

public virtual FileOnDiskProperties GetRepositoryFileProperties(string path, string hash)
FileOnDiskProperties IIndexReadService.GetRepositoryFileProperties(string path, string hash)
{
string filePath = Path.Join(_settings.RepositoryPath, path, hash, "bin");
if (!File.Exists(filePath))
Expand All @@ -148,12 +148,12 @@ public virtual FileOnDiskProperties GetRepositoryFileProperties(string path, str
return new FileOnDiskProperties { Hash = hash, Size = fileInfo.Length };
}

public virtual Manifest GetManifest(string packageId)
Manifest IIndexReadService.GetManifest(string packageId)
{
return this.GetManifest(packageId, "manifest.json");
}

public virtual Manifest GetManifestHead(string packageId)
Manifest IIndexReadService.GetManifestHead(string packageId)
{
return this.GetManifest(packageId, "manifest-head.json");
}
Expand All @@ -180,7 +180,7 @@ private Manifest GetManifest(string packageId, string type)
}
}

public GetFileResponse GetFile(string id)
GetFileResponse IIndexReadService.GetFile(string id)
{
FileIdentifier fileIdentifier = FileIdentifier.Decloak(id);
string directFilePath = Path.Combine(_settings.RepositoryPath, fileIdentifier.Path, fileIdentifier.Hash, "bin");
Expand All @@ -191,9 +191,9 @@ public GetFileResponse GetFile(string id)
return null;
}

public (bool, string) VerifyPackage(string packageId)
(bool, string) IIndexReadService.VerifyPackage(string packageId)
{
Manifest manifest = this.GetManifest(packageId);
Manifest manifest = ((IIndexReadService)this).GetManifest(packageId);
if (manifest == null)
throw new PackageNotFoundException(packageId);

Expand Down Expand Up @@ -230,12 +230,12 @@ public GetFileResponse GetFile(string id)
return (true, string.Empty);
}

public virtual void DeletePackage(string packageId)
void IIndexReadService.DeletePackage(string packageId)
{
if (!_settings.AllowPackageDelete)
throw new OperationNowAllowedException();

Manifest manifest = this.GetManifest(packageId);
Manifest manifest = ((IIndexReadService)this).GetManifest(packageId);
if (manifest == null)
throw new PackageNotFoundException(packageId);

Expand Down Expand Up @@ -290,7 +290,7 @@ public virtual void DeletePackage(string packageId)
}
}

public DiskUseStats GetDiskUseSats()
DiskUseStats IIndexReadService.GetDiskUseSats()
{
string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
DriveInfo drive = new DriveInfo(path);
Expand All @@ -302,7 +302,7 @@ public DiskUseStats GetDiskUseSats()
return stats;
}

public PartialPackageLookupResult FindExisting(PartialPackageLookupArguments newPackage)
PartialPackageLookupResult IIndexReadService.FindExisting(PartialPackageLookupArguments newPackage)
{
IList<ManifestItem> existing = new List<ManifestItem>();

Expand Down
3 changes: 1 addition & 2 deletions src/Tetrifact.Core/LinqExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ public static class LINQExtension
/// <returns></returns>
public static bool IsSubsetOf<T>(this ICollection<T> mainCollection, ICollection<T> subCollection)
{
bool isSubset = !mainCollection.Except(subCollection).Any();
return isSubset;
return !mainCollection.Except(subCollection).Any();
}

}
Expand Down
8 changes: 4 additions & 4 deletions src/Tetrifact.Core/PackagePruneService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ public PruneReport Report()
bool isTaggedKeep = manifest.Tags.Any(tag => _settings.PruneIgnoreTags.Any(protectedTag => protectedTag.Equals(tag)));
string flattenedTags = manifest.Tags.Count == 0 ? string.Empty : $"Tags : {string.Join(",", manifest.Tags)}";
int ageInDays = (int)Math.Round((utcNow - manifest.CreatedUtc).TotalDays, 0);
report.Add($"- {packageId}, added {TimeHelper.ToIsoString(manifest.CreatedUtc)} ({ageInDays}) days ago). {flattenedTags}");
report.Add($"- {packageId}, added {manifest.CreatedUtc.ToIso()} ({ageInDays}) days ago). {flattenedTags}");

if (isTaggedKeep){
taggedKeep.Add(packageId);
Expand Down Expand Up @@ -188,9 +188,9 @@ public PruneReport Report()
report.Add($"Pre-weekly ignore count is {newKeep.Count()} - {string.Join(",", newKeep)}");
if (taggedKeep.Count > 0)
report.Add($"Kept due to tagging - {string.Join(",", taggedKeep)}.");
report.Add($"WEEKLY prune (before {TimeHelper.ToIsoString(weeklyPruneFloor)}, {_settings.PruneWeeklyThreshold} days ago) count is {_settings.PruneWeeklyKeep}. Keeping {weeklyKeep.Count()} of {inWeeky}. {string.Join(",", weeklyKeep)}{weeklyPruneFlattened}.");
report.Add($"MONTHLY prune (before {TimeHelper.ToIsoString(monthlyPruneFloor)}, {_settings.PruneMonthlyThreshold} days ago) count is {_settings.PruneMonthlyKeep}. Keeping {monthlyKeep.Count()} of {inMonthly}. {string.Join(",", monthlyKeep)}{monthlyPruneFlattened}.");
report.Add($"YEARLY prune (before {TimeHelper.ToIsoString(yearlyPruneFloor)}, {_settings.PruneYearlyThreshold} days ago) count is {_settings.PruneYearlyKeep}. Keeping {yearlyKeep.Count()} of {inYearly}. {string.Join(",", yearlyKeep)}{yearlyPruneFlattened}.");
report.Add($"WEEKLY prune (before {weeklyPruneFloor.ToIso()}, {_settings.PruneWeeklyThreshold} days ago) count is {_settings.PruneWeeklyKeep}. Keeping {weeklyKeep.Count()} of {inWeeky}. {string.Join(",", weeklyKeep)}{weeklyPruneFlattened}.");
report.Add($"MONTHLY prune (before {monthlyPruneFloor.ToIso()}, {_settings.PruneMonthlyThreshold} days ago) count is {_settings.PruneMonthlyKeep}. Keeping {monthlyKeep.Count()} of {inMonthly}. {string.Join(",", monthlyKeep)}{monthlyPruneFlattened}.");
report.Add($"YEARLY prune (before {yearlyPruneFloor.ToIso()}, {_settings.PruneYearlyThreshold} days ago) count is {_settings.PruneYearlyKeep}. Keeping {yearlyKeep.Count()} of {inYearly}. {string.Join(",", yearlyKeep)}{yearlyPruneFlattened}.");
report.Add(string.Empty);
report.Add($"Pruning {packageIds.Count} packages{pruneIdList}.");
report.Add(" ******************************** Prune audit **********************************");
Expand Down
3 changes: 3 additions & 0 deletions src/Tetrifact.Core/PageableData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class PageableData<T>

public PageableData(IEnumerable<T> items, int pageIndex, int pageSize, long virtualItemCount)
{
if (pageSize == 0)
throw new Exception("PageableData page size cannot be zero, will divide overflow. Set to at least 1.");

this.Items = items;
this.PageSize = pageSize;
this.PageIndex = pageIndex;
Expand Down
18 changes: 0 additions & 18 deletions src/Tetrifact.Core/TimeHelper.cs

This file was deleted.

31 changes: 26 additions & 5 deletions src/Tetrifact.Tests/Core/ArchiveService/GetPackageArchiveStatus.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.IO;
using Moq;
using System.IO;
using System.IO.Abstractions;
using Tetrifact.Core;
using Xunit;

Expand All @@ -12,17 +14,36 @@ public class GetPackageArchiveStatus : FileSystemBase
[Fact]
public void GetNonExistent()
{
Assert.Throws<PackageNotFoundException>(() => this.ArchiveService.GetPackageArchiveStatus("invalid-id"));
// mock a non-existent package
Mock<IIndexReadService> indexReader = new Mock<IIndexReadService>();
indexReader
.Setup(r => r.PackageExists(It.IsAny<string>()))
.Returns(false);

IArchiveService archiveService = MoqHelper.CreateInstanceWithDependencies<Core.ArchiveService>(new object[]{ base.Settings, indexReader });
Assert.Throws<PackageNotFoundException>(()=> archiveService.GetPackageArchiveStatus("invalid-id"));
}

/// <summary>
/// Archive create status should be 0 (started)
/// Archive create status should be 0 (starting) when neither archive exists, nor archive creation has started yet
/// </summary>
[Fact]
public void GetArchiveStarted()
{
TestPackage testPackage = PackageHelper.CreateNewPackage(this.Settings);
Assert.Equal(0, this.ArchiveService.GetPackageArchiveStatus(testPackage.Id));
// force package exists
Mock<IIndexReadService> indexReader = new Mock<IIndexReadService>();
indexReader
.Setup(r => r.PackageExists(It.IsAny<string>()))
.Returns(true);

// force filesystem to return false for all file checks (ie, archive + archive temp)
Mock<IFileSystem> filesystem = new Mock<IFileSystem>();
filesystem
.Setup(r => r.File.Exists(It.IsAny<string>()))
.Returns(false);

IArchiveService archiveService = MoqHelper.CreateInstanceWithDependencies<Core.ArchiveService>(new object[] { base.Settings, indexReader, filesystem });
Assert.Equal(0, archiveService.GetPackageArchiveStatus("any-package-id"));
}

/// <summary>
Expand Down
Loading

0 comments on commit c0e8ea7

Please sign in to comment.