diff --git a/Program.HelperFunctions.cs b/Program.HelperFunctions.cs index c9d9f8c..bcc87b2 100644 --- a/Program.HelperFunctions.cs +++ b/Program.HelperFunctions.cs @@ -61,6 +61,9 @@ public static partial class EdgeInstall static Version GetCurrentVersion() { + // To get the current version we need to execute the installed microsoft edge. + // Before doing this we need to make sure we can execute microsoft edge. + return new("0.0.0.0-0"); } diff --git a/Program.cs b/Program.cs index a4b8e0a..fc563bb 100644 --- a/Program.cs +++ b/Program.cs @@ -18,8 +18,7 @@ public static partial class EdgeInstall // The default architecture to get // likely will go unused until proper cli interface is added - private static readonly string _DefaultArch = "amd64"; - + //private static readonly string _DefaultArch = "amd64"; private static HttpClient _client = new HttpClient(); private static readonly string DataDir = @@ -31,13 +30,23 @@ public static partial class EdgeInstall public static async Task Main() { + if (Environment.OSVersion.Platform != PlatformID.Unix) + { + Console.ForegroundColor = Color.Red; + Console.Error.WriteLine("ERROR: You are not running this on a *nix host this program is not designed for other system types"); + Environment.Exit(1); + } + _client.BaseAddress = new Uri("https://packages.microsoft.com/repos/edge/"); // Ensure DataDir exists. // NOTE: Directory.CreateDirectory will ALWAYS create the entire path Directory.CreateDirectory(DataDir); - BUGFIX_ansiDetection(); + BUGFIX_ansiDetection(); // Ensure that Spectre.Console is forced to work properly. + + // TODO: Add code to change this based on profile + // And also allow changing at runtime based on flags Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .WriteTo.File(Path.Combine(DataDir, ".EdgeInstaller.Log")) // Only ever log to the logfile @@ -59,7 +68,7 @@ public static partial class EdgeInstall RenderReleaseTable(data); - // only select arch if needed + // Either prompt for architecture selection OR use th eonly one available string TargetArch = data.Architectures.Count > 1 ? AnsiConsole.Prompt( new SelectionPrompt() .Title("Choose Architecture") @@ -74,7 +83,6 @@ public static partial class EdgeInstall // Check if the Release data we just grabbed is newer than the one that exists. // NOTE: we only do this if our chosen architecture hasn't been downloaded - bool NeedDownload = true; Log.Information("Reached Package download Stage"); @@ -82,18 +90,20 @@ public static partial class EdgeInstall { Log.Information("Checking for release.json"); // we need to check the release since we have an existing package.gz - - string JSONstring = File.ReadAllText(Path.Combine(DataDir, "release.json")); - ReleaseData? oldData = JsonSerializer.Deserialize(JSONstring); - if (oldData is not null) - { - // if equal then our data is the newest available - if (DateTime.Compare(oldData.Date, data.Date) == 0) - { - Log.Information("Our packages.gz is up to date"); - NeedDownload = false; - } - } + if (File.Exists(Path.Combine(DataDir, "release.json"))) + { + string JSONstring = File.ReadAllText(Path.Combine(DataDir, "release.json")); + ReleaseData? oldData = JsonSerializer.Deserialize(JSONstring); + if (oldData is not null) + { + // if equal then our data is the newest available + if (DateTime.Compare(oldData.Date, data.Date) == 0) + { + Log.Information("Our packages.gz is up to date"); + NeedDownload = false; + } + } + } } @@ -130,12 +140,14 @@ public static partial class EdgeInstall }); string JSONdata = JsonSerializer.Serialize(data); - File.WriteAllText(Path.Combine(DataDir, "release.json"), JSONdata); if (!ValidateChecksum(new FileInfo(filename), gzFile.Checksum)) { + AnsiConsole.WriteLine("[red b]ERROR: Release data checksum invalid[]"); File.Delete(filename); Environment.Exit(1); } + File.WriteAllText(Path.Combine(DataDir, "release.json"), JSONdata); // only do this if what we downloaded was valid. + // Otherwise we will skip downloading in the future } string PackagesFile = Path.Combine(Archdir, "Packages.gz"); @@ -148,9 +160,11 @@ public static partial class EdgeInstall foreach (var line in PackagesString.Split('\n')) { + Log.Debug("PackageLine: {line}",line); if (line == "") { string PackageString = sb.ToString(); + Log.Debug("Making Package from:\n{PackageString}",PackageString); if (PackageString == "") { continue; // The last "package" will be empty @@ -275,59 +289,90 @@ public static partial class EdgeInstall Environment.Exit(1); } - using (XZStream dataXZStream = new(dataStream)) - { - using (TarReader reader = new(dataXZStream)) - { - while (true) - { - var tarEntry = reader.GetNextEntry(); - if (tarEntry is null) - { - break; // TarReader returns null when we hit the end of the stream - } + using (XZStream dataXZStream = new(dataStream)) + using (TarReader reader = new(dataXZStream)) + { + while (true) + { + var tarEntry = reader.GetNextEntry(); + if (tarEntry is null) + { + break; // TarReader returns null when we hit the end of the stream + } - AnsiConsole.MarkupLineInterpolated($"TarEntry {tarEntry.Name}"); - // work out where we need to put the extracted file - var filepath = Path.Combine(versionDir, tarEntry.Name); + AnsiConsole.MarkupLineInterpolated($"Extracting TarEntry {tarEntry.Name}"); + // work out where we need to put the extracted file + var filepath = Path.Combine(versionDir, tarEntry.Name); - if (tarEntry.EntryType == TarEntryType.Directory) - { - // createDirectory doesn't fail if already exists - Directory.CreateDirectory(filepath); - continue; - } + if (tarEntry.EntryType == TarEntryType.Directory) + { + // createDirectory doesn't fail if already exists + Directory.CreateDirectory(filepath); + continue; + } - if (tarEntry.LinkName != "") - { - // Handle links manually - if (File.Exists(filepath)) - { - File.Delete(filepath); - } - File.CreateSymbolicLink(filepath, tarEntry.LinkName); - continue; // we are done with this file so keep going - } + if (tarEntry.LinkName != "") + { + // Handle links manually + 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); - } - } - } + tarEntry.ExtractToFile(filepath, overwrite: true); + } + } - // 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(); } } + // Patch the startup program to allow using UserFlags + + string startScript = Path.Combine(versionDir , "opt/microsoft/msedge/microsoft-edge"); + Log.Information("Patching {startScript}",startScript); + using (var scriptStream = File.Open(startScript,FileMode.Open)) + using (var scriptRead = new StreamReader(scriptStream)) + using (var scriptWrite = new StreamWriter(scriptStream)) + { + var newscriptString = new StringBuilder(); + var currentScriptString = scriptRead.ReadToEnd(); + if (currentScriptString is null) + { + return 1; + } + + List currentScriptSplit = currentScriptString.Split("\n").ToList(); + currentScriptSplit.RemoveRange(currentScriptSplit.Count - 3,3); + currentScriptSplit.Add("if [ -r \"${XDG_CONFIG_HOME}/microsoft-edge-stable-flags.conf\" ]; then"); + currentScriptSplit.Add(" EDGE_USER_FLAGS=\"$(cat \"$XDG_CONFIG_HOME/microsoft-edge-stable-flags.conf\")\""); + currentScriptSplit.Add("fi"); + currentScriptSplit.Add(""); + currentScriptSplit.Add(""); + currentScriptSplit.Add("# Note: exec -a below is a bashism"); + currentScriptSplit.Add("exec -a \"$0\" \"$HERE/msedge\" $EDGE_USER_FLAGS \"$@\""); + newscriptString.AppendJoin("\n",currentScriptSplit); + scriptStream.Position = 0; + scriptStream.SetLength(0); + AnsiConsole.MarkupLineInterpolated($"[grey]{newscriptString.ToString()}[/]"); + scriptWrite.Write(newscriptString.ToString()); + scriptStream.Flush(); + } + + // 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 -drv {versionDir}/opt {versionDir}/usr /"; + Mover.UseShellExecute = true; + var pr = Process.Start(Mover); + pr?.WaitForExit(); + return 0; } @@ -335,7 +380,6 @@ public static partial class EdgeInstall - Check version - Offer update - Make SENSIBLE backup - - Do install = if install fails revert backup */ } diff --git a/Readme.md b/Readme.md index 579a3be..40d7cef 100644 --- a/Readme.md +++ b/Readme.md @@ -4,6 +4,5 @@ A dumb package manager, soon to be outfitted with the ability to fully extract .deb packages. ## TODO: -- Add archive extraction code - Add install functionality - Refactor some classes to make them neater diff --git a/ReleaseData/ReleaseData.cs b/ReleaseData/ReleaseData.cs index 0dbd002..a6ba766 100644 --- a/ReleaseData/ReleaseData.cs +++ b/ReleaseData/ReleaseData.cs @@ -51,6 +51,13 @@ public sealed partial class ReleaseData .Split(": ").Last() // We only want items after the label .Split(" ", StringSplitOptions.RemoveEmptyEntries) .ToList(); + // Cope with files being in binary-arch sometimes. + List BinArchs = new(); + foreach (var arch in Architectures) + { + BinArchs.Add("binary-" + arch); + } + Architectures.AddRange(BinArchs); Log.Debug("Extracted architectures {@architectures}", Architectures); @@ -109,11 +116,16 @@ public sealed partial class ReleaseData * should never cause any issues. */ { - if (PackageFiles.Where(file => file.filename.Contains(arch)).Count() == 0) + 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"); + } }