diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..2858d472 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,78 @@ + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent + +[*.cs] +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_space_around_binary_operators = before_and_after \ No newline at end of file diff --git a/Program.cs b/Program.cs index 0c82a7be..99e512cd 100644 --- a/Program.cs +++ b/Program.cs @@ -1,6 +1,10 @@ -using pannella.analoguepocket; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Reflection; using System.Runtime.InteropServices; using CommandLine; +using pannella.analoguepocket; internal class Program { @@ -46,17 +50,17 @@ private static async Task Main(string[] args) cliMode = true; } } - ).WithNotParsed(o => - { - if(o.IsHelp()) { - Environment.Exit(1); - } - if(o.IsVersion()) { - Environment.Exit(1); - } + ).WithNotParsed(o => + { + if(o.IsHelp()) { + Environment.Exit(1); + } + if(o.IsVersion()) { + Environment.Exit(1); } + } ); - + //path = "/Users/mattpannella/pocket-test"; ConsoleKey response; @@ -65,11 +69,26 @@ private static async Task Main(string[] args) Console.WriteLine("Checking for updates..."); if(await CheckVersion(path)) { - Console.WriteLine("Would you like to continue anyway? [Y/n]:"); - response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N) { - Console.WriteLine("Come again soon"); - PauseExit(); + ConsoleKey[] acceptedInputs = new[] { ConsoleKey.I, ConsoleKey.C, ConsoleKey.Q }; + do { + Console.Write("Would you like to [i]nstall the update, [c]ontinue with the current version, or [q]uit? [i/c/q]: "); + response = Console.ReadKey(false).Key; + Console.WriteLine(); + } while(!acceptedInputs.Contains(response)); + + switch(response) { + case ConsoleKey.I: + int result = UpdateSelfAndRun(path, args); + Environment.Exit(result); + break; + + case ConsoleKey.C: + break; + + case ConsoleKey.Q: + Console.WriteLine("Come again soon"); + PauseExit(); + break; } } @@ -91,7 +110,7 @@ private static async Task Main(string[] args) if(coreSelector || settings.GetConfig().core_selector) { settings.EnableMissingCores(updater.GetMissingCores()); - List cores = await CoresService.GetCores(); + List cores = await CoresService.GetCores(); AskAboutNewCores(ref settings, true); RunCoreSelector(ref settings, cores); updater.LoadSettings(); @@ -103,7 +122,7 @@ private static async Task Main(string[] args) AskAboutNewCores(ref settings); string? download_new_cores = settings.GetConfig().download_new_cores?.ToLowerInvariant(); - switch (download_new_cores) { + switch(download_new_cores) { case "yes": Console.WriteLine("The following cores have been enabled:"); foreach(Core core in updater.GetMissingCores()) @@ -154,7 +173,7 @@ private static async Task Main(string[] args) Pause(); break; case 3: - List cores = await CoresService.GetCores(); + List cores = await CoresService.GetCores(); AskAboutNewCores(ref settings, true); RunCoreSelector(ref settings, cores); updater.LoadSettings(); @@ -186,13 +205,56 @@ private static async Task Main(string[] args) } } } - } catch (Exception e) { + } catch(Exception e) { Console.WriteLine("Well, something went wrong. Sorry about that."); Console.WriteLine(e.Message); Pause(); } } + private static int UpdateSelfAndRun(string directory, string[] updaterArgs) + { + string execName = "pocket_updater"; + if(GetPlatform() == "win") { + execName += ".exe"; + } + string execLocation = Path.Combine(directory, execName); + string backupName = $"{execName}.backup"; + string backupLocation = Path.Combine(directory, backupName); + string updateName = "pocket_updater.zip"; + string updateLocation = Path.Combine(directory, updateName); + + int exitcode = int.MinValue; + + try { + // Load System.IO.Compression now + Assembly.Load("System.IO.Compression"); + + // Move current process file + Console.WriteLine($"Renaming {execLocation} to {backupLocation}"); + File.Move(execLocation, backupLocation, true); + + // Extract update + Console.WriteLine($"Extracting {updateLocation} to {directory}"); + ZipFile.ExtractToDirectory(updateLocation, directory, true); + + // Execute + Console.WriteLine($"Executing {execLocation}"); + ProcessStartInfo pInfo = new ProcessStartInfo(execLocation) { + Arguments = string.Join(' ', updaterArgs), + UseShellExecute = false + }; + + Process p = Process.Start(pInfo); + p.WaitForExit(); + exitcode = p.ExitCode; + } catch(Exception e) { + Console.Error.WriteLine($"An error occurred: {e.GetType().Name}:{e.ToString()}"); + } + + return exitcode; + } + static void SetUpdaterFlags(ref PocketCoreUpdater updater, ref SettingsManager settings) { updater.DeleteSkippedCores(settings.GetConfig().delete_skipped_cores); @@ -209,7 +271,7 @@ static async Task RunInstanceGenerator(PocketCoreUpdater updater, bool force = f Console.Write("Do you want to overwrite existing json files? [y/N] "); Console.WriteLine(""); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.Y) { + if(response == ConsoleKey.Y) { force = true; } } @@ -227,7 +289,7 @@ static void RunCoreSelector(ref SettingsManager settings, List cores) foreach(Core core in cores) { Console.Write(core.identifier + "?[Y/n] "); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N) { + if(response == ConsoleKey.N) { settings.DisableCore(core.identifier); } else { settings.EnableCore(core.identifier); @@ -246,10 +308,10 @@ static void RunConfigWizard(ref SettingsManager settings) while(!valid) { Console.Write("\nDownload Firmware Updates during 'Update All'?[Y/n] "); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N) { + if(response == ConsoleKey.N) { settings.GetConfig().download_firmware = false; valid = true; - } else if (response == ConsoleKey.Y || response == ConsoleKey.Enter) { + } else if(response == ConsoleKey.Y || response == ConsoleKey.Enter) { settings.GetConfig().download_firmware = true; valid = true; } @@ -259,10 +321,10 @@ static void RunConfigWizard(ref SettingsManager settings) while(!valid) { Console.Write("\nDownload Missing Assets (ROMs and BIOS Files) during 'Update All'?[Y/n] "); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N) { + if(response == ConsoleKey.N) { settings.GetConfig().download_assets = false; valid = true; - } else if (response == ConsoleKey.Y || response == ConsoleKey.Enter) { + } else if(response == ConsoleKey.Y || response == ConsoleKey.Enter) { settings.GetConfig().download_assets = true; valid = true; } @@ -272,10 +334,10 @@ static void RunConfigWizard(ref SettingsManager settings) while(!valid) { Console.Write("\nBuild game JSON files for supported cores during 'Update All'?[Y/n] "); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N) { + if(response == ConsoleKey.N) { settings.GetConfig().build_instance_jsons = false; valid = true; - } else if (response == ConsoleKey.Y || response == ConsoleKey.Enter) { + } else if(response == ConsoleKey.Y || response == ConsoleKey.Enter) { settings.GetConfig().build_instance_jsons = true; valid = true; } @@ -285,10 +347,10 @@ static void RunConfigWizard(ref SettingsManager settings) while(!valid) { Console.Write("\nDelete untracked cores during 'Update All'?[Y/n] "); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N) { + if(response == ConsoleKey.N) { settings.GetConfig().delete_skipped_cores = false; valid = true; - } else if (response == ConsoleKey.Y || response == ConsoleKey.Enter) { + } else if(response == ConsoleKey.Y || response == ConsoleKey.Enter) { settings.GetConfig().delete_skipped_cores = true; valid = true; } @@ -311,10 +373,10 @@ static void RunConfigWizard(ref SettingsManager settings) while(!valid) { Console.Write("\nPreserve 'Platforms' folder during 'Update All'?[y/N] "); response = Console.ReadKey(false).Key; - if (response == ConsoleKey.N || response == ConsoleKey.Enter) { + if(response == ConsoleKey.N || response == ConsoleKey.Enter) { settings.GetConfig().preserve_platforms_folder = false; valid = true; - } else if (response == ConsoleKey.Y) { + } else if(response == ConsoleKey.Y) { settings.GetConfig().preserve_platforms_folder = true; valid = true; } @@ -362,7 +424,7 @@ static void updater_UpdateProcessComplete(object sender, UpdateProcessCompleteEv Console.WriteLine("we did it, come again soon"); } - //return true if newer version is available + //return true if newer version is available async static Task CheckVersion(string path) { try { @@ -386,7 +448,7 @@ async static Task CheckVersion(string path) } return false; - } catch (HttpRequestException e) { + } catch(HttpRequestException e) { return false; } } @@ -398,22 +460,21 @@ async static Task AutoUpdateCheckVersion(string path) string tempExecutable = Path.Combine(path, "update_temp.exe"); // We can only delete after the old one is done running. - if (File.Exists(tempExecutable)) { + if(File.Exists(tempExecutable)) { File.Delete(tempExecutable); } string? tagName, updateVersion, htmlUrl; // Get the available updates - try - { + try { List releases = await GithubApi.GetReleases(USER, REPOSITORY); tagName = releases[0].tag_name; updateVersion = SemverUtil.FindSemver(tagName); htmlUrl = releases[0].html_url; - if (tagName == null || updateVersion == null || htmlUrl == null) { + if(tagName == null || updateVersion == null || htmlUrl == null) { throw new Exception(); } } catch { @@ -422,7 +483,7 @@ async static Task AutoUpdateCheckVersion(string path) } // Check if we actually need to update - if (!SemverUtil.SemverCompare(updateVersion, version)) { + if(!SemverUtil.SemverCompare(updateVersion, version)) { Console.WriteLine("No new version found."); return; } @@ -455,7 +516,7 @@ async static Task AutoUpdateCheckVersion(string path) try { System.IO.Compression.ZipFile.ExtractToDirectory(saveLocation, path); - if (!File.Exists(updatedExecutable)) { + if(!File.Exists(updatedExecutable)) { throw new Exception(); } } catch { @@ -471,8 +532,7 @@ async static Task AutoUpdateCheckVersion(string path) var process = System.Diagnostics.Process.Start(updatedExecutable); // stdin only stays connected on Windows, wait on other platforms - if (platform != "win") - { + if(platform != "win") { // Can't do this on Windows because then deleting the old executable from the new one will fail process.WaitForExit(); } @@ -514,14 +574,14 @@ __ __ _ _ ______ _ "; Console.WriteLine(welcome); - - foreach(var(item, index) in menuItems.WithIndex()) { + + foreach(var (item, index) in menuItems.WithIndex()) { Console.WriteLine($"{index}) {item}"); } Console.Write("\nChoose your destiny: "); int choice; bool result = int.TryParse(Console.ReadLine(), out choice); - if (result) { + if(result) { return choice; } return 0; @@ -531,16 +591,16 @@ private static async Task ImagePackSelector(string path) { Console.Clear(); Console.WriteLine("Checking for image packs...\n"); - ImagePack[] packs = await ImagePacksService.GetImagePacks(); + ImagePack[] packs = await ImagePacksService.GetImagePacks(); if(packs.Length > 0) { - foreach(var(pack, index) in packs.WithIndex()) { + foreach(var (pack, index) in packs.WithIndex()) { Console.WriteLine($"{index}) {pack.owner}: {pack.repository} {pack.variant}"); } Console.WriteLine($"{packs.Length}) Go back"); Console.Write("\nSo, what'll it be?: "); int choice; bool result = int.TryParse(Console.ReadLine(), out choice); - if (result && choice < packs.Length && choice >= 0) { + if(result && choice < packs.Length && choice >= 0) { await InstallImagePack(path, packs[choice]); Pause(); } else if(choice == packs.Length) { @@ -562,10 +622,10 @@ private static async Task InstallImagePack(string path, ImagePack pack) //await installImagePack(path, filepath); } - private static void PauseExit() + private static void PauseExit(int exitcode = 0) { Console.ReadLine(); //wait for input so the console doesn't auto close in windows - Environment.Exit(1); + Environment.Exit(exitcode); } private static void Pause() @@ -581,8 +641,7 @@ private static void AskAboutNewCores(ref SettingsManager settings, bool force = Console.WriteLine("Would you like to, by default, install new cores? [Y]es, [N]o, [A]sk for each:"); ConsoleKey response = Console.ReadKey(false).Key; - settings.GetConfig().download_new_cores = response switch - { + settings.GetConfig().download_new_cores = response switch { ConsoleKey.Y => "yes", ConsoleKey.N => "no", ConsoleKey.A => "ask", @@ -613,14 +672,15 @@ public class Options [Option ('c', "coreselector", Required = false, HelpText = "Run the core selector.")] public bool CoreSelector { get; set; } - [Option ('f', "platformsfolder", Required = false, HelpText = "Preserve the Platforms folder, so customizations aren't overwritten by updates.")] + [Option('f', "platformsfolder", Required = false, HelpText = "Preserve the Platforms folder, so customizations aren't overwritten by updates.")] public bool PreservePlatformsFolder { get; set; } [Option('i', "instancegenerator", HelpText = "Force updater to just run instance json generator, instead of displaying the menu.", Required = false)] public bool ForceInstanceGenerator { get; set; } } -public static class EnumExtension { - public static IEnumerable<(T item, int index)> WithIndex(this IEnumerable self) +public static class EnumExtension +{ + public static IEnumerable<(T item, int index)> WithIndex(this IEnumerable self) => self.Select((item, index) => (item, index)); -} \ No newline at end of file +} diff --git a/pocket_updater.csproj b/pocket_updater.csproj index e9c5d82a..c19780d4 100644 --- a/pocket_updater.csproj +++ b/pocket_updater.csproj @@ -1,4 +1,4 @@ - + true Exe @@ -14,7 +14,13 @@ https://github.com/mattpannella/pocket-updater-utility - - + + + + + + + + \ No newline at end of file