edge-install/ReleaseData/ReleaseData.cs
Robert Morrison 4a959c53ea
evil commit
catch up repo to code status
2023-07-05 23:07:39 +01:00

141 lines
4.8 KiB
C#

// TODO: Refactor to be more like Package code. This is messy
// Substring should be replaced with a .split(": ")
// Also Directly assign to the values instead of using temporary variables.
using Serilog;
namespace EdgeInstaller;
public sealed partial class ReleaseData
{
public DateTime Date { get; private set; }
public List<string> Architectures { get; private set; }
public List<PackageFile> PackageFiles { get; private set; }
public ReleaseData(string Release)
{
Log.Information("Creating new ReleaseData object");
if (Release == "")
{
throw new ArgumentException(
message: "Empty release provided to ReleaseData",
paramName: "Release");
}
// Pull release apart
List<string> ReleaseLines = Release.Split("\n", StringSplitOptions.RemoveEmptyEntries).ToList();
Log.Debug("ReleaseLines = {@releaselines}", ReleaseLines);
Date = DateTime.Parse(
ReleaseLines.Where(
Line => Line.Contains("Date:"))
.First()
.Split(": ")
.Last()
);
// Safely find and add the possible architectures
string ArchitecturesLine =
ReleaseLines.Where(
Line => Line.Contains("Architectures:"))
.FirstOrDefault("");
Log.Debug("Arch line: {archline}", ArchitecturesLine);
if (ArchitecturesLine == "")
{
throw _lineFormatException("architectures");
}
Architectures = ArchitecturesLine
.Split(": ").Last() // We only want items after the label
.Split(" ", StringSplitOptions.RemoveEmptyEntries)
.ToList();
// Cope with files being in binary-arch sometimes.
List<string> BinArchs = new();
foreach (var arch in Architectures)
{
BinArchs.Add("binary-" + arch);
}
Architectures.AddRange(BinArchs);
Log.Debug("Extracted architectures {@architectures}", Architectures);
/*
* Package files are grabbed here. It is worth noting that empty files
* are removed (along with the .gz versions) this avoids displaying impossible
* options to the user
*/
// First split the Lines to only get the file data
// NOTE: This is probably the cleanest way to do this.
List<string> SHA256FileData = ReleaseLines.Where((_, index) =>
index > ReleaseLines.IndexOf("SHA256:") &&
index < ReleaseLines.IndexOf("SHA512:")
).ToList();
Log.Debug("SHA256FileData = {@data}", SHA256FileData);
// Now process these lines to get the data we need
List<PackageFile> releasePackageFiles = new();
foreach (var fileData in SHA256FileData)
{
Log.Debug("fileData = {filedata}", fileData);
string[] splitData = fileData.Split(' ', StringSplitOptions.RemoveEmptyEntries);
Log.Debug("splitData = {@splitData}", splitData);
string checksum = splitData[0];
int size = int.Parse(splitData[1]);
string filename = splitData[2];
releasePackageFiles.Add(new PackageFile(filename, checksum, size));
}
// remove any empty files (and the .gz version of them)
// NOTE: Empty gz files still have a size due to headers
// WARN: The `.ToList` is essential to ensure we COPY the list and not use references to the original items
var emptyFiles = releasePackageFiles
.Where(package => package.size == 0)
.ToList();
foreach (var file in emptyFiles)
{
releasePackageFiles
.RemoveAll(package =>
package.filename == file.filename ||
package.filename == $"{file.filename}.gz"
);
}
PackageFiles = releasePackageFiles;
// After removing the empty files we need to make sure that we remove the architectures that don't have any files
foreach (var arch in Architectures.ToList())
/*
* WARN: `.ToList` is used again to copy the list so we can iterate and operate
* on the list at the same time. This could be unsafe, but in this scenario
* should never cause any issues.
*/
{
if (PackageFiles.Where(file => file.filename.Contains($"main/{arch}/")).Count() == 0) // match on "/arch/"
{
Log.Debug("removing /{arch}/", arch);
Architectures.Remove(arch);
}
}
if (Architectures.Count == 0)
{
throw new Exception("Architectures is null");
}
}
private static FormatException _lineFormatException(string field)
{
return new FormatException($"Release does not contain a valid {field} line");
}
}
public record PackageFile(string filename, string Checksum, int size);