Builder improvements.

This commit is contained in:
José Pedro 2018-03-27 22:36:18 +01:00
parent e10351dcd2
commit d2dec6e316
No known key found for this signature in database
GPG key ID: B8247B9301707B83
7 changed files with 143 additions and 204 deletions

View file

@ -13,8 +13,9 @@ namespace Cosmos.Build.Builder
{
if (e.Args.Length == 0)
{
MessageBox.Show("Builder not meant to be called directly. Use install-VS2017.bat instead.");
ShowErrorMessageBox("Builder not meant to be called directly. Use install-VS2017.bat instead.");
Shutdown();
return;
}
var configuration = new CommandLineBuilderConfiguration(e.Args);
@ -31,13 +32,17 @@ namespace Cosmos.Build.Builder
// For debugging, set params to something like this:
// -VSPath=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise
MessageBox.Show("Visual Studio path must be provided. (-VSPATH or /VSPATH)");
ShowErrorMessageBox("Visual Studio path must be provided. (-VSPATH or /VSPATH)");
Shutdown();
return;
}
BuilderConfiguration = configuration;
base.OnStartup(e);
}
private void ShowErrorMessageBox(string message) =>
MessageBox.Show(message, "Cosmos Kit Builder", MessageBoxButton.OK, MessageBoxImage.Error);
}
}

View file

@ -1,9 +1,14 @@
using Cosmos.Build.Builder.Models;
using System;
using System.Windows;
using Cosmos.Build.Builder.Models;
namespace Cosmos.Build.Builder.ViewModels
{
internal class MainWindowLogger : ILogger
{
private static readonly string[] NewLineStringArray = new string[] { Environment.NewLine };
private readonly MainWindowViewModel _viewModel;
public MainWindowLogger(MainWindowViewModel viewModel)
@ -11,21 +16,29 @@ namespace Cosmos.Build.Builder.ViewModels
_viewModel = viewModel;
}
public void LogMessage(string text)
{
_viewModel.CurrentSection.LogMessage(text);
_viewModel.TailItems.Push(text);
}
public void LogMessage(string text) => Application.Current.Dispatcher.Invoke(
() =>
{
_viewModel.CurrentSection.LogMessage(text);
public void NewSection(string name)
{
_viewModel.Sections.Add(new Section(name));
_viewModel.TailItems.Clear();
}
foreach (var line in text.Split(NewLineStringArray, StringSplitOptions.None))
{
_viewModel.TailItems.Push(line);
}
});
public void SetError()
{
_viewModel.CurrentSection.SetError();
}
public void NewSection(string name) => Application.Current.Dispatcher.Invoke(
() =>
{
_viewModel.Sections.Add(new Section(name));
_viewModel.TailItems.Clear();
});
public void SetError() => Application.Current.Dispatcher.Invoke(
() =>
{
_viewModel.CurrentSection.SetError();
_viewModel.CloseWhenCompleted = false;
});
}
}

View file

@ -1,16 +1,19 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Cosmos.Build.Builder.Collections;
using Cosmos.Build.Builder.Models;
namespace Cosmos.Build.Builder.ViewModels
{
internal class MainWindowViewModel
internal class MainWindowViewModel : ViewModelBase
{
private const int ReleaseNumber = 106027;
private const int TailItemCount = 10;
public ObservableFixedSizeStack<string> TailItems { get; }
@ -20,19 +23,38 @@ namespace Cosmos.Build.Builder.ViewModels
public ICommand CopyCommand { get; }
private ILogger _logger;
public bool CloseWhenCompleted
{
get => _closeWhenCompleted;
set => SetAndRaiseIfChanged(ref _closeWhenCompleted, value);
}
private CosmosTask _cosmosTask;
private Task _cosmosTaskTask;
private bool _closeWhenCompleted;
public MainWindowViewModel()
{
TailItems = new ObservableFixedSizeStack<string>(TailItemCount);
Sections = new ObservableCollection<Section>();
CopyCommand = new CopyLogCommand(this);
CopyCommand = new RelayCommand(CopyLogToClipboard);
_logger = new MainWindowLogger(this);
var logger = new MainWindowLogger(this);
_closeWhenCompleted = true;
var cosmosDir = Directory.GetCurrentDirectory();
_cosmosTask = new CosmosTask(logger, cosmosDir, ReleaseNumber);
_cosmosTaskTask = Task.Run((Action)_cosmosTask.Run);
_cosmosTaskTask.ContinueWith(CosmosTaskFinishedAsync);
}
public string BuildLog()
private void CopyLogToClipboard(object parameter) => Clipboard.SetText(BuildLog());
private string BuildLog()
{
var log = @"
========================================
@ -55,23 +77,25 @@ namespace Cosmos.Build.Builder.ViewModels
return log;
}
private class CopyLogCommand : ICommand
{
public event EventHandler CanExecuteChanged;
private Task CosmosTaskFinishedAsync(Task task) =>
Application.Current.Dispatcher.InvokeAsync(
async () =>
{
var mainWindow = Application.Current.MainWindow;
private MainWindowViewModel _viewModel;
private Func<bool> _canExecute;
await Task.Delay(5000);
public CopyLogCommand(MainWindowViewModel viewModel, Func<bool> canExecute = null)
{
_viewModel = viewModel;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute?.Invoke() ?? true;
public void Execute(object parameter) => Clipboard.SetText(_viewModel.BuildLog());
public void RaiseCanExecuteChanged(object sender, EventArgs e) => CanExecuteChanged?.Invoke(sender, e);
}
if (CloseWhenCompleted)
{
mainWindow.Close();
}
else
{
if (mainWindow.WindowState == WindowState.Maximized)
{
mainWindow.WindowState = WindowState.Normal;
}
}
}).Task;
}
}

View file

@ -0,0 +1,24 @@
using System;
using System.Windows.Input;
namespace Cosmos.Build.Builder.ViewModels
{
internal class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged;
private Action<object> _execute;
private Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute?.Invoke(parameter) ?? true;
public void Execute(object parameter) => _execute?.Invoke(parameter);
public void RaiseCanExecuteChanged(object sender, EventArgs e) => CanExecuteChanged?.Invoke(sender, e);
}
}

View file

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Cosmos.Build.Builder.ViewModels
{
internal abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void SetAndRaiseIfChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(propertyName);
}
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

View file

@ -5,10 +5,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Icon="/Cosmos.Build.Builder;component/Resources/Cosmos.ico"
Loaded="Window_Loaded"
MinHeight="480"
MinWidth="800"
SizeChanged="Window_SizeChanged"
Title="Cosmos Kit Builder"
WindowStartupLocation="CenterScreen"
DataContext="{StaticResource MainWindowViewModel}">
@ -18,10 +16,21 @@
<DockPanel>
<WrapPanel DockPanel.Dock="Top">
<Button Command="{Binding CopyCommand}"
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Command="{Binding CopyCommand}"
Content="Copy" />
</WrapPanel>
<CheckBox Grid.Column="2"
IsChecked="{Binding CloseWhenCompleted}"
Content="Close window when completed" />
</Grid>
<Rectangle DockPanel.Dock="Top"
Height="5" />

View file

@ -1,171 +1,12 @@
using System;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using Cosmos.Build.Builder.Models;
using Cosmos.Build.Installer;
using System.Windows;
namespace Cosmos.Build.Builder.Views
{
public partial class MainWindow : Window
{
private static readonly string[] NewLineStringArray = new string[] { Environment.NewLine };
string mCosmosDir;
string mSetupPath;
// Needs updating with each new release.
int mReleaseNo = 106027;
public MainWindow()
{
InitializeComponent();
}
bool mPreventAutoClose = false;
StringBuilder mClipboard = new StringBuilder();
DispatcherTimer mCloseTimer;
public bool Build()
{
Log.LogLine += new Log.LogLineHandler(Log_LogLine);
Log.LogSection += new Log.LogSectionHandler(Log_LogSection);
Log.LogError += new Log.LogErrorHandler(Log_LogError);
if (App.BuilderConfiguration.UserKit)
{
mReleaseNo = Int32.Parse(DateTime.Now.ToString("yyyyMMdd"));
}
if (mPreventAutoClose)
{
return true;
}
var xTask = new CosmosTask(mCosmosDir, mReleaseNo);
var xThread = new System.Threading.Thread(delegate ()
{
xTask.Run();
ThreadDone();
});
xThread.Start();
return true;
}
void ThreadDone()
{
Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate ()
{
if (App.BuilderConfiguration.StayOpen == false)
{
mCloseTimer = new DispatcherTimer();
mCloseTimer.Interval = TimeSpan.FromSeconds(5);
mCloseTimer.Tick += delegate
{
mCloseTimer.Stop();
if (mPreventAutoClose)
{
if (WindowState == WindowState.Minimized)
{
WindowState = WindowState.Normal;
}
}
else
{
Close();
}
};
mCloseTimer.Start();
}
});
}
void ClearTail() => DoOnViewModel(vm => vm.TailItems.Clear());
void Log_LogError()
{
Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate ()
{
ClearTail();
DoOnViewModel(vm => vm.CurrentSection?.SetError());
mPreventAutoClose = true;
});
}
void Log_LogLine(string aLine)
{
Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate ()
{
WriteTail(aLine);
DoOnViewModel(vm => vm.CurrentSection?.LogMessage(aLine));
mClipboard.AppendLine(aLine);
});
}
void Log_LogSection(string name)
{
Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate ()
{
DoOnViewModel(vm => vm.Sections.Add(new Section(name)));
ClearTail();
mClipboard.AppendLine();
mClipboard.AppendLine(new string('=', name.Length));
mClipboard.AppendLine(name);
mClipboard.AppendLine(new string('=', name.Length));
mClipboard.AppendLine();
});
}
void WriteTail(string aText) => DoOnViewModel(
vm =>
{
foreach (var line in aText.Split(NewLineStringArray, StringSplitOptions.None))
{
vm.TailItems.Push(line);
}
});
protected bool mLoaded = false;
void Window_Loaded(object sender, RoutedEventArgs e)
{
mLoaded = true;
DoOnViewModel(vm => vm.LogBuilder = mClipboard);
string xAppPath = AppContext.BaseDirectory;
mCosmosDir = Path.GetFullPath(xAppPath + @"..\..\..\..\..\");
mSetupPath = Path.Combine(mCosmosDir, @"Setup\Output\" + CosmosTask.GetSetupName(mReleaseNo) + ".exe");
if (!Build())
{
Close();
}
}
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
// User had non minimized window, or maximized it, or otherwise manually intervened.
// Even if starting minimized, this event gets called with Normal before load.
// This is why we have mLoaded.
if (mLoaded && WindowState != WindowState.Minimized)
{
mPreventAutoClose = true;
}
}
private void DoOnViewModel(Action<ViewModels.MainWindowViewModel> action)
{
if (DataContext is ViewModels.MainWindowViewModel viewModel)
{
action(viewModel);
}
}
}
}