mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-02-04 02:43:32 +00:00
Merge branch 'master' into development
This commit is contained in:
commit
36761509e2
5
.github/workflows/master.yml
vendored
5
.github/workflows/master.yml
vendored
@ -22,9 +22,8 @@ jobs:
|
||||
run: |
|
||||
$MidnightUtc = [DateTime]::UtcNow.Date
|
||||
$BranchName = "${{ github.ref_name }}".replace('/','-').replace('.','-')
|
||||
$ApiVersion = (Select-Xml -Path 'src/Artemis.Core/Artemis.Core.csproj' -XPath '//PluginApiVersion').Node.InnerText
|
||||
$NumberOfCommitsToday = (git log --after=$($MidnightUtc.ToString("o")) --oneline | Measure-Object -Line).Lines
|
||||
$VersionNumber = "$ApiVersion.$($MidnightUtc.ToString("yyyy.MMdd")).$NumberOfCommitsToday"
|
||||
$VersionNumber = "1.$($MidnightUtc.ToString("yyyy.MMdd")).$NumberOfCommitsToday"
|
||||
# If we're not in master, add the branch name to the version so it counts as prerelease
|
||||
if ($BranchName -ne "master") { $VersionNumber += "-$BranchName" }
|
||||
"version-number=$VersionNumber" >> $Env:GITHUB_OUTPUT
|
||||
@ -55,7 +54,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
dotnet-version: '10.0.x'
|
||||
- name: Publish Artemis
|
||||
run: dotnet publish --configuration Release -p:Version=${{ needs.version.outputs.version-number }} --runtime ${{ matrix.rid }} --output build/${{ matrix.rid }} --self-contained Artemis/src/Artemis.UI.${{ matrix.csproj }}/Artemis.UI.${{ matrix.csproj }}.csproj
|
||||
- name: Upload Artifact
|
||||
|
||||
5
.github/workflows/nuget.yml
vendored
5
.github/workflows/nuget.yml
vendored
@ -22,9 +22,8 @@ jobs:
|
||||
run: |
|
||||
$MidnightUtc = [DateTime]::UtcNow.Date
|
||||
$BranchName = "${{ github.ref_name }}".replace('/','-').replace('.','-')
|
||||
$ApiVersion = (Select-Xml -Path 'src/Artemis.Core/Artemis.Core.csproj' -XPath '//PluginApiVersion').Node.InnerText
|
||||
$NumberOfCommitsToday = (git log --after=$($MidnightUtc.ToString("o")) --oneline | Measure-Object -Line).Lines
|
||||
$VersionNumber = "$ApiVersion.$($MidnightUtc.ToString("yyyy.MMdd")).$NumberOfCommitsToday"
|
||||
$VersionNumber = "1.$($MidnightUtc.ToString("yyyy.MMdd")).$NumberOfCommitsToday"
|
||||
# If we're not in master, add the branch name to the version so it counts as prerelease
|
||||
if ($BranchName -ne "master") { $VersionNumber += "-$BranchName" }
|
||||
"version-number=$VersionNumber" >> $Env:GITHUB_OUTPUT
|
||||
@ -37,7 +36,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: '9.0.x'
|
||||
dotnet-version: '10.0.x'
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Pack Artemis.Core
|
||||
|
||||
@ -41,7 +41,7 @@ public static class Constants
|
||||
/// The full path to the Artemis data folder
|
||||
/// </summary>
|
||||
#if DEBUG
|
||||
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis-dev");
|
||||
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis");
|
||||
#else
|
||||
public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis");
|
||||
#endif
|
||||
|
||||
@ -16,8 +16,8 @@ public static class ReleaseExtensions
|
||||
{
|
||||
if (release.MinimumVersion == null || Constants.CurrentVersion == "local")
|
||||
return true;
|
||||
|
||||
return release.MinimumVersion <= Version.Parse(Constants.CurrentVersion).ArtemisVersionToLong();
|
||||
|
||||
return Version.Parse(release.MinimumVersion) <= Version.Parse(Constants.CurrentVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Artemis.UI.Extensions;
|
||||
|
||||
public static class VersionExtensions
|
||||
{
|
||||
/// <param name="version">The version to convert</param>
|
||||
extension(Version version)
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert a Version to a long representation for easy comparison in PostgreSQL
|
||||
/// <remarks>Assumes format: major.year.dayOfYear.revision (e.g., 1.2024.0225.2)</remarks>
|
||||
/// </summary>
|
||||
/// <returns>A long value that preserves version comparison order</returns>
|
||||
public long ArtemisVersionToLong()
|
||||
{
|
||||
// Format: major.year.dayOfYear.revision
|
||||
// Convert to: majorYYYYDDDRRRR (16 digits)
|
||||
// Major: 1 digit (0-9)
|
||||
// Year: 4 digits (e.g., 2024)
|
||||
// Day: 3 digits (001-366, padded)
|
||||
// Revision: 4 digits (0000-9999, padded)
|
||||
|
||||
long major = Math.Max(0, Math.Min(9, version.Major));
|
||||
long year = Math.Max(1000, Math.Min(9999, version.Minor));
|
||||
long day = Math.Max(1, Math.Min(366, version.Build));
|
||||
long revision = Math.Max(0, Math.Min(9999, version.Revision >= 0 ? version.Revision : 0));
|
||||
|
||||
return major * 100000000000L +
|
||||
year * 10000000L +
|
||||
day * 10000L +
|
||||
revision;
|
||||
}
|
||||
|
||||
public static Version FromLong(long versionLong)
|
||||
{
|
||||
int major = (int)(versionLong / 100000000000L);
|
||||
int year = (int)((versionLong / 10000000L) % 10000);
|
||||
int day = (int)((versionLong / 10000L) % 1000);
|
||||
int revision = (int)(versionLong % 10000L);
|
||||
|
||||
return new Version(major, year, day, revision);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -69,11 +69,11 @@ public partial class EntryReleaseInfoViewModel : ActivatableViewModelBase
|
||||
}).DisposeWith(d);
|
||||
|
||||
IsCurrentVersion = Release != null && _workshopService.GetInstalledEntry(Release.Entry.Id)?.ReleaseId == Release.Id;
|
||||
IncompatibilityReason = Release != null && !Release.IsCompatible() ? $"Requires Artemis v{Version.FromLong(Release.MinimumVersion!.Value)} or later" : null;
|
||||
IncompatibilityReason = Release != null && !Release.IsCompatible() ? $"Requires Artemis v{Release.MinimumVersion} or later" : null;
|
||||
});
|
||||
|
||||
this.WhenAnyValue(vm => vm.Release).Subscribe(r => IsCurrentVersion = r != null && _workshopService.GetInstalledEntry(r.Entry.Id)?.ReleaseId == r.Id);
|
||||
this.WhenAnyValue(vm => vm.Release).Subscribe(r => IncompatibilityReason = r != null && !r.IsCompatible() ? $"Requires Artemis v{Version.FromLong(r.MinimumVersion!.Value)} or later" : null);
|
||||
this.WhenAnyValue(vm => vm.Release).Subscribe(r => IncompatibilityReason = r != null && !r.IsCompatible() ? $"Requires Artemis v{r.MinimumVersion} or later" : null);
|
||||
|
||||
InDetailsScreen = true;
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ public partial class EntryReleaseItemViewModel : ActivatableViewModelBase
|
||||
}).DisposeWith(d);
|
||||
|
||||
IsCurrentVersion = _workshopService.GetInstalledEntry(_entry.Id)?.ReleaseId == Release.Id;
|
||||
IncompatibilityReason = !Release.IsCompatible() ? $"Requires Artemis v{Version.FromLong(Release.MinimumVersion!.Value)} or later" : null;
|
||||
IncompatibilityReason = !Release.IsCompatible() ? $"Requires Artemis v{Release.MinimumVersion} or later" : null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -20,15 +20,21 @@ public class WorkshopUpdateService : IWorkshopUpdateService
|
||||
private readonly ILogger _logger;
|
||||
private readonly IWorkshopClient _client;
|
||||
private readonly IWorkshopService _workshopService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly Lazy<IUpdateNotificationProvider> _updateNotificationProvider;
|
||||
private readonly PluginSetting<bool> _showNotifications;
|
||||
|
||||
public WorkshopUpdateService(ILogger logger, IWorkshopClient client, IWorkshopService workshopService, ISettingsService settingsService,
|
||||
public WorkshopUpdateService(ILogger logger,
|
||||
IWorkshopClient client,
|
||||
IWorkshopService workshopService,
|
||||
ISettingsService settingsService,
|
||||
IPluginManagementService pluginManagementService,
|
||||
Lazy<IUpdateNotificationProvider> updateNotificationProvider)
|
||||
{
|
||||
_logger = logger;
|
||||
_client = client;
|
||||
_workshopService = workshopService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_updateNotificationProvider = updateNotificationProvider;
|
||||
_showNotifications = settingsService.GetSetting("Workshop.ShowNotifications", true);
|
||||
}
|
||||
@ -88,6 +94,18 @@ public class WorkshopUpdateService : IWorkshopUpdateService
|
||||
else
|
||||
_logger.Warning("Auto-update failed for entry {Entry}: {Message}", entry, updateResult.Message);
|
||||
|
||||
if (!updateResult.IsSuccess || updateResult.Installed is not Plugin {IsEnabled: false} updatedPlugin)
|
||||
return updateResult.IsSuccess;
|
||||
|
||||
try
|
||||
{
|
||||
_pluginManagementService.EnablePlugin(updatedPlugin, true, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warning(e, "Failed to auto-enable updated plugin {Plugin}", updatedPlugin);
|
||||
}
|
||||
|
||||
return updateResult.IsSuccess;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@ -101,9 +101,7 @@ public class PluginEntryInstallationHandler : IEntryInstallationHandler
|
||||
{
|
||||
// ignored, will get cleaned up as an orphaned file
|
||||
}
|
||||
|
||||
if (installedEntry.Entity.Id != Guid.Empty)
|
||||
_workshopService.RemoveInstalledEntry(installedEntry);
|
||||
|
||||
return EntryInstallResult.FromException(e);
|
||||
}
|
||||
|
||||
|
||||
@ -225,7 +225,6 @@ public class InstalledEntry : CorePropertyChanged
|
||||
IsOfficial = Entity.IsOfficial;
|
||||
Name = Entity.Name;
|
||||
Summary = Entity.Summary;
|
||||
EntryType = (EntryType) Entity.EntryType;
|
||||
Downloads = Entity.Downloads;
|
||||
CreatedAt = Entity.CreatedAt;
|
||||
LatestReleaseId = Entity.LatestReleaseId;
|
||||
@ -235,6 +234,15 @@ public class InstalledEntry : CorePropertyChanged
|
||||
ReleaseVersion = Entity.ReleaseVersion;
|
||||
InstalledAt = Entity.InstalledAt;
|
||||
AutoUpdate = Entity.AutoUpdate;
|
||||
|
||||
// Avoiding a cast here, the enum has shifted around before as it is generated from the GraphQL schema
|
||||
EntryType = Entity.EntryType switch
|
||||
{
|
||||
0 => EntryType.Plugin,
|
||||
1 => EntryType.Profile,
|
||||
2 => EntryType.Layout,
|
||||
_ => EntryType
|
||||
};
|
||||
|
||||
_metadata = Entity.Metadata != null ? new Dictionary<string, JsonNode>(Entity.Metadata) : [];
|
||||
}
|
||||
@ -242,8 +250,6 @@ public class InstalledEntry : CorePropertyChanged
|
||||
internal void Save()
|
||||
{
|
||||
Entity.EntryId = Id;
|
||||
Entity.EntryType = (int) EntryType;
|
||||
|
||||
Entity.Author = Author;
|
||||
Entity.IsOfficial = IsOfficial;
|
||||
Entity.Name = Name;
|
||||
@ -257,6 +263,15 @@ public class InstalledEntry : CorePropertyChanged
|
||||
Entity.ReleaseVersion = ReleaseVersion;
|
||||
Entity.InstalledAt = InstalledAt;
|
||||
Entity.AutoUpdate = AutoUpdate;
|
||||
|
||||
// Avoiding a cast here, the enum has shifted around before as it is generated from the GraphQL schema
|
||||
Entity.EntryType = EntryType switch
|
||||
{
|
||||
EntryType.Plugin => 0,
|
||||
EntryType.Profile => 1,
|
||||
EntryType.Layout => 2,
|
||||
_ => Entity.EntryType
|
||||
};
|
||||
|
||||
Entity.Metadata = new Dictionary<string, JsonNode>(_metadata);
|
||||
}
|
||||
|
||||
@ -26,9 +26,8 @@ public class WorkshopService : IWorkshopService
|
||||
private readonly IWorkshopClient _workshopClient;
|
||||
private readonly PluginSetting<bool> _migratedBuiltInPlugins;
|
||||
|
||||
|
||||
|
||||
private bool _initialized;
|
||||
private bool _mutating;
|
||||
|
||||
public WorkshopService(ILogger logger,
|
||||
IHttpClientFactory httpClientFactory,
|
||||
@ -173,27 +172,45 @@ public class WorkshopService : IWorkshopService
|
||||
/// <inheritdoc />
|
||||
public async Task<EntryInstallResult> InstallEntry(IEntrySummary entry, IRelease release, Progress<StreamProgress> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
IEntryInstallationHandler handler = _factory.CreateHandler(entry.EntryType);
|
||||
EntryInstallResult result = await handler.InstallAsync(entry, release, progress, cancellationToken);
|
||||
if (result.IsSuccess && result.Entry != null)
|
||||
OnEntryInstalled?.Invoke(this, result.Entry);
|
||||
else
|
||||
_logger.Warning("Failed to install entry {Entry}: {Message}", entry, result.Message);
|
||||
_mutating = true;
|
||||
|
||||
return result;
|
||||
try
|
||||
{
|
||||
IEntryInstallationHandler handler = _factory.CreateHandler(entry.EntryType);
|
||||
EntryInstallResult result = await handler.InstallAsync(entry, release, progress, cancellationToken);
|
||||
if (result.IsSuccess && result.Entry != null)
|
||||
OnEntryInstalled?.Invoke(this, result.Entry);
|
||||
else
|
||||
_logger.Warning("Failed to install entry {Entry}: {Message}", entry, result.Message);
|
||||
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mutating = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<EntryUninstallResult> UninstallEntry(InstalledEntry installedEntry, CancellationToken cancellationToken)
|
||||
{
|
||||
IEntryInstallationHandler handler = _factory.CreateHandler(installedEntry.EntryType);
|
||||
EntryUninstallResult result = await handler.UninstallAsync(installedEntry, cancellationToken);
|
||||
if (result.IsSuccess)
|
||||
OnEntryUninstalled?.Invoke(this, installedEntry);
|
||||
else
|
||||
_logger.Warning("Failed to uninstall entry {EntryId}: {Message}", installedEntry.Id, result.Message);
|
||||
_mutating = true;
|
||||
|
||||
return result;
|
||||
try
|
||||
{
|
||||
IEntryInstallationHandler handler = _factory.CreateHandler(installedEntry.EntryType);
|
||||
EntryUninstallResult result = await handler.UninstallAsync(installedEntry, cancellationToken);
|
||||
if (result.IsSuccess)
|
||||
OnEntryUninstalled?.Invoke(this, installedEntry);
|
||||
else
|
||||
_logger.Warning("Failed to uninstall entry {EntryId}: {Message}", installedEntry.Id, result.Message);
|
||||
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mutating = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -316,16 +333,28 @@ public class WorkshopService : IWorkshopService
|
||||
// If already migrated, do nothing
|
||||
if (_migratedBuiltInPlugins.Value)
|
||||
return;
|
||||
|
||||
MigratingBuildInPlugins?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
bool migrated = await BuiltInPluginsMigrator.Migrate(this, _workshopClient, _logger, _pluginRepository);
|
||||
_migratedBuiltInPlugins.Value = migrated;
|
||||
_migratedBuiltInPlugins.Save();
|
||||
_mutating = true;
|
||||
|
||||
try
|
||||
{
|
||||
MigratingBuildInPlugins?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
bool migrated = await BuiltInPluginsMigrator.Migrate(this, _workshopClient, _logger, _pluginRepository);
|
||||
_migratedBuiltInPlugins.Value = migrated;
|
||||
_migratedBuiltInPlugins.Save();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mutating = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfileServiceOnProfileRemoved(object? sender, ProfileConfigurationEventArgs e)
|
||||
{
|
||||
if (_mutating)
|
||||
return;
|
||||
|
||||
InstalledEntry? entry = GetInstalledEntryByProfile(e.ProfileConfiguration);
|
||||
if (entry == null)
|
||||
return;
|
||||
@ -336,6 +365,9 @@ public class WorkshopService : IWorkshopService
|
||||
|
||||
private void PluginManagementServiceOnPluginRemoved(object? sender, PluginEventArgs e)
|
||||
{
|
||||
if (_mutating)
|
||||
return;
|
||||
|
||||
InstalledEntry? entry = GetInstalledEntryByPlugin(e.Plugin);
|
||||
if (entry == null)
|
||||
return;
|
||||
@ -349,6 +381,6 @@ public class WorkshopService : IWorkshopService
|
||||
public event EventHandler<InstalledEntry>? OnEntryUninstalled;
|
||||
|
||||
public event EventHandler<InstalledEntry>? OnEntryInstalled;
|
||||
|
||||
|
||||
public event EventHandler? MigratingBuildInPlugins;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -59,8 +59,8 @@
|
||||
<PackageVersion Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||
<PackageVersion Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||
<PackageVersion Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="3.119.1" />
|
||||
<PackageVersion Include="SkiaSharp.Vulkan.SharpVk" Version="3.119.1" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.Vulkan.SharpVk" Version="2.88.9" />
|
||||
<PackageVersion Include="Splat.DryIoc" Version="17.1.1" />
|
||||
<PackageVersion Include="StrawberryShake.Server" Version="15.1.11" />
|
||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.15.0" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user