From 2af1f6bcd1c5e91314687600f4da7ff8a0f5cabb Mon Sep 17 00:00:00 2001 From: Hendrik Mennen Date: Wed, 15 Nov 2023 22:14:23 +0100 Subject: [PATCH] childprocessservice --- .../Services/ChildProcessService.cs | 80 +++++++++++++++++++ .../OneWare.OssCadSuiteIntegration.csproj | 1 + .../OssCadSuiteIntegrationModule.cs | 2 +- .../Yosys/YosysService.cs | 27 +++++++ .../Services/IChildProcessService.cs | 9 +++ .../UniversalFpgaProjectCompileViewModel.cs | 6 +- 6 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/OneWare.Core/Services/ChildProcessService.cs create mode 100644 src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs create mode 100644 src/OneWare.Shared/Services/IChildProcessService.cs diff --git a/src/OneWare.Core/Services/ChildProcessService.cs b/src/OneWare.Core/Services/ChildProcessService.cs new file mode 100644 index 00000000..fae0dbfa --- /dev/null +++ b/src/OneWare.Core/Services/ChildProcessService.cs @@ -0,0 +1,80 @@ +using System.Diagnostics; +using Avalonia.Media; +using OneWare.Shared.Enums; +using OneWare.Shared.Services; + +namespace OneWare.Core.Services; + +public class ChildProcessService : IChildProcessService +{ + private readonly ILogger _logger; + private readonly IActive _active; + + public ChildProcessService(ILogger logger, IActive active) + { + _logger = logger; + _active = active; + } + + private static ProcessStartInfo GetProcessStartInfo(string workingDirectory, string path, string arguments) + { + return new ProcessStartInfo + { + FileName = path, + Arguments = $"{arguments}", + CreateNoWindow = true, + WorkingDirectory = workingDirectory, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + } + + public async Task<(bool success, string output)> ExecuteShellAsync(string path, string arguments, string workingDirectory, string status, AppState state = AppState.Loading) + { + var success = true; + + _logger.Log($"{Path.GetFileNameWithoutExtension(path)} {arguments}", ConsoleColor.DarkCyan, true, Brushes.CornflowerBlue); + + var output = string.Empty; + + var startInfo = GetProcessStartInfo(path, workingDirectory, arguments); + + using var activeProcess = new Process(); + activeProcess.StartInfo = startInfo; + var key = _active.AddState(status, state, activeProcess); + + activeProcess.OutputDataReceived += (o, i) => + { + if (string.IsNullOrEmpty(i.Data)) return; + _logger.Log(i.Data, ConsoleColor.Black, true); + output += i.Data + '\n'; + }; + activeProcess.ErrorDataReceived += (o, i) => + { + if (string.IsNullOrEmpty(i.Data)) return; + success = false; + _logger.Warning(i.Data, null, false); + output += i.Data + '\n'; + }; + + try + { + activeProcess.Start(); + activeProcess.BeginOutputReadLine(); + activeProcess.BeginErrorReadLine(); + + await Task.Run(() => activeProcess.WaitForExit()); + } + catch (Exception e) + { + _logger.Error(e.Message, e); + success = false; + } + + if (key.Terminated) success = false; + _active.RemoveState(key); + + return (success,output); + } +} \ No newline at end of file diff --git a/src/OneWare.OssCadSuiteIntegration/OneWare.OssCadSuiteIntegration.csproj b/src/OneWare.OssCadSuiteIntegration/OneWare.OssCadSuiteIntegration.csproj index 8dd83d1a..851f56f4 100644 --- a/src/OneWare.OssCadSuiteIntegration/OneWare.OssCadSuiteIntegration.csproj +++ b/src/OneWare.OssCadSuiteIntegration/OneWare.OssCadSuiteIntegration.csproj @@ -4,5 +4,6 @@ + diff --git a/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs b/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs index 22a0f130..3dca7a16 100644 --- a/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs +++ b/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs @@ -38,7 +38,7 @@ public void OnInitialized(IContainerProvider containerProvider) var currentPath = Environment.GetEnvironmentVariable("PATH"); //TODO Add all - Environment.SetEnvironmentVariable("PATH", $"{currentPath}{environmentPathSetting}"); + Environment.SetEnvironmentVariable("PATH", $"{environmentPathSetting}{currentPath}"); Environment.SetEnvironmentVariable("OPENFPGALOADER_SOJ_DIR", Path.Combine(x, "share", "openFPGALoader")); Environment.SetEnvironmentVariable("PYTHON_EXECUTABLE", Path.Combine(x, "py3bin", $"python3{PlatformHelper.ExecutableExtension}")); }); diff --git a/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs b/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs new file mode 100644 index 00000000..56e08791 --- /dev/null +++ b/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs @@ -0,0 +1,27 @@ +using OneWare.Shared.Services; +using OneWare.UniversalFpgaProjectSystem.Models; + +namespace OneWare.OssCadSuiteIntegration.Yosys; + +public class YosysService +{ + private readonly IChildProcessService _childProcessService; + + public YosysService(IChildProcessService childProcessService) + { + _childProcessService = childProcessService; + } + + public async Task SynthAsync(UniversalFpgaProjectRoot project) + { + var fpga = project.Properties["Fpga"]; + var top = project.Properties["TopEntity"]; + + var verilogFiles = string.Join(" ", project.Files.Where(x => x.Extension == ".v")); + var yosysFlags = string.Empty; + + await _childProcessService.ExecuteShellAsync("yosys", + $"yosys -p \"synth_${fpga} -top ${top} -json ${project.FullPath}/synth.json\" ${yosysFlags} ${verilogFiles}", + project.FullPath, "Yosys Synth"); + } +} \ No newline at end of file diff --git a/src/OneWare.Shared/Services/IChildProcessService.cs b/src/OneWare.Shared/Services/IChildProcessService.cs new file mode 100644 index 00000000..8b80b269 --- /dev/null +++ b/src/OneWare.Shared/Services/IChildProcessService.cs @@ -0,0 +1,9 @@ +using OneWare.Shared.Enums; + +namespace OneWare.Shared.Services; + +public interface IChildProcessService +{ + public Task<(bool success, string output)> ExecuteShellAsync(string path, string arguments, string workingDirectory, + string status, AppState state = AppState.Loading); +} \ No newline at end of file diff --git a/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs b/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs index 5faf7d63..08d5cc50 100644 --- a/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs +++ b/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs @@ -15,6 +15,7 @@ namespace OneWare.UniversalFpgaProjectSystem.ViewModels; public class UniversalFpgaProjectCompileViewModel : FlexibleWindowViewModelBase { private readonly IWindowService _windowService; + private readonly IProjectExplorerService _projectExplorerService; private readonly UniversalFpgaProjectRoot _project; public ObservableCollection FpgaModels { get; } = new(); @@ -33,9 +34,10 @@ public bool HideExtensions set => SetProperty(ref _hideExtensions, value); } - public UniversalFpgaProjectCompileViewModel(IWindowService windowService, FpgaService fpgaService, NodeProviderService nodeProviderService, UniversalFpgaProjectRoot project) + public UniversalFpgaProjectCompileViewModel(IWindowService windowService, IProjectExplorerService projectExplorerService, FpgaService fpgaService, NodeProviderService nodeProviderService, UniversalFpgaProjectRoot project) { _windowService = windowService; + _projectExplorerService = projectExplorerService; _project = project; this.WhenValueChanged(x => x.IsDirty).Subscribe(x => @@ -97,7 +99,9 @@ private async Task SafeQuitAsync(FlexibleWindow window) public void SaveAndClose(FlexibleWindow window) { + _project.Properties["Fpga"] = SelectedFpga?.Name; CreatePcf(); + _ = _projectExplorerService.SaveProjectAsync(_project); IsDirty = false; window.Close(); }