diff --git a/WPILibInstaller-Avalonia/Interfaces/IConfigurationProvider.cs b/WPILibInstaller-Avalonia/Interfaces/IConfigurationProvider.cs index 657acf7..d2ae5ac 100644 --- a/WPILibInstaller-Avalonia/Interfaces/IConfigurationProvider.cs +++ b/WPILibInstaller-Avalonia/Interfaces/IConfigurationProvider.cs @@ -18,6 +18,8 @@ public interface IConfigurationProvider ChoreoConfig ChoreoConfig { get; } + ElasticConfig ElasticConfig { get; } + VsCodeConfig VsCodeConfig { get; } string InstallDirectory { get; } diff --git a/WPILibInstaller-Avalonia/Models/ElasticConfig.cs b/WPILibInstaller-Avalonia/Models/ElasticConfig.cs new file mode 100644 index 0000000..1464e7d --- /dev/null +++ b/WPILibInstaller-Avalonia/Models/ElasticConfig.cs @@ -0,0 +1,14 @@ +#nullable disable + +using Newtonsoft.Json; + +namespace WPILibInstaller.Models +{ + public class ElasticConfig + { + [JsonProperty("zipFile")] + public string ZipFile { get; set; } + [JsonProperty("folder")] + public string Folder { get; set; } + } +} diff --git a/WPILibInstaller-Avalonia/ViewModels/InstallPageViewModel.cs b/WPILibInstaller-Avalonia/ViewModels/InstallPageViewModel.cs index 01f7822..3686aa9 100644 --- a/WPILibInstaller-Avalonia/ViewModels/InstallPageViewModel.cs +++ b/WPILibInstaller-Avalonia/ViewModels/InstallPageViewModel.cs @@ -96,6 +96,7 @@ await ExtractArchive(token, new[] { configurationProvider.UpgradeConfig.Tools.Folder + "/", configurationProvider.AdvantageScopeConfig.Folder + "/", configurationProvider.ChoreoConfig.Folder + "/", + configurationProvider.ElasticConfig.Folder + "/", "installUtils/"}); } @@ -847,6 +848,7 @@ private async Task RunShortcutCreator(CancellationToken token) shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "DataLogTool.exe"), $"{frcYear} WPILib Tools/Data Log Tool {frcYear}", $"Data Log Tool {frcYear}", "")); shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "advantagescope", "AdvantageScope (WPILib).exe"), $"{frcYear} WPILib Tools/AdvantageScope (WPILib) {frcYear}", $"AdvantageScope (WPILib) {frcYear}", "")); shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "choreo", "choreo.exe"), $"{frcYear} WPILib Tools/Choreo (WPILib) {frcYear}", $"Choreo (WPILib) {frcYear}", "")); + shortcutData.DesktopShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "elastic", "elastic_dashboard.exe"), $"{frcYear} WPILib Tools/Elastic (WPILib) {frcYear}", $"Elastic (WPILib) {frcYear}", "")); shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "Glass.exe"), $"Programs/{frcYear} WPILib Tools/Glass {frcYear}", $"Glass {frcYear}", "")); shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "OutlineViewer.exe"), $"Programs/{frcYear} WPILib Tools/OutlineViewer {frcYear}", $"OutlineViewer {frcYear}", "")); @@ -859,6 +861,7 @@ private async Task RunShortcutCreator(CancellationToken token) shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "tools", "DataLogTool.exe"), $"Programs/{frcYear} WPILib Tools/Data Log Tool {frcYear}", $"Data Log Tool {frcYear}", "")); shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "advantagescope", "AdvantageScope (WPILib).exe"), $"Programs/{frcYear} WPILib Tools/AdvantageScope (WPILib) {frcYear}", $"AdvantageScope (WPILib) {frcYear}", "")); shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "choreo", "choreo.exe"), $"Programs/{frcYear} WPILib Tools/Choreo (WPILib) {frcYear}", $"Choreo (WPILib) {frcYear}", "")); + shortcutData.StartMenuShortcuts.Add(new ShortcutInfo(Path.Join(frcHomePath, "elastic", "elastic_dashboard.exe"), $"Programs/{frcYear} WPILib Tools/Elastic (WPILib) {frcYear}", $"Elastic (WPILib) {frcYear}", "")); if (toInstallProvider.Model.InstallEverything) { diff --git a/WPILibInstaller-Avalonia/ViewModels/StartPageViewModel.cs b/WPILibInstaller-Avalonia/ViewModels/StartPageViewModel.cs index 7145a69..173021b 100644 --- a/WPILibInstaller-Avalonia/ViewModels/StartPageViewModel.cs +++ b/WPILibInstaller-Avalonia/ViewModels/StartPageViewModel.cs @@ -225,6 +225,17 @@ private async Task SelectResourceFilesWithFile(string file) }) ?? throw new InvalidOperationException("Not Valid"); } + entry = zipArchive.GetEntry("elasticConfig.json"); + + using (StreamReader reader = new StreamReader(entry!.Open())) + { + var configStr = await reader.ReadToEndAsync(); + ElasticConfig = JsonConvert.DeserializeObject(configStr, new JsonSerializerSettings + { + MissingMemberHandling = MissingMemberHandling.Error + }) ?? throw new InvalidOperationException("Not Valid"); + } + entry = zipArchive.GetEntry("fullConfig.json"); using (StreamReader reader = new StreamReader(entry!.Open())) @@ -427,6 +438,8 @@ public override PageViewModelBase MoveNext() public ChoreoConfig ChoreoConfig { get; private set; } = null!; + public ElasticConfig ElasticConfig { get; private set; } = null!; + public VsCodeConfig VsCodeConfig { get; private set; } = null!; } diff --git a/apps/ToolsUpdater/src/main/java/Program.java b/apps/ToolsUpdater/src/main/java/Program.java index 731c9b7..80bfe6d 100644 --- a/apps/ToolsUpdater/src/main/java/Program.java +++ b/apps/ToolsUpdater/src/main/java/Program.java @@ -116,6 +116,23 @@ private static void installAdvantageScope(String toolsPath) { } } + private static void installElastic(String toolsPath) { + if (SystemUtils.IS_OS_MAC) { + String archiveFileName = "Elastic-WPILib-macOS.tar.gz"; + String elasticFolder = Paths.get(new File(toolsPath).getParent(), "elastic").toString(); + Path archivePath = Paths.get(elasticFolder, archiveFileName); + + try { + Runtime.getRuntime().exec(new String[] { + "tar", "-xzf", archivePath.toString(), "-C", elasticFolder + }).waitFor(); + } catch (IOException | InterruptedException e) { + System.out.println(e.toString()); + e.printStackTrace(); + } + } + } + private static void installUtility(String toolsPath) { if (SystemUtils.IS_OS_MAC) { String archiveFileName = "wpilibutility-mac.tar.gz"; @@ -148,7 +165,9 @@ public static void main(String[] args) throws URISyntaxException, IOException { System.out.println("Installing " + tool.name); if (tool.name.equals("AdvantageScope")) { installAdvantageScope(toolsPath); - } if (tool.name.equals("Utility")) { + } else if (tool.name.equals("Elastic")) { + installElastic(toolsPath); + } else if (tool.name.equals("Utility")) { installUtility(toolsPath); } else if (tool.artifact != null) { if (tool.cpp) { diff --git a/build.gradle b/build.gradle index a4b76c3..6da1f52 100644 --- a/build.gradle +++ b/build.gradle @@ -104,6 +104,7 @@ apply from: 'scripts/maven.gradle' apply from: 'scripts/advantagescope.gradle' apply from: 'scripts/choreo.gradle' +apply from: 'scripts/elastic.gradle' // Tools must happen after maven apply from: 'scripts/tools.gradle' @@ -223,6 +224,7 @@ def generateFullResourcesTask = tasks.register('generateFullResources', project. advantageScopeZipSetup(it) choreoZipSetup(it) + elasticZipSetup(it) if (OperatingSystem.current().isWindows()) { def task = it @@ -329,6 +331,7 @@ def generateConfigFiles = tasks.register('generateCommonResources', Zip) { advantageScopeConfigFileSetup(zip) choreoConfigFileSetup(zip) + elasticConfigFileSetup(zip) vscodeConfigZipSetup(zip) } diff --git a/files/Elastic.sh b/files/Elastic.sh new file mode 100644 index 0000000..20d7af4 --- /dev/null +++ b/files/Elastic.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +SCRIPT_PATH="$(dirname "$(realpath "$0")")" +SCRIPT_NAME="$(basename "$(realpath "$0")")" +SCRIPT_BASE="$(basename -s .sh "$SCRIPT_NAME")" +OS_NAME="$(uname -s)" +ELASTIC_PATH="$(realpath "$SCRIPT_PATH/../elastic")" + +if [ "$OS_NAME" = "Darwin" ]; then + open "$ELASTIC_PATH/elastic_dashboard.app" +else + exec "$ELASTIC_PATH/elastic_dashboard" +fi diff --git a/files/Elastic.vbs b/files/Elastic.vbs new file mode 100644 index 0000000..723caff --- /dev/null +++ b/files/Elastic.vbs @@ -0,0 +1,44 @@ +'Create File System Object for working with directories +Set fso = WScript.CreateObject("Scripting.FileSystemObject") + +'Get the folder of this script +toolsFolder = fso.GetParentFolderName(WScript.ScriptFullName) + +'Get the Elastic folder +toolsFolder = fso.GetParentFolderName(WScript.ScriptFullName) +yearFolder = fso.GetParentFolderName(toolsFolder) +elasticFolder = fso.BuildPath(yearFolder, "elastic") + +'Get the full path to the exe +fullExeName = fso.BuildPath(elasticFolder, "elastic_dashboard.exe") + +shellScript = fullExeName + +'Create Shell Object +Set objShell = WScript.CreateObject( "WScript.Shell" ) +Set objEnv = objShell.Environment("PROCESS") +dim runObject +' Allow us to catch a script run failure +On Error Resume Next +Set runObj = objShell.Exec(shellScript) +If Err.Number <> 0 Then + If WScript.Arguments.Count > 0 Then + If (WScript.Arguments(0) <> "silent") Then + WScript.Echo "Error Launching Tool" + vbCrLf + Err.Description + Else + WScript.StdOut.Write("Error Launching Tool") + WScript.StdOut.Write(Error.Description) + End If + Else + WScript.Echo "Error Launching Tool" + vbCrLf + Err.Description + End If + Set runObj = Nothing + Set objShell = Nothing + Set fso = Nothing + WScript.Quit(1) +End If + +Set runObj = Nothing +Set objShell = Nothing +Set fso = Nothing +WScript.Quit(0) diff --git a/scripts/elastic.gradle b/scripts/elastic.gradle new file mode 100644 index 0000000..678524f --- /dev/null +++ b/scripts/elastic.gradle @@ -0,0 +1,120 @@ +apply from: 'scripts/versions.gradle' + +def baseUrl = "https://github.com/Gold872/elastic-dashboard/releases/download/$elasticGitTag/" + +def fileNameWindows = 'Elastic-WPILib-Windows.zip' + +def downloadUrlWindows = baseUrl + fileNameWindows + +def fileNameMac = 'Elastic-WPILib-macOS.tar.gz' + +def downloadUrlMac = baseUrl + fileNameMac + +def fileNameMacArm = 'Elastic-WPILib-macOS.tar.gz' + +def downloadUrlMacArm = baseUrl + fileNameMacArm + +def fileNameLinux = 'Elastic-WPILib-Linux.zip' + +def downloadUrlLinux = baseUrl + fileNameLinux + +apply plugin: 'de.undercouch.download' + +def downloadTaskWindows = tasks.register('downloadElasticWindows', Download) { + src downloadUrlWindows + def fileName = file(src.file).name + dest "$buildDir/downloads/$fileName" + overwrite true +} + +def downloadTaskMac = tasks.register('downloadElasticMac', Download) { + src downloadUrlMac + def fileName = file(src.file).name + dest "$buildDir/downloads/$fileName" + overwrite true +} + +def downloadTaskMacArm = tasks.register('downloadElasticMacArm', Download) { + src downloadUrlMacArm + def fileName = file(src.file).name + dest "$buildDir/downloads/$fileName" + overwrite true +} + +def downloadTaskLinux = tasks.register('downloadElasticLinux', Download) { + src downloadUrlLinux + def fileName = file(src.file).name + dest "$buildDir/downloads/$fileName" + overwrite true +} + +def elasticConfigFile = file("$buildDir/elasticConfig.json") + +def elasticConfigFileTask = tasks.register('elasticConfigFile') { + it.outputs.file elasticConfigFile + + doLast { + def config = [:] + config['folder'] = 'elastic' + config['zipFile'] = 'elastic.zip' + + def gbuilder = getGsonBuilder() + + gbuilder.setPrettyPrinting() + def json = gbuilder.create().toJson(config) + + elasticConfigFile.parentFile.mkdirs() + + elasticConfigFile.text = json + } +} + +ext.elasticConfigFileSetup = { AbstractArchiveTask zip-> + zip.dependsOn elasticConfigFileTask + zip.inputs.file elasticConfigFile + + zip.from(elasticConfigFile) { + rename { 'elasticConfig.json' } + } +} + +ext.elasticZipSetup = { AbstractArchiveTask zip-> + if (project.hasProperty('linuxBuild')) { + zip.dependsOn downloadTaskLinux + + zip.inputs.files downloadTaskLinux.get().outputFiles + + zip.from(project.zipTree(downloadTaskLinux.get().outputFiles.first())) { + into '/elastic' + includeEmptyDirs = false + } + } else if (project.hasProperty('macBuild')) { + zip.dependsOn downloadTaskMac + + zip.inputs.files downloadTaskMac.get().outputFiles + + // Cannot extract, otherwise breaks mac + zip.from(downloadTaskMac.get().outputFiles.first()) { + into '/elastic' + } + } else if (project.hasProperty('macBuildArm')) { + zip.dependsOn downloadTaskMacArm + + zip.inputs.files downloadTaskMacArm.get().outputFiles + + // Cannot extract, otherwise breaks mac + zip.from(downloadTaskMacArm.get().outputFiles.first()) { + into '/elastic' + } + } else { + zip.dependsOn downloadTaskWindows + + zip.inputs.files downloadTaskWindows.get().outputFiles + + zip.from(project.zipTree(downloadTaskWindows.get().outputFiles.first())) { + into '/elastic' + includeEmptyDirs = false + } + } +} + diff --git a/scripts/tools.gradle b/scripts/tools.gradle index 1a0ed1a..7da210d 100644 --- a/scripts/tools.gradle +++ b/scripts/tools.gradle @@ -11,6 +11,9 @@ def advantageScopeScriptUnixFile = file("files/AdvantageScope.sh") def choreoScriptFile = file("files/Choreo.vbs") def choreoScriptUnixFile = file("files/Choreo.sh") +def elasticScriptFile = file("files/Elastic.vbs") +def elasticScriptUnixFile = file("files/Elastic.sh") + def toolsJsonTask = tasks.register('toolsJson', Task) { dependsOn tasks.named('lazyModelEvaluation') @@ -61,6 +64,11 @@ def toolsJsonTask = tasks.register('toolsJson', Task) { choreoItem['version'] = choreoGitTag config << choreoItem + def elasticItem = [:] + elasticItem['name'] = "Elastic" + elasticItem['version'] = elasticGitTag + config << elasticItem + def utilityItem = [:] utilityItem['name'] = "Utility" utilityItem['version'] = wpilibVersion @@ -113,6 +121,10 @@ ext.toolsSetup = { AbstractArchiveTask zip-> zip.from (choreoScriptFile) { into '/tools' } + + zip.from (elasticScriptFile) { + into '/tools' + } } else { zip.from (scriptBaseUnixFile) { into '/tools' @@ -133,6 +145,11 @@ ext.toolsSetup = { AbstractArchiveTask zip-> into '/tools' fileMode 0755 } + + zip.from (elasticScriptUnixFile) { + into '/tools' + fileMode 0755 + } } } diff --git a/scripts/versions.gradle b/scripts/versions.gradle index 3f43175..a97e657 100644 --- a/scripts/versions.gradle +++ b/scripts/versions.gradle @@ -25,6 +25,8 @@ ext.advantagescopeGitTag = 'v4.0.0-beta-3' ext.choreoGitTag = 'v2025.0.0-beta-6' +ext.elasticGitTag = 'v2025.0.0-beta-4' + ext.frcYear = '2025' ext.gradleWrapperVersion = '8.11'