mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Implemented Artemis.Web.Update client
This commit is contained in:
1 parent
a5d2249593
commit
0cd65a2ebf
36 files changed
+1022
-359
No files matched your search
@@ -17,7 +17,7 @@ namespace Artemis.UI.Windows;
|
||||
public class ApplicationStateManager
|
||||
{
|
||||
private const int SM_SHUTTINGDOWN = 0x2000;
|
||||
|
||||
|
||||
public ApplicationStateManager(IContainer container, string[] startupArguments)
|
||||
{
|
||||
StartupArguments = startupArguments;
|
||||
@@ -25,6 +25,7 @@ public class ApplicationStateManager
|
||||
|
||||
Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested;
|
||||
Core.Utilities.RestartRequested += UtilitiesOnRestartRequested;
|
||||
Core.Utilities.UpdateRequested += UtilitiesOnUpdateRequested;
|
||||
|
||||
// On Windows shutdown dispose the IOC container just so device providers get a chance to clean up
|
||||
if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
|
||||
@@ -91,6 +92,33 @@ public class ApplicationStateManager
|
||||
Dispatcher.UIThread.Post(() => controlledApplicationLifetime.Shutdown());
|
||||
}
|
||||
|
||||
private void UtilitiesOnUpdateRequested(object? sender, UpdateEventArgs e)
|
||||
{
|
||||
List<string> argsList = new(StartupArguments);
|
||||
if (e.Silent)
|
||||
argsList.Add("--autorun");
|
||||
|
||||
// Retain startup arguments after update by providing them to the script
|
||||
string script = $"\"{Path.Combine(Constants.DataFolder, "updating", "pending", "scripts", "update.ps1")}\"";
|
||||
string source = $"-sourceDirectory \"{Path.Combine(Constants.DataFolder, "updating", "pending")}\"";
|
||||
string destination = $"-destinationDirectory \"{Constants.ApplicationFolder}\"";
|
||||
string args = argsList.Any() ? $"-artemisArgs \"{string.Join(',', argsList)}\"" : "";
|
||||
|
||||
// Run the PowerShell script included in the new version, that way any changes made to the script are used
|
||||
ProcessStartInfo info = new()
|
||||
{
|
||||
Arguments = $"-File {script} {source} {destination} {args}",
|
||||
WindowStyle = ProcessWindowStyle.Hidden,
|
||||
CreateNoWindow = true,
|
||||
FileName = "PowerShell.exe"
|
||||
};
|
||||
Process.Start(info);
|
||||
|
||||
// Lets try a graceful shutdown, PowerShell will kill if needed
|
||||
if (Application.Current?.ApplicationLifetime is IControlledApplicationLifetime controlledApplicationLifetime)
|
||||
Dispatcher.UIThread.Post(() => controlledApplicationLifetime.Shutdown());
|
||||
}
|
||||
|
||||
private void UtilitiesOnShutdownRequested(object? sender, EventArgs e)
|
||||
{
|
||||
// Use PowerShell to kill the process after 8 sec just in case
|
||||
@@ -115,7 +143,7 @@ public class ApplicationStateManager
|
||||
};
|
||||
Process.Start(info);
|
||||
}
|
||||
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("user32.dll")]
|
||||
private static extern int GetSystemMetrics(int nIndex);
|
||||
}
|
||||
@@ -12,20 +12,10 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
<None Remove=".gitignore" />
|
||||
<None Remove="Assets\Cursors\aero_crosshair.cur" />
|
||||
<None Remove="Assets\Cursors\aero_crosshair_minus.cur" />
|
||||
<None Remove="Assets\Cursors\aero_crosshair_plus.cur" />
|
||||
<None Remove="Assets\Cursors\aero_drag.cur" />
|
||||
<None Remove="Assets\Cursors\aero_drag_ew.cur" />
|
||||
<None Remove="Assets\Cursors\aero_fill.cur" />
|
||||
<None Remove="Assets\Cursors\aero_pen_min.cur" />
|
||||
<None Remove="Assets\Cursors\aero_pen_plus.cur" />
|
||||
<None Remove="Assets\Cursors\aero_rotate.cur" />
|
||||
<None Remove="Assets\Cursors\aero_rotate_bl.cur" />
|
||||
<None Remove="Assets\Cursors\aero_rotate_br.cur" />
|
||||
<None Remove="Assets\Cursors\aero_rotate_tl.cur" />
|
||||
<None Remove="Assets\Cursors\aero_rotate_tr.cur" />
|
||||
|
||||
<Content Include="Scripts\**">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="..\Artemis.UI\Assets\Images\Logo\application.ico">
|
||||
<Link>application.ico</Link>
|
||||
</None>
|
||||
|
||||
@@ -20,7 +20,6 @@ public static class UIContainerExtensions
|
||||
{
|
||||
container.Register<ICursorProvider, CursorProvider>(Reuse.Singleton);
|
||||
container.Register<IGraphicsContextProvider, GraphicsContextProvider>(Reuse.Singleton);
|
||||
container.Register<IUpdateProvider, UpdateProvider>(Reuse.Singleton);
|
||||
container.Register<IAutoRunProvider, AutoRunProvider>();
|
||||
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:update="clr-namespace:Artemis.UI.Windows.Screens.Update"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Windows.Screens.Update.UpdateDialogView"
|
||||
x:DataType="update:UpdateDialogViewModel"
|
||||
Title="Artemis | Update available"
|
||||
Width="750"
|
||||
MinWidth="750"
|
||||
Height="500"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="15" RowDefinitions="Auto,*,Auto">
|
||||
|
||||
<TextBlock Grid.Row="0" Classes="h4">
|
||||
A new Artemis update is available! 🥳
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="1" IsVisible="{CompiledBinding RetrievingChanges}" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<TextBlock>Retrieving changes...</TextBlock>
|
||||
<ProgressBar IsIndeterminate="True"></ProgressBar>
|
||||
</StackPanel>
|
||||
|
||||
<Border Grid.Row="1" Classes="card" IsVisible="{CompiledBinding !RetrievingChanges}">
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<StackPanel Grid.Row="0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="You are currently running build " />
|
||||
<TextBlock Text="{CompiledBinding CurrentBuild, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Text=" while the latest build is " />
|
||||
<TextBlock Text="{CompiledBinding LatestBuild, Mode=OneWay}"></TextBlock>
|
||||
<TextBlock Text="." />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="Updating Artemis will give you the latest bug(fixes), features and improvements." />
|
||||
<Separator Classes="card-separator" />
|
||||
|
||||
<TextBlock Classes="h5" IsVisible="{CompiledBinding HasChanges}">
|
||||
Changelog (auto-generated)
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalAlignment="Top" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" IsVisible="{CompiledBinding HasChanges}">
|
||||
<ItemsControl Items="{CompiledBinding Changes}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="Auto,*">
|
||||
<TextBlock Text="•" Margin="10 0" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding}" TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<StackPanel Grid.Row="1" IsVisible="{CompiledBinding !HasChanges}" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<TextBlock HorizontalAlignment="Center">We couldn't retrieve any changes</TextBlock>
|
||||
<controls:HyperlinkButton NavigateUri="https://github.com/Artemis-RGB/Artemis/commits/master" HorizontalAlignment="Center">View online</controls:HyperlinkButton>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" Spacing="5" Grid.Row="2" Margin="0 15 0 0">
|
||||
<Button Classes="accent" Command="{CompiledBinding Install}">Install update</Button>
|
||||
<Button Command="{CompiledBinding AskLater}">Ask later</Button>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,21 +0,0 @@
|
||||
using Artemis.UI.Shared;
|
||||
using Avalonia;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Artemis.UI.Windows.Screens.Update;
|
||||
|
||||
public class UpdateDialogView : ReactiveCoreWindow<UpdateDialogViewModel>
|
||||
{
|
||||
public UpdateDialogView()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Providers;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Artemis.UI.Shared.Services.Builders;
|
||||
using Artemis.UI.Windows.Models;
|
||||
using Artemis.UI.Windows.Providers;
|
||||
using Avalonia.Threading;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Windows.Screens.Update;
|
||||
|
||||
public class UpdateDialogViewModel : DialogViewModelBase<bool>
|
||||
{
|
||||
// Based on https://docs.microsoft.com/en-us/azure/devops/pipelines/repos/github?view=azure-devops&tabs=yaml#skipping-ci-for-individual-commits
|
||||
private readonly string[] _excludedCommitMessages =
|
||||
{
|
||||
"[skip ci]",
|
||||
"[ci skip]",
|
||||
"skip-checks: true",
|
||||
"skip-checks:true",
|
||||
"[skip azurepipelines]",
|
||||
"[azurepipelines skip]",
|
||||
"[skip azpipelines]",
|
||||
"[azpipelines skip]",
|
||||
"[skip azp]",
|
||||
"[azp skip]",
|
||||
"***NO_CI***"
|
||||
};
|
||||
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly UpdateProvider _updateProvider;
|
||||
private bool _hasChanges;
|
||||
private string? _latestBuild;
|
||||
|
||||
private bool _retrievingChanges;
|
||||
|
||||
public UpdateDialogViewModel(string channel, IUpdateProvider updateProvider, INotificationService notificationService)
|
||||
{
|
||||
_updateProvider = (UpdateProvider) updateProvider;
|
||||
_notificationService = notificationService;
|
||||
|
||||
Channel = channel;
|
||||
CurrentBuild = Constants.BuildInfo.BuildNumberDisplay;
|
||||
|
||||
this.WhenActivated((CompositeDisposable _) => Dispatcher.UIThread.InvokeAsync(GetBuildChanges));
|
||||
Install = ReactiveCommand.Create(() => Close(true));
|
||||
AskLater = ReactiveCommand.Create(() => Close(false));
|
||||
}
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Install { get; }
|
||||
public ReactiveCommand<Unit, Unit> AskLater { get; }
|
||||
|
||||
public string Channel { get; }
|
||||
public string CurrentBuild { get; }
|
||||
|
||||
public ObservableCollection<string> Changes { get; } = new();
|
||||
|
||||
public bool RetrievingChanges
|
||||
{
|
||||
get => _retrievingChanges;
|
||||
set => RaiseAndSetIfChanged(ref _retrievingChanges, value);
|
||||
}
|
||||
|
||||
public bool HasChanges
|
||||
{
|
||||
get => _hasChanges;
|
||||
set => RaiseAndSetIfChanged(ref _hasChanges, value);
|
||||
}
|
||||
|
||||
public string? LatestBuild
|
||||
{
|
||||
get => _latestBuild;
|
||||
set => RaiseAndSetIfChanged(ref _latestBuild, value);
|
||||
}
|
||||
|
||||
private async Task GetBuildChanges()
|
||||
{
|
||||
try
|
||||
{
|
||||
RetrievingChanges = true;
|
||||
Task<DevOpsBuild?> currentTask = _updateProvider.GetBuildInfo(1, CurrentBuild);
|
||||
Task<DevOpsBuild?> latestTask = _updateProvider.GetBuildInfo(1);
|
||||
|
||||
DevOpsBuild? current = await currentTask;
|
||||
DevOpsBuild? latest = await latestTask;
|
||||
|
||||
LatestBuild = latest?.BuildNumber;
|
||||
if (current != null && latest != null)
|
||||
{
|
||||
GitHubDifference difference = await _updateProvider.GetBuildDifferences(current, latest);
|
||||
|
||||
// Only take commits with one parents (no merges)
|
||||
Changes.Clear();
|
||||
Changes.AddRange(difference.Commits.Where(c => c.Parents.Count == 1)
|
||||
.SelectMany(c => c.Commit.Message.Split("\n"))
|
||||
.Select(m => m.Trim())
|
||||
.Where(m => !string.IsNullOrWhiteSpace(m) && !_excludedCommitMessages.Contains(m))
|
||||
.OrderBy(m => m)
|
||||
);
|
||||
HasChanges = Changes.Any();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_notificationService.CreateNotification().WithTitle("Failed to retrieve build changes").WithMessage(e.Message).WithSeverity(NotificationSeverity.Error).Show();
|
||||
}
|
||||
finally
|
||||
{
|
||||
RetrievingChanges = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
param (
|
||||
[Parameter(Mandatory=$true)][string]$sourceDirectory,
|
||||
[Parameter(Mandatory=$true)][string]$destinationDirectory,
|
||||
[Parameter(Mandatory=$false)][string]$artemisArgs
|
||||
)
|
||||
|
||||
# Wait up to 10 seconds for the process to shut down
|
||||
for ($i=1; $i -le 10; $i++) {
|
||||
$process = Get-Process -Name Artemis.UI.Windows -ErrorAction SilentlyContinue
|
||||
if (!$process) {
|
||||
break
|
||||
}
|
||||
Write-Host "Waiting for Artemis to shut down ($i / 10)"
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
|
||||
# If the process is still running, kill it
|
||||
$process = Get-Process -Name Artemis.UI.Windows -ErrorAction SilentlyContinue
|
||||
if ($process) {
|
||||
Stop-Process -Id $process.Id -Force
|
||||
Start-Sleep -Seconds 1
|
||||
}
|
||||
|
||||
# Check if the destination directory exists
|
||||
if (!(Test-Path $destinationDirectory)) {
|
||||
Write-Error "The destination directory does not exist"
|
||||
}
|
||||
|
||||
# If the destination directory exists, clear it
|
||||
Get-ChildItem $destinationDirectory | Remove-Item -Recurse -Force
|
||||
|
||||
# Move the contents of the source directory to the destination directory
|
||||
Get-ChildItem $sourceDirectory | Move-Item -Destination $destinationDirectory
|
||||
|
||||
Start-Sleep -Seconds 1
|
||||
|
||||
# When finished, run the updated version
|
||||
if ($artemisArgs) {
|
||||
Start-Process -FilePath "$destinationDirectory\Artemis.UI.Windows.exe" -WorkingDirectory $destinationDirectory -ArgumentList $artemisArgs
|
||||
} else {
|
||||
Start-Process -FilePath "$destinationDirectory\Artemis.UI.Windows.exe" -WorkingDirectory $destinationDirectory
|
||||
}
|
||||
Reference in new issue
Block a user