Skip to content

Commit

Permalink
Add the process runner and cook dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
Golle committed Aug 26, 2022
1 parent 4832a76 commit 6a71c98
Show file tree
Hide file tree
Showing 15 changed files with 276 additions and 36 deletions.
1 change: 1 addition & 0 deletions tools/Titan.Tools.ManifestBuilder/App.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

<Application.Resources>
<ResourceDictionary>
<FontFamily x:Key="CascadiaCode">/Assets/CascadiaCode-Regular-VTT.ttf#Cascadia Code</FontFamily>
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="/Resources/Colors.xaml"/>
<ResourceInclude Source="/Resources/Icons.xaml"/>
Expand Down
Binary file not shown.
26 changes: 26 additions & 0 deletions tools/Titan.Tools.ManifestBuilder/Common/GlobalConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ internal static class GlobalConfiguration
public const string ManifestFileExtension = "tmanifest";
public static string AppDataFolder { get; }
public static string SettingsFile { get; }
public static string BaseFolder { get; }

public static string PackagerProjectPath { get; }

static GlobalConfiguration()
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
Expand All @@ -24,5 +27,28 @@ static GlobalConfiguration()
{
Directory.CreateDirectory(AppDataFolder);
}

BaseFolder = GetBaseDirectory();
PackagerProjectPath = Path.Combine(BaseFolder, "tools", "Titan.Tools.Packager");
}

//NOTE(Jens): figure out how we should do this
private static string GetBaseDirectory()
{
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
const string SolutionFilename = "Titan.sln";
return FindParentWithFile(SolutionFilename, baseDirectory, 7)
?? baseDirectory;

static string? FindParentWithFile(string filename, string? path, int steps)
{
if (steps == 0 || path == null)
{
return null;
}
return File.Exists(Path.Combine(path, filename))
? path
: FindParentWithFile(filename, Directory.GetParent(path)?.FullName, steps - 1);
}
}
}
1 change: 1 addition & 0 deletions tools/Titan.Tools.ManifestBuilder/Registry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ static Registry()
.AddSingleton<IAppSettings, AppDataSettings>()
.AddSingleton<IManifestService, ManifestService>()
.AddSingleton<IManifestItemFactory, ManifestItemFactory>()
.AddSingleton<IApplicationState, ApplicationState>()
.AddSingleton<MainWindow>()

//.AddSingleton<EditorViewModel>()
Expand Down
2 changes: 0 additions & 2 deletions tools/Titan.Tools.ManifestBuilder/Services/DialogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Titan.Tools.ManifestBuilder.Common;
using Titan.Tools.ManifestBuilder.ViewModels.Dialogs;
using Titan.Tools.ManifestBuilder.Views.Dialogs;
Expand All @@ -14,7 +13,6 @@ public interface IDialogService
Task<string?> OpenFileDialog(string? path = null);
Task<string?> OpenFolderDialog(string? path = null);
Task<MessageBoxResult?> MessageBox(string title, string? message = null, MessageBoxType type = MessageBoxType.Ok);

}

internal class DialogService : IDialogService
Expand Down
13 changes: 13 additions & 0 deletions tools/Titan.Tools.ManifestBuilder/Services/IApplicationState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Titan.Tools.ManifestBuilder.Services;


public record AppState(string? ProjectPath = null);
public interface IApplicationState
{
string? ProjectPath { get; set; }
}

public class ApplicationState : IApplicationState
{
public string? ProjectPath { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Folder Include="Assets\" />
<AvaloniaResource Include="Assets\**" />
<Folder Include="DataTemplates\Attributes\" />
<None Remove=".gitignore" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using Avalonia.Controls;
using ReactiveUI;
using Titan.Tools.Core.Manifests;
using Titan.Tools.ManifestBuilder.Common;
using Titan.Tools.ManifestBuilder.Services;
using Titan.Tools.ManifestBuilder.Views.Dialogs;

namespace Titan.Tools.ManifestBuilder.ViewModels.Dialogs;

Expand Down Expand Up @@ -30,13 +37,12 @@ public string? Namespace

public ICommand BrowsePackagePath { get; }
public ICommand BrowseGeneratedPath { get; }


public ICommand Build { get; }
public CookAssetsViewModel(IDialogService? dialogService = null, IAppSettings? appSettings = null)
public CookAssetsViewModel(Window window, IDialogService? dialogService = null, IAppSettings? appSettings = null, IApplicationState? applicationState = null)
{
dialogService ??= Registry.GetRequiredService<IDialogService>();
appSettings ??= Registry.GetRequiredService<IAppSettings>();
applicationState ??= Registry.GetRequiredService<IApplicationState>();

var cookSettings = appSettings.GetSettings().CookAssetSettings;
_packagePath = cookSettings.OutputPath;
Expand All @@ -45,16 +51,37 @@ public CookAssetsViewModel(IDialogService? dialogService = null, IAppSettings? a

BrowseGeneratedPath = ReactiveCommand.CreateFromTask(async () => GeneratedPath = await dialogService.OpenFolderDialog(_generatedPath));
BrowsePackagePath = ReactiveCommand.CreateFromTask(async () => PackagePath = await dialogService.OpenFolderDialog(_packagePath));
Build = ReactiveCommand.CreateFromTask(() =>
Build = ReactiveCommand.CreateFromTask(async () =>
{
var settings = appSettings.GetSettings();
appSettings.Save(settings with { CookAssetSettings = new CookAssetSettings(_namespace, PackagePath, GeneratedPath) });
return Task.CompletedTask;
var projectPath = applicationState.ProjectPath;

var manifests = Directory.GetFiles(projectPath!, $"*.{GlobalConfiguration.ManifestFileExtension}");
if (manifests.Length == 0)
{
await dialogService.MessageBox("Failed", $"No manifests found in path {projectPath}");
return;
}

//NOTE(Jens): add support for multiple manifests. can probably execute them either in parallel and show different tabs inside the window.
if (manifests.Length > 1)
{
await dialogService.MessageBox("Warning", $"We currently only support a single manifest per project. Only {manifests[0]} will be built.");
}

var args = $"run --project {GlobalConfiguration.PackagerProjectPath} -- -m {manifests.First()} -o \"{_packagePath}\" -g \"{_generatedPath}\" {(_namespace != null ? $"-n {_namespace}" : string.Empty)}";
var dialog = new ExternalProcessWindow
{
DataContext = new ExternalProcessViewModel(new ExternalProcess("dotnet", args))
};
await dialog.ShowDialog(window);
window.Close();
});
}

public CookAssetsViewModel()
: this(null)
: this(null!)
{
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Threading;
using DynamicData.Binding;

namespace Titan.Tools.ManifestBuilder.ViewModels.Dialogs;

public record ExternalProcess(string Filename, string Arguments, string? WorkingDir = null);

public class ExternalProcessViewModel : ViewModelBase
{
private bool _isRunning;
public bool IsRunning
{
get => _isRunning;
set => SetProperty(ref _isRunning, value);
}

private string _status = "Running";
public string Status
{
get => _status;
set => SetProperty(ref _status, value);
}

public IObservableCollection<string> LogOutput { get; } = new ObservableCollectionExtended<string>();


private int _lineCount;
public ExternalProcessViewModel(ExternalProcess externalProcess)
{
WriteLine($"Starting process {Path.GetFileNameWithoutExtension(externalProcess.Filename)} {externalProcess.Arguments}\n");

var _ = Run(externalProcess);
}

private async Task Run(ExternalProcess externalProcess)
{
try
{
IsRunning = true;
using var process = new Process
{
StartInfo = new ProcessStartInfo(externalProcess.Filename, externalProcess.Arguments)
{
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true
},
};
process.OutputDataReceived += async (_, args) =>
{
if (args.Data != null)
{
await WriteLineAsync(args.Data);
}
};

process.ErrorDataReceived += async (_, args) =>
{
if (args.Data != null)
{
await WriteLineAsync(args.Data);
}
};
if (!process.Start())
{
Status = "Failed to start the process.";
return;
}
process.BeginErrorReadLine();
process.BeginOutputReadLine();
await process.WaitForExitAsync(CancellationToken.None); //NOTE(Jens): add support for cancellation token
var exitCode = process.ExitCode;
Status = $"Completed with exit code {exitCode}";
}
catch (Exception e)
{
Status = $"Exception occurred: {e.GetType().Name} - {e.Message}";
}
finally
{
IsRunning = false;
}
}
public ExternalProcessViewModel()
{
for (var i = 0; i < 100; ++i)
WriteLine("Design mode");
}

private async ValueTask WriteLineAsync(string line)
{
if (Dispatcher.UIThread.CheckAccess())
{
WriteLine(line);
}
else
{
await Dispatcher.UIThread.InvokeAsync(() => WriteLine(line));
}
}

private void WriteLine(string line)
=> LogOutput.Add($"{_lineCount++,4}: {line}");
}


Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ public class RecentProjectViewModel
{
public required string Title { get; init; }
public required string Path { get; init; }

public static RecentProjectViewModel Create(string path) =>
new()
{
Title = System.IO.Path.GetFileNameWithoutExtension(path) ?? "unknown",
Title = System.IO.Path.GetFileNameWithoutExtension(path),
Path = path
};
}
Expand All @@ -28,14 +27,10 @@ public class SelectProjectWindowViewModel : ViewModelBase
public IEnumerable<RecentProjectViewModel> RecentProjects { get; }

public SelectProjectWindowViewModel() : this(null!) { }
public SelectProjectWindowViewModel(Window parentWindow)
: this(parentWindow, null)
{
}

public SelectProjectWindowViewModel(Window parentWindow, IAppSettings? appSettings = null)
public SelectProjectWindowViewModel(Window parentWindow, IAppSettings? appSettings = null, IApplicationState? applicationState = null)
{
appSettings ??= Registry.GetRequiredService<IAppSettings>();
applicationState ??= Registry.GetRequiredService<IApplicationState>();
RecentProjects = appSettings
.GetSettings()
.RecentProjects
Expand All @@ -47,26 +42,29 @@ public SelectProjectWindowViewModel(Window parentWindow, IAppSettings? appSettin
OpenProject = ReactiveCommand.CreateFromTask(async () =>
{
var dialog = new OpenFolderDialog();
var result = await dialog.ShowAsync(parentWindow);
if (result != null)
var projectPath = await dialog.ShowAsync(parentWindow);
if (projectPath != null)
{
var settings = appSettings.GetSettings();
if (settings.RecentProjects.AddProject(result))
if (settings.RecentProjects.AddProject(projectPath))
{
appSettings.Save(settings);
}
parentWindow.Close(result);
parentWindow.Close(projectPath);

applicationState.ProjectPath = projectPath;
}
});

OpenRecentProject = ReactiveCommand.Create<string>(path =>
OpenRecentProject = ReactiveCommand.Create<string>(projectPath =>
{
if (!Directory.Exists(path))
if (!Directory.Exists(projectPath))
{
// do some error handling and remove the project from the list.
return;
}
parentWindow.Close(path);
parentWindow.Close(projectPath);
applicationState.ProjectPath = projectPath;
});
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using ReactiveUI;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,8 @@
<Design.DataContext>
<dialogs:CookAssetsViewModel></dialogs:CookAssetsViewModel>
</Design.DataContext>
<Window.Styles>
<Style Selector="Button#PART_Build">
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="150"/>
<Setter Property="FontSize" Value="30"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</Window.Styles>
<Panel>

<Panel>
<ExperimentalAcrylicBorder IsHitTestVisible="False">
<ExperimentalAcrylicBorder.Material>
<ExperimentalAcrylicMaterial BackgroundSource="Digger" TintColor="Black" TintOpacity="1" MaterialOpacity="0.8" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public CookAssetsDialog()
this.AttachDevTools();
#endif

DataContext = new CookAssetsViewModel();
DataContext = new CookAssetsViewModel(this);
}

private void InitializeComponent()
Expand Down
Loading

0 comments on commit 6a71c98

Please sign in to comment.