Lots of changes here... - Removed code using RecursivExtractor due to bad usage of /tmp Note: the code that used RecursiveExtractor may not have been in the previous commit - Created _functioning_ implementation of DebUnpacker - Restructured Project layout. TODO: - Possibly rewrite how the DebUnpacker works to have the file contents part of an entry. - Further restructuring and refactoring to make the code a little neater. - Add code for the final unpack steps Un-XZ -> untar -> write to disk - Add code to install - Add code for modified post-install pre-remove etc.. This is kinda needed to ensure proper system integration of new packages.
129 lines
4.5 KiB
C#
129 lines
4.5 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();
|
|
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(arch)).Count() == 0)
|
|
{
|
|
Architectures.Remove(arch);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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);
|