feat: Add installing

It can install now.
Requires pexec to be present

This may be due to an upstream issue with spectre.console affecting how
stdin/stdout are handled.

TODO:
 - Add backup/restore functionality
 - Refactor sections for neatness
 - Improve UX
This commit is contained in:
Robert Morrison 2023-06-08 11:22:00 +01:00
parent 60e06b2144
commit 79063f97ee
Signed by: robert
GPG Key ID: 73E012EB3F4EC696
3 changed files with 84 additions and 41 deletions

View File

@ -123,7 +123,7 @@ sealed class DebEntry
throw new ArgumentException("buffer too short"); throw new ArgumentException("buffer too short");
} }
name = Encoding.ASCII.GetString(buffer[0..16]); name = Encoding.ASCII.GetString(buffer[0..16]).Trim(); // Trim any trailing whitespace
mtime = long.Parse(Encoding.ASCII.GetString(buffer[16..28])); mtime = long.Parse(Encoding.ASCII.GetString(buffer[16..28]));
mode = int.Parse(Encoding.ASCII.GetString(buffer[28..34])); mode = int.Parse(Encoding.ASCII.GetString(buffer[28..34]));
gid = int.Parse(Encoding.ASCII.GetString(buffer[34..40])); gid = int.Parse(Encoding.ASCII.GetString(buffer[34..40]));

View File

@ -3,6 +3,9 @@ using Serilog;
using Spectre.Console; using Spectre.Console;
using System.Text.Json; using System.Text.Json;
using System.Text; using System.Text;
using SharpCompress.Compressors.Xz;
using System.Formats.Tar;
using System.Diagnostics;
namespace EdgeInstaller; namespace EdgeInstaller;
@ -222,71 +225,111 @@ public static partial class EdgeInstall
RenderPackageAsTable(LatestVersion); RenderPackageAsTable(LatestVersion);
var versionPath = LatestVersion.Filename
.Replace("pool/main/m/", "")
.Replace(".deb", "");
var versionsDir = Path.Join(Archdir, "Versions"); var versionsDir = Path.Join(Archdir, "Versions");
var versionDir = Path.Join(versionsDir, LatestVersion.PackageName, LatestVersion.Version.ToString());
Directory.CreateDirectory(versionDir);
// Let's get and unpack the latest version // Let's get and unpack the latest version
if (true)//!Directory.Exists(Path.Join(versionsDir, versionPath))) // for the moment we will always just grab
{ using (MemoryStream debStream =
using (MemoryStream debStream = await AnsiConsole.Progress()
await AnsiConsole.Progress() .Columns(new ProgressColumn[]
.Columns(new ProgressColumn[] {
{
new TaskDescriptionColumn(), new TaskDescriptionColumn(),
new ProgressBarColumn(), new ProgressBarColumn(),
new PercentageColumn(), new PercentageColumn(),
new RemainingTimeColumn(), new RemainingTimeColumn(),
new SpinnerColumn(), new SpinnerColumn(),
}) })
.StartAsync<MemoryStream>(async ctx => .StartAsync<MemoryStream>(async ctx =>
{ {
var task = ctx.AddTask(LatestVersion.Filename, new ProgressTaskSettings { AutoStart = false }); var task = ctx.AddTask(LatestVersion.Filename, new ProgressTaskSettings { AutoStart = false });
return await downloadStream(LatestVersion.Filename, task); return await downloadStream(LatestVersion.Filename, task);
})) }))
{
if (!ValidateChecksum(debStream, LatestVersion.SHA256))
{
AnsiConsole.MarkupLine("[red b]ERROR:[/] checksum did not validate");
Environment.Exit(1);
}
using (DebFile debfile = new DebFile(debStream))
{ {
if (!ValidateChecksum(debStream, LatestVersion.SHA256)) // NOTE: deb entries have trailing /
DebEntry? dataEntry = debfile.fileEntries.Find(file => file.name == "data.tar.xz/");
if (dataEntry is null)
{ {
AnsiConsole.MarkupLine("[red b]ERROR:[/] checksum did not validate"); AnsiConsole.MarkupLine("[red b]ERROR:[/] debfile does not contain data.tar.xz");
Environment.Exit(1); Environment.Exit(1);
} }
using (DebFile debfile = new DebFile(debStream)) // Looks like we have a hit. Lets try and extract it
if (!debfile.getFile(dataEntry, out Stream dataStream))
{ {
foreach (var fileEntry in debfile.fileEntries) AnsiConsole.MarkupLine("[red b]ERROR:[/] couldn't get stream for data.tar.xz");
Environment.Exit(1);
}
using (XZStream dataXZStream = new(dataStream))
{
using (TarReader reader = new(dataXZStream))
{ {
AnsiConsole.MarkupLineInterpolated($"FileName: {fileEntry.name}"); while (true)
AnsiConsole.MarkupLineInterpolated($"FilePos: {fileEntry.offset}");
AnsiConsole.MarkupLineInterpolated($"FileSize: {fileEntry.sizeBytes}");
// NOTE: This is dumb test code
// to verify the files are actually being "extracted" properly
if (!debfile.getFile(fileEntry, out Stream contents))
{ {
return 1; var tarEntry = reader.GetNextEntry();
} if (tarEntry is null)
{
break; // TarReader returns null when we hit the end of the stream
}
// Now we write this to tmp. AnsiConsole.MarkupLineInterpolated($"TarEntry {tarEntry.Name}");
// WARN: Without deleting these you will fill up your ram // work out where we need to put the extracted file
var filepath = Path.Combine(versionDir, tarEntry.Name);
var temp = Path.GetTempFileName(); if (tarEntry.EntryType == TarEntryType.Directory)
{
// createDirectory doesn't fail if already exists
Directory.CreateDirectory(filepath);
continue;
}
using (var tmpfile = File.Open(temp, FileMode.Open)) if (tarEntry.LinkName != "")
{ {
contents.CopyTo(tmpfile); // Handle links manually
contents.Dispose(); if (File.Exists(filepath))
{
File.Delete(filepath);
}
File.CreateSymbolicLink(filepath, tarEntry.LinkName);
continue; // we are done with this file so keep going
}
tarEntry.ExtractToFile(filepath, overwrite: true);
} }
} }
} }
}
return 0; // Now assuming nothing broke before now we can copy the files into the system directories.
// WARN: This is dangerous stuff and involves making system calls.
// NOTE: be sure when calling to other programs to wait until they exit.
var Mover = new ProcessStartInfo();
Mover.FileName = "pkexec";
Mover.Arguments = $"cp -dri {versionDir}/opt {versionDir}/usr /";
Mover.UseShellExecute = true;
var pr = Process.Start(Mover);
pr?.WaitForExit();
}
} }
return 0;
} }
/*TODO: /*TODO:
- Check version - Check version

View File

@ -9,9 +9,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CST.RecursiveExtractor" Version="1.2.13" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SharpCompress" Version="0.33.0" />
<PackageReference Include="Spectre.Console" Version="0.47.0" /> <PackageReference Include="Spectre.Console" Version="0.47.0" />
<PackageReference Include="System.Commandline" Version="2.0.0-beta4.22272.1" /> <PackageReference Include="System.Commandline" Version="2.0.0-beta4.22272.1" />
</ItemGroup> </ItemGroup>