From f72f960c4faff1116798283922f543891280e1e2 Mon Sep 17 00:00:00 2001 From: Noam Zaks Date: Sun, 2 May 2021 11:49:03 +0300 Subject: [PATCH 1/4] Started implementing CLI --- WPILibInstaller-Avalonia/CLI/Installer.cs | 101 ++++++++++++++++++++++ WPILibInstaller-Avalonia/Program.cs | 8 +- 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 WPILibInstaller-Avalonia/CLI/Installer.cs diff --git a/WPILibInstaller-Avalonia/CLI/Installer.cs b/WPILibInstaller-Avalonia/CLI/Installer.cs new file mode 100644 index 00000000..26a2e833 --- /dev/null +++ b/WPILibInstaller-Avalonia/CLI/Installer.cs @@ -0,0 +1,101 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Threading.Tasks; +using WPILibInstaller.Interfaces; +using WPILibInstaller.Models; +using WPILibInstaller.Utils; + +namespace WPILibInstaller.CLI { + public class CLIConfigurationProvider : IConfigurationProvider { + public CLIConfigurationProvider(string[] args) { + this.UpgradeConfig = new UpgradeConfig(); + this.FullConfig = new FullConfig(); + this.JdkConfig = new JdkConfig(); + this.VsCodeConfig = new VsCodeConfig(); + var publicFolder = Environment.GetEnvironmentVariable("PUBLIC"); + if (publicFolder == null) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + publicFolder = "C:\\Users\\Public"; + } + else + { + publicFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + } + } + this.InstallDirectory = Path.Combine(publicFolder, "wpilib", UpgradeConfig.FrcYear); + + FileStream fileStream = File.OpenRead(""); + //if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + //{ + //// Read the original hash. + //string hash = File.ReadAllText(Path.Join(AppContext.BaseDirectory, "checksum.txt")).Trim(); + + //// Compute the hash of the file that exists. + //string s; + //using (SHA256 SHA256 = SHA256Managed.Create()) + //{ + //s = Convert.ToHexString(await SHA256.ComputeHashAsync(fileStream)); + //} + + //// Make sure they match. + //if (!s.Equals(hash.ToUpper())) + //{ + //throw new Exception("The artifacts file was damaged."); + //} + //} + + + fileStream.Position = 0; + this.ZipArchive = ArchiveUtils.OpenArchive(fileStream); + } + public VsCodeModel VsCodeModel + { + get + { + VsCodeModel model = new VsCodeModel(VsCodeConfig.VsCodeVersion); + model.Platforms.Add(Utils.Platform.Win32, new VsCodeModel.PlatformData(VsCodeConfig.VsCode32Url, VsCodeConfig.VsCode32Name)); + model.Platforms.Add(Utils.Platform.Win64, new VsCodeModel.PlatformData(VsCodeConfig.VsCode64Url, VsCodeConfig.VsCode64Name)); + model.Platforms.Add(Utils.Platform.Linux64, new VsCodeModel.PlatformData(VsCodeConfig.VsCodeLinuxUrl, VsCodeConfig.VsCodeLinuxName)); + model.Platforms.Add(Utils.Platform.Mac64, new VsCodeModel.PlatformData(VsCodeConfig.VsCodeMacUrl, VsCodeConfig.VsCodeMacName)); + return model; + } + } + + + public IArchiveExtractor ZipArchive { get; private set; } + + public UpgradeConfig UpgradeConfig { get; private set; } + + public FullConfig FullConfig { get; private set; } + + public JdkConfig JdkConfig { get; private set; } + + public VsCodeConfig VsCodeConfig { get; private set; } + + public string InstallDirectory { get; private set; } + } + + public class Installer { + private readonly IConfigurationProvider configurationProvider; + + public Installer(string[] args) { + this.configurationProvider = new CLIConfigurationProvider(args); + } + + public void Install() { + Console.WriteLine("Extracting"); + Console.WriteLine("Installing Gradle"); + Console.WriteLine("Installing Tools"); + Console.WriteLine("Installing CPP"); + Console.WriteLine("Fixing Maven"); + Console.WriteLine("Installing VS Code"); + Console.WriteLine("Configuring VS Code"); + Console.WriteLine("Installing VS Code Extensions"); + Console.WriteLine("Creating Shortcuts"); + } + } +} diff --git a/WPILibInstaller-Avalonia/Program.cs b/WPILibInstaller-Avalonia/Program.cs index db7f09ae..25d82fd5 100644 --- a/WPILibInstaller-Avalonia/Program.cs +++ b/WPILibInstaller-Avalonia/Program.cs @@ -1,5 +1,6 @@ using Avalonia; using Avalonia.ReactiveUI; +using WPILibInstaller.CLI; namespace WPILibInstaller { @@ -8,8 +9,11 @@ class Program // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. - public static void Main(string[] args) => BuildAvaloniaApp() - .StartWithClassicDesktopLifetime(args); + public static void Main(string[] args) { + if (args.Length == 0) + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + else new Installer(args).Install(); + } // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() From dec1aabf8a3e70b3cce55f27ad3c434858933526 Mon Sep 17 00:00:00 2001 From: Noam Zaks Date: Sun, 2 May 2021 12:12:05 +0300 Subject: [PATCH 2/4] Added FRC year and file to options --- WPILibInstaller-Avalonia/CLI/Installer.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/WPILibInstaller-Avalonia/CLI/Installer.cs b/WPILibInstaller-Avalonia/CLI/Installer.cs index 26a2e833..b418f171 100644 --- a/WPILibInstaller-Avalonia/CLI/Installer.cs +++ b/WPILibInstaller-Avalonia/CLI/Installer.cs @@ -14,6 +14,24 @@ public CLIConfigurationProvider(string[] args) { this.FullConfig = new FullConfig(); this.JdkConfig = new JdkConfig(); this.VsCodeConfig = new VsCodeConfig(); + + string file = ""; + bool skip = false; + for (int i = 0; i < args.Length; i++) { + if (skip) { + skip = false; + continue; + } + if (args[i] == "--frc-year") { + this.UpgradeConfig.FrcYear = args[i+1]; + skip = true; + } + if (args[i] == "--file") { + file = args[i+1]; + skip = true; + } + } + var publicFolder = Environment.GetEnvironmentVariable("PUBLIC"); if (publicFolder == null) { @@ -28,7 +46,7 @@ public CLIConfigurationProvider(string[] args) { } this.InstallDirectory = Path.Combine(publicFolder, "wpilib", UpgradeConfig.FrcYear); - FileStream fileStream = File.OpenRead(""); + FileStream fileStream = File.OpenRead(file); //if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) //{ //// Read the original hash. From 47d5b24aa4c301b850942a6ebc5db5e422208f87 Mon Sep 17 00:00:00 2001 From: Noam Zaks Date: Tue, 3 Aug 2021 00:46:05 +0300 Subject: [PATCH 3/4] Quick and dirty --- WPILibInstaller-Avalonia/CLI/Installer.cs | 556 +++++++++++++++++++++- 1 file changed, 555 insertions(+), 1 deletion(-) diff --git a/WPILibInstaller-Avalonia/CLI/Installer.cs b/WPILibInstaller-Avalonia/CLI/Installer.cs index b418f171..abc539cb 100644 --- a/WPILibInstaller-Avalonia/CLI/Installer.cs +++ b/WPILibInstaller-Avalonia/CLI/Installer.cs @@ -2,10 +2,16 @@ using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography; +using System.Collections.Generic; using System.Threading.Tasks; using WPILibInstaller.Interfaces; using WPILibInstaller.Models; using WPILibInstaller.Utils; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Diagnostics; +using System.Linq; +using System.Threading; namespace WPILibInstaller.CLI { public class CLIConfigurationProvider : IConfigurationProvider { @@ -100,20 +106,568 @@ public VsCodeModel VsCodeModel public class Installer { private readonly IConfigurationProvider configurationProvider; + private readonly InstallSelectionModel selectionModel; + public Installer(string[] args) { this.configurationProvider = new CLIConfigurationProvider(args); + this.selectionModel = new InstallSelectionModel(); } - public void Install() { + public async Task Install() { Console.WriteLine("Extracting"); + await ExtractArchive(); Console.WriteLine("Installing Gradle"); + await RunGradleSetup(); Console.WriteLine("Installing Tools"); + await RunToolSetup(); Console.WriteLine("Installing CPP"); + await RunCppSetup(); Console.WriteLine("Fixing Maven"); + await RunMavenMetaDataFixer(); Console.WriteLine("Installing VS Code"); + await RunVsCodeSetup(); Console.WriteLine("Configuring VS Code"); + await ConfigureVsCodeSettings(); Console.WriteLine("Installing VS Code Extensions"); + await RunVsCodeExtensionsSetup(); Console.WriteLine("Creating Shortcuts"); + await RunShortcutCreator(); + } + + private async Task ExtractArchive() { + var directoriesToIgnore = GetExtractionIgnoreDirectories(); + + var archive = configurationProvider.ZipArchive; + + var extractor = archive; + + double totalSize = extractor.TotalUncompressSize; + long currentSize = 0; + + string intoPath = configurationProvider.InstallDirectory; + + while (extractor.MoveToNextEntry()) + { + currentSize += extractor.EntrySize; + if (extractor.EntryIsDirectory) continue; + + var entryName = extractor.EntryKey; + bool skip = false; + foreach (var ignore in directoriesToIgnore) + { + if (entryName.StartsWith(ignore)) + { + skip = true; + break; + } + } + + if (skip) + { + continue; + } + + string fullZipToPath = Path.Combine(intoPath, entryName); + string? directoryName = Path.GetDirectoryName(fullZipToPath); + if (directoryName?.Length > 0) + { + try + { + Directory.CreateDirectory(directoryName); + } + catch (IOException) + { + + } + } + + { + using FileStream writer = File.Create(fullZipToPath); + await extractor.CopyToStreamAsync(writer); + } + + if (extractor.EntryIsExecutable) + { + new Mono.Unix.UnixFileInfo(fullZipToPath).FileAccessPermissions |= + (Mono.Unix.FileAccessPermissions.GroupExecute | + Mono.Unix.FileAccessPermissions.UserExecute | + Mono.Unix.FileAccessPermissions.OtherExecute); + } + } + } + + private List GetExtractionIgnoreDirectories() + { + List ignoreDirs = new List(); + if (!selectionModel.InstallCpp) ignoreDirs.Add(configurationProvider.FullConfig.CppToolchain.Directory + "/"); + if (!selectionModel.InstallGradle) ignoreDirs.Add(configurationProvider.FullConfig.Gradle.ZipName); + if (!selectionModel.InstallJDK) ignoreDirs.Add(configurationProvider.JdkConfig.Folder + "/"); + if (!selectionModel.InstallTools) ignoreDirs.Add(configurationProvider.UpgradeConfig.Tools.Folder + "/"); + if (!selectionModel.InstallWPILibDeps) ignoreDirs.Add(configurationProvider.UpgradeConfig.Maven.Folder + "/"); + + return ignoreDirs; + } + + private Task RunGradleSetup() + { + if (!selectionModel.InstallGradle || !selectionModel.InstallWPILibDeps) return Task.CompletedTask; + + string extractFolder = configurationProvider.InstallDirectory; + + var config = configurationProvider.FullConfig; + + string gradleZipLoc = Path.Combine(extractFolder, "installUtils", config.Gradle.ZipName); + + string userFolder = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + List tasks = new List(); + foreach (var extractLocation in config.Gradle.ExtractLocations) + { + string toFolder = Path.Combine(userFolder, ".gradle", extractLocation, Path.GetFileNameWithoutExtension(config.Gradle.ZipName), config.Gradle.Hash); + string toFile = Path.Combine(toFolder, config.Gradle.ZipName); + tasks.Add(Task.Factory.StartNew(() => + { + try + { + Directory.CreateDirectory(toFolder); + } + catch (IOException) + { + + } + File.Copy(gradleZipLoc, toFile, true); + })); + } + return Task.WhenAll(tasks); + } + + private async Task RunToolSetup() + { + if (!selectionModel.InstallTools || !selectionModel.InstallWPILibDeps) + return; + + await RunScriptExecutable(Path.Combine(configurationProvider.InstallDirectory, + configurationProvider.UpgradeConfig.Tools.Folder, + configurationProvider.UpgradeConfig.Tools.UpdaterExe), 5000, "silent"); + } + + private Task RunScriptExecutable(string script, int timeoutMs, params string[] args) + { + ProcessStartInfo pstart = new ProcessStartInfo(script, string.Join(" ", args)); + var p = Process.Start(pstart); + return Task.Run(() => + { + return p!.WaitForExit(timeoutMs); + }); + } + + private async Task RunCppSetup() + { + if (!selectionModel.InstallCpp) return; + + await Task.Yield(); + } + + private async Task RunMavenMetaDataFixer() + { + if (!selectionModel.InstallWPILibDeps) + return; + + await RunScriptExecutable(Path.Combine(configurationProvider.InstallDirectory, + configurationProvider.UpgradeConfig.Maven.Folder, + configurationProvider.UpgradeConfig.Maven.MetaDataFixerExe), 5000, "silent"); + } + + private async Task RunVsCodeSetup() + { + if (!selectionModel.InstallVsCode) return; + + string intoPath = Path.Join(configurationProvider.InstallDirectory, "vscode"); + + if (configurationProvider.VsCodeModel.ToExtractArchiveMacOs != null) + { + configurationProvider.VsCodeModel.ToExtractArchiveMacOs.Seek(0, SeekOrigin.Begin); + var zipPath = Path.Join(intoPath, "MacVsCode.zip"); + Directory.CreateDirectory(intoPath); + { + using var fileToWrite = new FileStream(zipPath, FileMode.Create, FileAccess.Write, FileShare.None); + await configurationProvider.VsCodeModel.ToExtractArchiveMacOs.CopyToAsync(fileToWrite, token); + } + await RunScriptExecutable("unzip", Timeout.Infinite, zipPath, "-d", intoPath); + File.Delete(zipPath); + return; + } + + var archive = configurationProvider.VsCodeModel.ToExtractArchive!; + + var extractor = archive; + + while (extractor.MoveToNextEntry()) + { + if (extractor.EntryIsDirectory) continue; + var entryName = extractor.EntryKey; + + string fullZipToPath = Path.Combine(intoPath, entryName); + string? directoryName = Path.GetDirectoryName(fullZipToPath); + if (directoryName?.Length > 0) + { + try + { + Directory.CreateDirectory(directoryName); + } + catch (IOException) + { + + } + } + + { + using FileStream writer = File.Create(fullZipToPath); + await extractor.CopyToStreamAsync(writer); + } + + if (extractor.EntryIsExecutable) + { + new Mono.Unix.UnixFileInfo(fullZipToPath).FileAccessPermissions |= + (Mono.Unix.FileAccessPermissions.GroupExecute | + Mono.Unix.FileAccessPermissions.UserExecute | + Mono.Unix.FileAccessPermissions.OtherExecute); + } + } + + } + + private async Task ConfigureVsCodeSettings() + { + if (!selectionModel.InstallVsCode && !configurationProvider.VsCodeModel.AlreadyInstalled) return; + + var dataPath = await SetVsCodePortableMode(); + + var settingsDir = Path.Combine(dataPath, "user-data", "User"); + var settingsFile = Path.Combine(settingsDir, "settings.json"); + + var homePath = configurationProvider.InstallDirectory; + + var codeFolder = Path.Combine(homePath, configurationProvider.UpgradeConfig.PathFolder); + + try + { + Directory.CreateDirectory(codeFolder); + } + catch (IOException) + { + + } + + try + { + Directory.CreateDirectory(settingsDir); + } + catch (IOException) + { + + } + + dynamic settingsJson = new JObject(); + if (File.Exists(settingsFile)) + { + settingsJson = (JObject)JsonConvert.DeserializeObject(await File.ReadAllTextAsync(settingsFile))!; + } + + SetIfNotSet("java.home", Path.Combine(homePath, "jdk"), settingsJson); + SetIfNotSet("extensions.autoUpdate", false, settingsJson); + SetIfNotSet("extensions.autoCheckUpdates", false, settingsJson); + SetIfNotSet("extensions.ignoreRecommendations", true, settingsJson); + SetIfNotSet("extensions.showRecommendationsOnlyOnDemand", false, settingsJson); + SetIfNotSet("update.channel", "none", settingsJson); + SetIfNotSet("update.showReleaseNotes", false, settingsJson); + + string os; + string path_seperator; + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + os = "windows"; + path_seperator = ";"; + } + else if (OperatingSystem.IsMacOS()) + { + os = "osx"; + path_seperator = ":"; + } + else + { + os = "linux"; + path_seperator = ":"; + } + + if (!settingsJson.ContainsKey("terminal.integrated.env." + os)) + { + dynamic terminalProps = new JObject(); + + terminalProps["JAVA_HOME"] = Path.Combine(homePath, "jdk"); + terminalProps["PATH"] = Path.Combine(homePath, "jdk", "bin") + path_seperator + "${env:PATH}"; + + settingsJson["terminal.integrated.env." + os] = terminalProps; + + } + else + { + dynamic terminalEnv = settingsJson["terminal.integrated.env." + os]; + terminalEnv["JAVA_HOME"] = Path.Combine(homePath, "jdk"); + string path = terminalEnv["PATH"]; + if (path == null) + { + terminalEnv["PATH"] = Path.Combine(homePath, "jdk", "bin") + path_seperator + "${env:PATH}"; + } + else + { + var binPath = Path.Combine(homePath, "jdk", "bin"); + if (!path.Contains(binPath)) + { + path = binPath + path_seperator + path; + terminalEnv["PATH"] = path; + } + } + } + + var serialized = JsonConvert.SerializeObject(settingsJson, Formatting.Indented); + await File.WriteAllTextAsync(settingsFile, serialized); + } + + private ValueTask SetVsCodePortableMode() + { + string portableFolder = Path.Combine(configurationProvider.InstallDirectory, "vscode"); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + portableFolder = Path.Combine(portableFolder, "VSCode-linux-x64", "data"); + } + else if (OperatingSystem.IsMacOS()) + { + portableFolder = Path.Combine(portableFolder, "code-portable-data"); + } + else + { + portableFolder = Path.Combine(portableFolder, "data"); + } + + try + { + Directory.CreateDirectory(portableFolder); + } + catch (IOException) + { + + } + + return new ValueTask(portableFolder); + } + + private void SetIfNotSet(string key, T value, dynamic settingsJson) + { + if (!settingsJson.ContainsKey(key)) + { + + settingsJson[key] = value; + } + } + + private async Task RunVsCodeExtensionsSetup() + { + if (!selectionModel.InstallVsCodeExtensions) return; + + string codeExe; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + codeExe = Path.Combine(configurationProvider.InstallDirectory, "vscode", "bin", "code.cmd"); + } + else if (OperatingSystem.IsMacOS()) + { + codeExe = Path.Combine(configurationProvider.InstallDirectory, "vscode", "Visual Studio Code.app", "Contents", "Resources", "app", "bin", "code"); + } + else + { + codeExe = Path.Combine(configurationProvider.InstallDirectory, "vscode", "VSCode-linux-x64", "bin", "code"); + } + + // Load existing extensions + + var versions = await Task.Run(() => + { + var startInfo = new ProcessStartInfo(codeExe, "--list-extensions --show-versions") + { + UseShellExecute = false, + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + RedirectStandardOutput = true + }; + var proc = Process.Start(startInfo); + proc!.WaitForExit(); + var lines = new List<(string name, WPIVersion version)>(); + while (true) + { + string? line = proc.StandardOutput.ReadLine(); + if (line == null) + { + return lines; + } + + if (line.Contains('@')) + { + var split = line.Split('@'); + lines.Add((split[0], new WPIVersion(split[1]))); + } + } + }); + + var availableToInstall = new List<(Extension extension, WPIVersion version, int sortOrder)>(); + + availableToInstall.Add((configurationProvider.VsCodeConfig.WPILibExtension, + new WPIVersion(configurationProvider.VsCodeConfig.WPILibExtension.Version), int.MaxValue)); + + for (int i = 0; i < configurationProvider.VsCodeConfig.ThirdPartyExtensions.Length; i++) + { + availableToInstall.Add((configurationProvider.VsCodeConfig.ThirdPartyExtensions[i], + new WPIVersion(configurationProvider.VsCodeConfig.ThirdPartyExtensions[i].Version), i)); + } + + var maybeUpdates = availableToInstall.Where(x => versions.Select(y => y.name).Contains(x.extension.Name)).ToList(); + var newInstall = availableToInstall.Except(maybeUpdates).ToList(); + + var definitelyUpdate = maybeUpdates.Join(versions, x => x.extension.Name, y => y.name, + (newVersion, existing) => (newVersion, existing)) + .Where(x => x.newVersion.version > x.existing.version).Select(x => x.newVersion); + + var installs = definitelyUpdate.Concat(newInstall) + .OrderBy(x => x.sortOrder) + .Select(x => x.extension) + .ToArray(); + + double end = installs.Length; + foreach (var item in installs) + { + var startInfo = new ProcessStartInfo(codeExe, "--install-extension " + Path.Combine(configurationProvider.InstallDirectory, "vsCodeExtensions", item.Vsix)) + { + UseShellExecute = false, + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + RedirectStandardOutput = true + }; + await Task.Run(() => + { + var proc = Process.Start(startInfo); + proc!.WaitForExit(); + }); + + } + } + + private async Task RunShortcutCreator() + { + var shortcutData = new ShortcutData(); + + var frcHomePath = configurationProvider.InstallDirectory; + var frcYear = configurationProvider.UpgradeConfig.FrcYear; + + shortcutData.IconLocation = Path.Join(frcHomePath, configurationProvider.UpgradeConfig.PathFolder, "wpilib-256.ico"); + shortcutData.IsAdmin = selectionModel.InstallAsAdmin; + + if (selectionModel.InstallVsCode) + { + // Add VS Code Shortcuts + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "vscode", "Code.exe"), $"{frcYear} WPILib VS Code", $"{frcYear} WPILib VS Code")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "vscode", "Code.exe"), $"Programs/{frcYear} WPILib VS Code", $"{frcYear} WPILib VS Code")); + } + + if (selectionModel.InstallTools) + { + // Add Tool Shortcuts + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "OutlineViewer.vbs"), $"{frcYear} WPILib Tools/OutlineViewer", "OutlineViewer")); + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "PathWeaver.vbs"), $"{frcYear} WPILib Tools/PathWeaver", "PathWeaver")); + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "RobotBuilder.vbs"), $"{frcYear} WPILib Tools/RobotBuilder", "RobotBuilder")); + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "RobotBuilder-Old.vbs"), $"{frcYear} WPILib Tools/RobotBuilder-Old", "RobotBuilder-Old")); + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "shuffleboard.vbs"), $"{frcYear} WPILib Tools/Shuffleboard", "Shuffleboard")); + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "SmartDashboard.vbs"), $"{frcYear} WPILib Tools/SmartDashboard", "SmartDashboard")); + + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "OutlineViewer.vbs"), $"Programs/{frcYear} WPILib Tools/OutlineViewer", "OutlineViewer")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "PathWeaver.vbs"), $"Programs/{frcYear} WPILib Tools/PathWeaver", "PathWeaver")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "RobotBuilder.vbs"), $"Programs/{frcYear} WPILib Tools/RobotBuilder", "RobotBuilder")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "RobotBuilder-Old.vbs"), $"Programs/{frcYear} WPILib Tools/RobotBuilder-Old", "RobotBuilder-Old")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "shuffleboard.vbs"), $"Programs/{frcYear} WPILib Tools/Shuffleboard", "Shuffleboard")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "SmartDashboard.vbs"), $"Programs/{frcYear} WPILib Tools/SmartDashboard", "SmartDashboard")); + } + + // Add Documentation Shortcuts + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "documentation", "rtd", "frc-docs-latest", "index.html"), $"{frcYear} WPILib Documentation", $"{frcYear} WPILib Documentation")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "documentation", "rtd", "frc-docs-latest", "index.html"), $"Programs/{frcYear} WPILib Documentation", $"{frcYear} WPILib Documentation")); + + var serializedData = JsonConvert.SerializeObject(shortcutData); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Run windows shortcut creater + var tempFile = Path.GetTempFileName(); + await File.WriteAllTextAsync(tempFile, serializedData, token); + var shortcutCreatorPath = Path.Combine(configurationProvider.InstallDirectory, "installUtils", "WPILibShortcutCreator.exe"); + + var startInfo = new ProcessStartInfo(shortcutCreatorPath, $"\"{tempFile}\"") + { + WorkingDirectory = Environment.CurrentDirectory + }; + if (shortcutData.IsAdmin) + { + startInfo.UseShellExecute = true; + startInfo.Verb = "runas"; + } + else + { + startInfo.UseShellExecute = false; + startInfo.WindowStyle = ProcessWindowStyle.Hidden; + startInfo.CreateNoWindow = true; + startInfo.RedirectStandardOutput = true; + } + var exitCode = await Task.Run(() => + { + var proc = Process.Start(startInfo); + proc!.WaitForExit(); + return proc.ExitCode; + }); + + if (exitCode != 0) + { + Console.WriteLine("Warning: Shortcut creation failed. Error Code: " + exitCode); + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && selectionModel.InstallVsCode) + { + // Create Linux desktop shortcut + var desktopFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Desktop", $@"FRC VS Code {frcYear}.desktop"); + var launcherFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".local/share/applications", $@"FRC VS Code {frcYear}.desktop"); + string contents = $@"#!/usr/bin/env xdg-open +[Desktop Entry] +Version=1.0 +Type=Application +Categories=Development +Name=FRC VS Code {frcYear} +Comment=Official C++/Java IDE for the FIRST Robotics Competition +Exec={configurationProvider.InstallDirectory}/frccode/frccode{frcYear} +Icon={configurationProvider.InstallDirectory}/frccode/wpilib-256.ico +Terminal=false +StartupNotify=true +"; + + var desktopPath = Path.GetDirectoryName(desktopFile); + if (desktopPath != null) + { + Directory.CreateDirectory(desktopPath); + } + var launcherPath = Path.GetDirectoryName(launcherFile); + if (launcherPath != null) + { + Directory.CreateDirectory(launcherPath); + } + File.WriteAllText(desktopFile, contents); + File.WriteAllText(launcherFile, contents); + } } } } From 4fa46256ba4a1e674a2a17b7191bd276fe3a4389 Mon Sep 17 00:00:00 2001 From: Noam Zaks Date: Tue, 3 Aug 2021 18:27:17 +0300 Subject: [PATCH 4/4] Added cli options --- .../CLI/CLIConfigurationProvider.cs | 154 ++++++++++++++++++ WPILibInstaller-Avalonia/CLI/Installer.cs | 151 ++++------------- WPILibInstaller-Avalonia/CLI/Parser.cs | 91 +++++++++++ WPILibInstaller-Avalonia/Program.cs | 22 ++- .../Properties/launchSettings.json | 8 + 5 files changed, 306 insertions(+), 120 deletions(-) create mode 100644 WPILibInstaller-Avalonia/CLI/CLIConfigurationProvider.cs create mode 100644 WPILibInstaller-Avalonia/CLI/Parser.cs create mode 100644 WPILibInstaller-Avalonia/Properties/launchSettings.json diff --git a/WPILibInstaller-Avalonia/CLI/CLIConfigurationProvider.cs b/WPILibInstaller-Avalonia/CLI/CLIConfigurationProvider.cs new file mode 100644 index 00000000..f76532d9 --- /dev/null +++ b/WPILibInstaller-Avalonia/CLI/CLIConfigurationProvider.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using WPILibInstaller.Interfaces; +using WPILibInstaller.Models; +using WPILibInstaller.Utils; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Diagnostics; +using System.Threading; + +namespace WPILibInstaller.CLI +{ + class CLIConfigurationProvider : IConfigurationProvider + { + private CLIConfigurationProvider(UpgradeConfig upgradeConfig, FullConfig fullConfig, JdkConfig jdkConfig, VsCodeConfig vsCodeConfig, IArchiveExtractor zipArchive, string installDirectory) + { + UpgradeConfig = upgradeConfig; + FullConfig = fullConfig; + JdkConfig = jdkConfig; + VsCodeConfig = vsCodeConfig; + ZipArchive = zipArchive; + InstallDirectory = installDirectory; + } + + public static async Task From(string artifactsFile, string resourcesFile) + { + UpgradeConfig UpgradeConfig; + FullConfig FullConfig; + JdkConfig JdkConfig; + VsCodeConfig VsCodeConfig; + + var publicFolder = Environment.GetEnvironmentVariable("PUBLIC"); + if (publicFolder == null) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + publicFolder = "C:\\Users\\Public"; + } + else + { + publicFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal); + } + } + + FileStream fileStream = File.OpenRead(artifactsFile); + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + // Read the original hash. + string hash = File.ReadAllText(Path.Join(AppContext.BaseDirectory, "checksum.txt")).Trim(); + + // Compute the hash of the file that exists. + string s; + using (SHA256 SHA256 = SHA256Managed.Create()) + { + s = Convert.ToHexString(await SHA256.ComputeHashAsync(fileStream)); + } + + // Make sure they match. + if (!s.Equals(hash.ToUpper())) + { + throw new Exception("The artifacts file was damaged."); + } + } + + + fileStream.Position = 0; + var ZipArchive = ArchiveUtils.OpenArchive(fileStream); + + var resourcesArchive = ZipFile.OpenRead(resourcesFile); + + var entry = resourcesArchive.GetEntry("vscodeConfig.json"); + + using (StreamReader reader = new StreamReader(entry!.Open())) + { + var vsConfigStr = await reader.ReadToEndAsync(); + VsCodeConfig = JsonConvert.DeserializeObject(vsConfigStr, new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }) ?? throw new InvalidOperationException("Not Valid"); + } + + entry = resourcesArchive.GetEntry("jdkConfig.json"); + + using (StreamReader reader = new StreamReader(entry!.Open())) + { + var configStr = await reader.ReadToEndAsync(); + JdkConfig = JsonConvert.DeserializeObject(configStr, new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }) ?? throw new InvalidOperationException("Not Valid"); + } + + + entry = resourcesArchive.GetEntry("fullConfig.json"); + + using (StreamReader reader = new StreamReader(entry!.Open())) + { + var configStr = await reader.ReadToEndAsync(); + FullConfig = JsonConvert.DeserializeObject(configStr, new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }) ?? throw new InvalidOperationException("Not Valid"); + } + + + entry = resourcesArchive.GetEntry("upgradeConfig.json"); + + using (StreamReader reader = new StreamReader(entry!.Open())) + { + var configStr = await reader.ReadToEndAsync(); + UpgradeConfig = JsonConvert.DeserializeObject(configStr, new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }) ?? throw new InvalidOperationException("Not Valid"); + } + + var InstallDirectory = Path.Combine(publicFolder, "wpilib", UpgradeConfig.FrcYear); + return new CLIConfigurationProvider(UpgradeConfig, FullConfig, JdkConfig, VsCodeConfig, ZipArchive, InstallDirectory); + } + + public VsCodeModel VsCodeModel + { + get + { + VsCodeModel model = new VsCodeModel(VsCodeConfig.VsCodeVersion); + model.Platforms.Add(Utils.Platform.Win32, new VsCodeModel.PlatformData(VsCodeConfig.VsCode32Url, VsCodeConfig.VsCode32Name)); + model.Platforms.Add(Utils.Platform.Win64, new VsCodeModel.PlatformData(VsCodeConfig.VsCode64Url, VsCodeConfig.VsCode64Name)); + model.Platforms.Add(Utils.Platform.Linux64, new VsCodeModel.PlatformData(VsCodeConfig.VsCodeLinuxUrl, VsCodeConfig.VsCodeLinuxName)); + model.Platforms.Add(Utils.Platform.Mac64, new VsCodeModel.PlatformData(VsCodeConfig.VsCodeMacUrl, VsCodeConfig.VsCodeMacName)); + return model; + } + } + + + public IArchiveExtractor ZipArchive { get; private set; } + + public UpgradeConfig UpgradeConfig { get; private set; } + + public FullConfig FullConfig { get; private set; } + + public JdkConfig JdkConfig { get; private set; } + + public VsCodeConfig VsCodeConfig { get; private set; } + + public string InstallDirectory { get; private set; } + } +} diff --git a/WPILibInstaller-Avalonia/CLI/Installer.cs b/WPILibInstaller-Avalonia/CLI/Installer.cs index abc539cb..ffd81135 100644 --- a/WPILibInstaller-Avalonia/CLI/Installer.cs +++ b/WPILibInstaller-Avalonia/CLI/Installer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -13,107 +13,23 @@ using System.Linq; using System.Threading; -namespace WPILibInstaller.CLI { - public class CLIConfigurationProvider : IConfigurationProvider { - public CLIConfigurationProvider(string[] args) { - this.UpgradeConfig = new UpgradeConfig(); - this.FullConfig = new FullConfig(); - this.JdkConfig = new JdkConfig(); - this.VsCodeConfig = new VsCodeConfig(); - - string file = ""; - bool skip = false; - for (int i = 0; i < args.Length; i++) { - if (skip) { - skip = false; - continue; - } - if (args[i] == "--frc-year") { - this.UpgradeConfig.FrcYear = args[i+1]; - skip = true; - } - if (args[i] == "--file") { - file = args[i+1]; - skip = true; - } - } - - var publicFolder = Environment.GetEnvironmentVariable("PUBLIC"); - if (publicFolder == null) - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - publicFolder = "C:\\Users\\Public"; - } - else - { - publicFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal); - } - } - this.InstallDirectory = Path.Combine(publicFolder, "wpilib", UpgradeConfig.FrcYear); - - FileStream fileStream = File.OpenRead(file); - //if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - //{ - //// Read the original hash. - //string hash = File.ReadAllText(Path.Join(AppContext.BaseDirectory, "checksum.txt")).Trim(); - - //// Compute the hash of the file that exists. - //string s; - //using (SHA256 SHA256 = SHA256Managed.Create()) - //{ - //s = Convert.ToHexString(await SHA256.ComputeHashAsync(fileStream)); - //} - - //// Make sure they match. - //if (!s.Equals(hash.ToUpper())) - //{ - //throw new Exception("The artifacts file was damaged."); - //} - //} - - - fileStream.Position = 0; - this.ZipArchive = ArchiveUtils.OpenArchive(fileStream); - } - public VsCodeModel VsCodeModel - { - get - { - VsCodeModel model = new VsCodeModel(VsCodeConfig.VsCodeVersion); - model.Platforms.Add(Utils.Platform.Win32, new VsCodeModel.PlatformData(VsCodeConfig.VsCode32Url, VsCodeConfig.VsCode32Name)); - model.Platforms.Add(Utils.Platform.Win64, new VsCodeModel.PlatformData(VsCodeConfig.VsCode64Url, VsCodeConfig.VsCode64Name)); - model.Platforms.Add(Utils.Platform.Linux64, new VsCodeModel.PlatformData(VsCodeConfig.VsCodeLinuxUrl, VsCodeConfig.VsCodeLinuxName)); - model.Platforms.Add(Utils.Platform.Mac64, new VsCodeModel.PlatformData(VsCodeConfig.VsCodeMacUrl, VsCodeConfig.VsCodeMacName)); - return model; - } - } - - - public IArchiveExtractor ZipArchive { get; private set; } - - public UpgradeConfig UpgradeConfig { get; private set; } - - public FullConfig FullConfig { get; private set; } - - public JdkConfig JdkConfig { get; private set; } - - public VsCodeConfig VsCodeConfig { get; private set; } - - public string InstallDirectory { get; private set; } - } - - public class Installer { +namespace WPILibInstaller.CLI +{ + public class Installer + { private readonly IConfigurationProvider configurationProvider; - private readonly InstallSelectionModel selectionModel; + private readonly InstallSelectionModel installSelectionModel; - public Installer(string[] args) { - this.configurationProvider = new CLIConfigurationProvider(args); - this.selectionModel = new InstallSelectionModel(); + public Installer(string[] args) + { + var parser = new Parser(args); + configurationProvider = parser.configurationProvider; + installSelectionModel = parser.installSelectionModel; } - public async Task Install() { + public async Task Install() + { Console.WriteLine("Extracting"); await ExtractArchive(); Console.WriteLine("Installing Gradle"); @@ -131,10 +47,11 @@ public async Task Install() { Console.WriteLine("Installing VS Code Extensions"); await RunVsCodeExtensionsSetup(); Console.WriteLine("Creating Shortcuts"); - await RunShortcutCreator(); + // await RunShortcutCreator(); } - private async Task ExtractArchive() { + private async Task ExtractArchive() + { var directoriesToIgnore = GetExtractionIgnoreDirectories(); var archive = configurationProvider.ZipArchive; @@ -199,18 +116,18 @@ private async Task ExtractArchive() { private List GetExtractionIgnoreDirectories() { List ignoreDirs = new List(); - if (!selectionModel.InstallCpp) ignoreDirs.Add(configurationProvider.FullConfig.CppToolchain.Directory + "/"); - if (!selectionModel.InstallGradle) ignoreDirs.Add(configurationProvider.FullConfig.Gradle.ZipName); - if (!selectionModel.InstallJDK) ignoreDirs.Add(configurationProvider.JdkConfig.Folder + "/"); - if (!selectionModel.InstallTools) ignoreDirs.Add(configurationProvider.UpgradeConfig.Tools.Folder + "/"); - if (!selectionModel.InstallWPILibDeps) ignoreDirs.Add(configurationProvider.UpgradeConfig.Maven.Folder + "/"); + if (!installSelectionModel.InstallCpp) ignoreDirs.Add(configurationProvider.FullConfig.CppToolchain.Directory + "/"); + if (!installSelectionModel.InstallGradle) ignoreDirs.Add(configurationProvider.FullConfig.Gradle.ZipName); + if (!installSelectionModel.InstallJDK) ignoreDirs.Add(configurationProvider.JdkConfig.Folder + "/"); + if (!installSelectionModel.InstallTools) ignoreDirs.Add(configurationProvider.UpgradeConfig.Tools.Folder + "/"); + if (!installSelectionModel.InstallWPILibDeps) ignoreDirs.Add(configurationProvider.UpgradeConfig.Maven.Folder + "/"); return ignoreDirs; } private Task RunGradleSetup() { - if (!selectionModel.InstallGradle || !selectionModel.InstallWPILibDeps) return Task.CompletedTask; + if (!installSelectionModel.InstallGradle || !installSelectionModel.InstallWPILibDeps) return Task.CompletedTask; string extractFolder = configurationProvider.InstallDirectory; @@ -242,7 +159,7 @@ private Task RunGradleSetup() private async Task RunToolSetup() { - if (!selectionModel.InstallTools || !selectionModel.InstallWPILibDeps) + if (!installSelectionModel.InstallTools || !installSelectionModel.InstallWPILibDeps) return; await RunScriptExecutable(Path.Combine(configurationProvider.InstallDirectory, @@ -262,14 +179,14 @@ private Task RunScriptExecutable(string script, int timeoutMs, params stri private async Task RunCppSetup() { - if (!selectionModel.InstallCpp) return; + if (!installSelectionModel.InstallCpp) return; await Task.Yield(); } private async Task RunMavenMetaDataFixer() { - if (!selectionModel.InstallWPILibDeps) + if (!installSelectionModel.InstallWPILibDeps) return; await RunScriptExecutable(Path.Combine(configurationProvider.InstallDirectory, @@ -279,7 +196,7 @@ await RunScriptExecutable(Path.Combine(configurationProvider.InstallDirectory, private async Task RunVsCodeSetup() { - if (!selectionModel.InstallVsCode) return; + if (!installSelectionModel.InstallVsCode) return; string intoPath = Path.Join(configurationProvider.InstallDirectory, "vscode"); @@ -290,7 +207,7 @@ private async Task RunVsCodeSetup() Directory.CreateDirectory(intoPath); { using var fileToWrite = new FileStream(zipPath, FileMode.Create, FileAccess.Write, FileShare.None); - await configurationProvider.VsCodeModel.ToExtractArchiveMacOs.CopyToAsync(fileToWrite, token); + configurationProvider.VsCodeModel.ToExtractArchiveMacOs.CopyTo(fileToWrite); } await RunScriptExecutable("unzip", Timeout.Infinite, zipPath, "-d", intoPath); File.Delete(zipPath); @@ -338,7 +255,7 @@ private async Task RunVsCodeSetup() private async Task ConfigureVsCodeSettings() { - if (!selectionModel.InstallVsCode && !configurationProvider.VsCodeModel.AlreadyInstalled) return; + if (!installSelectionModel.InstallVsCode && !configurationProvider.VsCodeModel.AlreadyInstalled) return; var dataPath = await SetVsCodePortableMode(); @@ -472,7 +389,7 @@ private void SetIfNotSet(string key, T value, dynamic settingsJson) private async Task RunVsCodeExtensionsSetup() { - if (!selectionModel.InstallVsCodeExtensions) return; + if (!installSelectionModel.InstallVsCodeExtensions) return; string codeExe; @@ -561,7 +478,7 @@ await Task.Run(() => } } - private async Task RunShortcutCreator() + private async Task RunShortcutCreator(CancellationToken token) { var shortcutData = new ShortcutData(); @@ -569,16 +486,16 @@ private async Task RunShortcutCreator() var frcYear = configurationProvider.UpgradeConfig.FrcYear; shortcutData.IconLocation = Path.Join(frcHomePath, configurationProvider.UpgradeConfig.PathFolder, "wpilib-256.ico"); - shortcutData.IsAdmin = selectionModel.InstallAsAdmin; + shortcutData.IsAdmin = installSelectionModel.InstallAsAdmin; - if (selectionModel.InstallVsCode) + if (installSelectionModel.InstallVsCode) { // Add VS Code Shortcuts shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "vscode", "Code.exe"), $"{frcYear} WPILib VS Code", $"{frcYear} WPILib VS Code")); shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "vscode", "Code.exe"), $"Programs/{frcYear} WPILib VS Code", $"{frcYear} WPILib VS Code")); } - if (selectionModel.InstallTools) + if (installSelectionModel.InstallTools) { // Add Tool Shortcuts shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "OutlineViewer.vbs"), $"{frcYear} WPILib Tools/OutlineViewer", "OutlineViewer")); @@ -637,7 +554,7 @@ private async Task RunShortcutCreator() Console.WriteLine("Warning: Shortcut creation failed. Error Code: " + exitCode); } } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && selectionModel.InstallVsCode) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && installSelectionModel.InstallVsCode) { // Create Linux desktop shortcut var desktopFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Desktop", $@"FRC VS Code {frcYear}.desktop"); diff --git a/WPILibInstaller-Avalonia/CLI/Parser.cs b/WPILibInstaller-Avalonia/CLI/Parser.cs new file mode 100644 index 00000000..c5ec6d4d --- /dev/null +++ b/WPILibInstaller-Avalonia/CLI/Parser.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using WPILibInstaller.Models; + +namespace WPILibInstaller.CLI +{ + class Parser + { + public readonly CLIConfigurationProvider configurationProvider; + + public readonly InstallSelectionModel installSelectionModel; + + public Parser(string[] args) + { + string artifactsFile = "", resourcesFile = ""; + installSelectionModel = new InstallSelectionModel(); + + bool skip = false; + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "--help" || args[i] == "-h") + { + Console.WriteLine("Copyright (c) FIRST and other WPILib contributors.\n"); + Console.WriteLine("The following options are available:"); + Console.WriteLine(" -a,--artifacts The artifacts file to use for installation"); + Console.WriteLine(" -r,--resources The resources file to use for installation"); + Console.WriteLine(" -h,--help Show this help message"); + Console.WriteLine(" --as-admin Install WPILib as an administrator"); + Console.WriteLine(" --without-vscode Do not install Visual Studio Code"); + Console.WriteLine(" --without-gradle Do not install Gradle"); + Console.WriteLine(" --without-jdk Do not install the Java Development Kit"); + Console.WriteLine(" --without-tools Do not install the WPILib tools"); + Console.WriteLine(" --without-wpilibdeps Do not install the WPILib dependencies"); + Console.WriteLine(" --without-vscodeextensions Do not install the Visual Studio Code extensions"); + + throw new Exception("Couldn't create parser - only showing help message"); + } + if (skip) + { + skip = false; + continue; + } + if (args[i] == "--artifacts" || args[i] == "-a") + { + artifactsFile = args[i + 1]; + skip = true; + } + if (args[i] == "--resources" || args[i] == "-r") + { + resourcesFile = args[i + 1]; + skip = true; + } + if (args[i] == "--as-admin") + { + installSelectionModel.InstallAsAdmin = true; + } + if (args[i] == "--without-vscode") + { + installSelectionModel.InstallVsCode = false; + } + if (args[i] == "--without-gradle") + { + installSelectionModel.InstallGradle = false; + } + if (args[i] == "--without-jdk") + { + installSelectionModel.InstallJDK = false; + } + if (args[i] == "--without-tools") + { + installSelectionModel.InstallTools = false; + } + if (args[i] == "--without-wpilibdeps") + { + installSelectionModel.InstallWPILibDeps = false; + } + if (args[i] == "--without-vscodeextensions") + { + installSelectionModel.InstallVsCodeExtensions = false; + } + } + + var task = CLIConfigurationProvider.From(artifactsFile, resourcesFile); + task.Wait(); + configurationProvider = task.Result; + } + } +} diff --git a/WPILibInstaller-Avalonia/Program.cs b/WPILibInstaller-Avalonia/Program.cs index 25d82fd5..ff03bbcf 100644 --- a/WPILibInstaller-Avalonia/Program.cs +++ b/WPILibInstaller-Avalonia/Program.cs @@ -1,6 +1,7 @@ using Avalonia; using Avalonia.ReactiveUI; using WPILibInstaller.CLI; +using System; namespace WPILibInstaller { @@ -9,10 +10,25 @@ class Program // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. - public static void Main(string[] args) { + public static void Main(string[] args) + { + Console.WriteLine(args.Length); if (args.Length == 0) - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - else new Installer(args).Install(); + { + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + } + else + { + Console.WriteLine("Installing with CLI"); + try + { + new Installer(args).Install().Wait(); + } + catch (Exception e) + { + Console.WriteLine("CLI Installation Failed: " + e.Message); + } + } } // Avalonia configuration, don't remove; also used by visual designer. diff --git a/WPILibInstaller-Avalonia/Properties/launchSettings.json b/WPILibInstaller-Avalonia/Properties/launchSettings.json new file mode 100644 index 00000000..0b2adafc --- /dev/null +++ b/WPILibInstaller-Avalonia/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "WPILibInstaller-Avalonia": { + "commandName": "Project", + "commandLineArgs": "--help" + } + } +} \ No newline at end of file