Browse Source

Fix Branch Mode

- Switch to Octokit instead of manually calling Github API
- Add DisplayVersion & InstalledBranch to InstalledPackage for update checks & display
- Fixed branch mode install now actually uses the commit hash
- Update check updated for branch mode
pull/5/head
JT 1 year ago
parent
commit
1ff445b949
  1. 23
      StabilityMatrix/Api/IGithubApi.cs
  2. 25
      StabilityMatrix/App.xaml.cs
  3. 31
      StabilityMatrix/Helper/Cache/GithubApiCache.cs
  4. 10
      StabilityMatrix/Helper/Cache/IGithubApiCache.cs
  5. 2
      StabilityMatrix/Helper/ISettingsManager.cs
  6. 9
      StabilityMatrix/Helper/SettingsManager.cs
  7. 7
      StabilityMatrix/InstallerWindow.xaml
  8. 13
      StabilityMatrix/Models/Api/GithubAuthor.cs
  9. 12
      StabilityMatrix/Models/Api/GithubBranch.cs
  10. 12
      StabilityMatrix/Models/Api/GithubCommit.cs
  11. 12
      StabilityMatrix/Models/Api/GithubCommitCommit.cs
  12. 12
      StabilityMatrix/Models/Api/GithubRelease.cs
  13. 4
      StabilityMatrix/Models/InstalledPackage.cs
  14. 1
      StabilityMatrix/Models/Packages/A3WebUI.cs
  15. 75
      StabilityMatrix/Models/Packages/BaseGitPackage.cs
  16. 15
      StabilityMatrix/Models/Packages/BasePackage.cs
  17. 1
      StabilityMatrix/Models/Packages/ComfyUI.cs
  18. 96
      StabilityMatrix/Models/Packages/DankDiffusion.cs
  19. 1
      StabilityMatrix/Models/Packages/VladAutomatic.cs
  20. 4
      StabilityMatrix/PackageManagerPage.xaml
  21. 1
      StabilityMatrix/StabilityMatrix.csproj
  22. 69
      StabilityMatrix/ViewModels/InstallerViewModel.cs
  23. 2
      StabilityMatrix/ViewModels/OneClickInstallViewModel.cs
  24. 4
      StabilityMatrix/ViewModels/PackageManagerViewModel.cs

23
StabilityMatrix/Api/IGithubApi.cs

@ -1,23 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Refit;
using StabilityMatrix.Models.Api;
namespace StabilityMatrix.Api;
[Headers("User-Agent: StabilityMatrix")]
public interface IGithubApi
{
[Get("/repos/{username}/{repository}/releases/latest")]
Task<GithubRelease> GetLatestRelease(string username, string repository);
[Get("/repos/{username}/{repository}/releases")]
Task<IEnumerable<GithubRelease>> GetAllReleases(string username, string repository);
[Get("/repos/{username}/{repository}/branches")]
Task<IEnumerable<GithubBranch>> GetAllBranches(string username, string repository);
[Get("/repos/{username}/{repository}/commits?sha={branch}")]
Task<IEnumerable<GithubCommit>> GetAllCommits(string username, string repository, string branch, int page = 1,
[AliasAs("per_page")] int perPage = 10);
}

25
StabilityMatrix/App.xaml.cs

@ -9,6 +9,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NLog.Extensions.Logging; using NLog.Extensions.Logging;
using Octokit;
using Polly; using Polly;
using Polly.Contrib.WaitAndRetry; using Polly.Contrib.WaitAndRetry;
using Polly.Extensions.Http; using Polly.Extensions.Http;
@ -24,6 +25,7 @@ using StabilityMatrix.Services;
using StabilityMatrix.ViewModels; using StabilityMatrix.ViewModels;
using Wpf.Ui.Contracts; using Wpf.Ui.Contracts;
using Wpf.Ui.Services; using Wpf.Ui.Services;
using Application = System.Windows.Application;
namespace StabilityMatrix namespace StabilityMatrix
{ {
@ -86,6 +88,16 @@ namespace StabilityMatrix
serviceCollection.AddSingleton<ISettingsManager, SettingsManager>(); serviceCollection.AddSingleton<ISettingsManager, SettingsManager>();
serviceCollection.AddSingleton<IPrerequisiteHelper, PrerequisiteHelper>(); serviceCollection.AddSingleton<IPrerequisiteHelper, PrerequisiteHelper>();
serviceCollection.AddSingleton<IDialogErrorHandler, DialogErrorHandler>(); serviceCollection.AddSingleton<IDialogErrorHandler, DialogErrorHandler>();
serviceCollection.AddTransient<IGitHubClient, GitHubClient>(_ =>
{
var client = new GitHubClient(new ProductHeaderValue("StabilityMatrix"));
var githubApiKey = Config["GithubApiKey"];
if (string.IsNullOrWhiteSpace(githubApiKey))
return client;
client.Credentials = new Credentials(githubApiKey);
return client;
});
serviceCollection.AddMemoryCache(); serviceCollection.AddMemoryCache();
serviceCollection.AddSingleton<IGithubApiCache, GithubApiCache>(); serviceCollection.AddSingleton<IGithubApiCache, GithubApiCache>();
@ -106,19 +118,6 @@ namespace StabilityMatrix
.WaitAndRetryAsync(delay); .WaitAndRetryAsync(delay);
// Add Refit clients // Add Refit clients
serviceCollection.AddRefitClient<IGithubApi>(defaultRefitSettings)
.ConfigureHttpClient(c =>
{
c.BaseAddress = new Uri("https://api.github.com");
c.Timeout = TimeSpan.FromSeconds(5);
var githubApiKey = Config["GithubApiKey"];
if (!string.IsNullOrEmpty(githubApiKey))
{
c.DefaultRequestHeaders.Add("Authorization", $"Bearer {githubApiKey}");
}
})
.AddPolicyHandler(retryPolicy);
serviceCollection.AddRefitClient<IA3WebApi>(defaultRefitSettings) serviceCollection.AddRefitClient<IA3WebApi>(defaultRefitSettings)
.ConfigureHttpClient(c => .ConfigureHttpClient(c =>
{ {

31
StabilityMatrix/Helper/Cache/GithubApiCache.cs

@ -1,7 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Octokit;
using StabilityMatrix.Api; using StabilityMatrix.Api;
using StabilityMatrix.Models.Api; using StabilityMatrix.Models.Api;
@ -10,52 +12,61 @@ namespace StabilityMatrix.Helper.Cache;
public class GithubApiCache : IGithubApiCache public class GithubApiCache : IGithubApiCache
{ {
private readonly IMemoryCache memoryCache; private readonly IMemoryCache memoryCache;
private readonly IGithubApi githubApi; private readonly IGitHubClient githubApi;
private readonly TimeSpan cacheDuration = TimeSpan.FromMinutes(5); private readonly TimeSpan cacheDuration = TimeSpan.FromMinutes(5);
public GithubApiCache(IMemoryCache memoryCache, IGithubApi githubApi) public GithubApiCache(IMemoryCache memoryCache, IGitHubClient githubApi)
{ {
this.memoryCache = memoryCache; this.memoryCache = memoryCache;
this.githubApi = githubApi; this.githubApi = githubApi;
} }
public Task<GithubRelease> GetLatestRelease(string username, string repository) public Task<Release> GetLatestRelease(string username, string repository)
{ {
var cacheKey = $"LatestRelease-{username}-{repository}"; var cacheKey = $"LatestRelease-{username}-{repository}";
return memoryCache.GetOrCreateAsync(cacheKey, async entry => return memoryCache.GetOrCreateAsync(cacheKey, async entry =>
{ {
entry.SlidingExpiration = cacheDuration; entry.SlidingExpiration = cacheDuration;
return await githubApi.GetLatestRelease(username, repository); return await githubApi.Repository.Release.GetLatest(username, repository);
})!; })!;
} }
public Task<IEnumerable<GithubRelease>> GetAllReleases(string username, string repository) public Task<IOrderedEnumerable<Release>> GetAllReleases(string username, string repository)
{ {
var cacheKey = $"Releases-{username}-{repository}"; var cacheKey = $"Releases-{username}-{repository}";
return memoryCache.GetOrCreateAsync(cacheKey, async entry => return memoryCache.GetOrCreateAsync(cacheKey, async entry =>
{ {
entry.SlidingExpiration = cacheDuration; entry.SlidingExpiration = cacheDuration;
return await githubApi.GetAllReleases(username, repository); var allReleases = await githubApi.Repository.Release.GetAll(username, repository);
return allReleases.OrderByDescending(x => x.CreatedAt);
})!; })!;
} }
public Task<IEnumerable<GithubBranch>> GetAllBranches(string username, string repository) public Task<IReadOnlyList<Branch>> GetAllBranches(string username, string repository)
{ {
var cacheKey = $"Branches-{username}-{repository}"; var cacheKey = $"Branches-{username}-{repository}";
return memoryCache.GetOrCreateAsync(cacheKey, async entry => return memoryCache.GetOrCreateAsync(cacheKey, async entry =>
{ {
entry.SlidingExpiration = cacheDuration; entry.SlidingExpiration = cacheDuration;
return await githubApi.GetAllBranches(username, repository); var allReleases = await githubApi.Repository.Branch.GetAll(username, repository);
return allReleases;
})!; })!;
} }
public Task<IEnumerable<GithubCommit>> GetAllCommits(string username, string repository, string branch, int page = 1, int perPage = 10) public Task<IReadOnlyList<GitHubCommit>?> GetAllCommits(string username, string repository, string branch, int page = 1, int perPage = 10)
{ {
var cacheKey = $"Commits-{username}-{repository}-{branch}-{page}-{perPage}"; var cacheKey = $"Commits-{username}-{repository}-{branch}-{page}-{perPage}";
return memoryCache.GetOrCreateAsync(cacheKey, async entry => return memoryCache.GetOrCreateAsync(cacheKey, async entry =>
{ {
entry.SlidingExpiration = cacheDuration; entry.SlidingExpiration = cacheDuration;
return await githubApi.GetAllCommits(username, repository, branch, page, perPage); return await githubApi.Repository.Commit.GetAll(username, repository, new CommitRequest {Sha = branch},
new ApiOptions
{
PageCount = page,
PageSize = perPage,
StartPage = page
});
})!; })!;
} }
} }

10
StabilityMatrix/Helper/Cache/IGithubApiCache.cs

@ -1,5 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Octokit;
using Refit; using Refit;
using StabilityMatrix.Models.Api; using StabilityMatrix.Models.Api;
@ -7,12 +9,12 @@ namespace StabilityMatrix.Helper.Cache;
public interface IGithubApiCache public interface IGithubApiCache
{ {
Task<GithubRelease> GetLatestRelease(string username, string repository); Task<Release> GetLatestRelease(string username, string repository);
Task<IEnumerable<GithubRelease>> GetAllReleases(string username, string repository); Task<IOrderedEnumerable<Release>> GetAllReleases(string username, string repository);
Task<IEnumerable<GithubBranch>> GetAllBranches(string username, string repository); Task<IReadOnlyList<Branch>> GetAllBranches(string username, string repository);
Task<IEnumerable<GithubCommit>> GetAllCommits(string username, string repository, string branch, int page = 1, Task<IReadOnlyList<GitHubCommit>?> GetAllCommits(string username, string repository, string branch, int page = 1,
[AliasAs("per_page")] int perPage = 10); [AliasAs("per_page")] int perPage = 10);
} }

2
StabilityMatrix/Helper/ISettingsManager.cs

@ -12,7 +12,7 @@ public interface ISettingsManager
void RemoveInstalledPackage(InstalledPackage p); void RemoveInstalledPackage(InstalledPackage p);
void SetActiveInstalledPackage(InstalledPackage? p); void SetActiveInstalledPackage(InstalledPackage? p);
void SetNavExpanded(bool navExpanded); void SetNavExpanded(bool navExpanded);
void UpdatePackageVersionNumber(string name, string? newVersion); void UpdatePackageVersionNumber(Guid id, string? newVersion);
void SetLastUpdateCheck(InstalledPackage package); void SetLastUpdateCheck(InstalledPackage package);
List<LaunchOption> GetLaunchArgs(Guid packageId); List<LaunchOption> GetLaunchArgs(Guid packageId);
void SaveLaunchArgs(Guid packageId, List<LaunchOption> launchArgs); void SaveLaunchArgs(Guid packageId, List<LaunchOption> launchArgs);

9
StabilityMatrix/Helper/SettingsManager.cs

@ -63,15 +63,20 @@ public class SettingsManager : ISettingsManager
SaveSettings(); SaveSettings();
} }
public void UpdatePackageVersionNumber(string name, string? newVersion) public void UpdatePackageVersionNumber(Guid id, string? newVersion)
{ {
var package = Settings.InstalledPackages.FirstOrDefault(x => x.DisplayName == name); var package = Settings.InstalledPackages.FirstOrDefault(x => x.Id == id);
if (package == null || newVersion == null) if (package == null || newVersion == null)
{ {
return; return;
} }
package.PackageVersion = newVersion; package.PackageVersion = newVersion;
package.DisplayVersion = string.IsNullOrWhiteSpace(package.InstalledBranch)
? newVersion
: $"{package.InstalledBranch}@{newVersion[..7]}";
SaveSettings(); SaveSettings();
} }

7
StabilityMatrix/InstallerWindow.xaml

@ -26,7 +26,8 @@
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:viewModels="clr-namespace:StabilityMatrix.ViewModels" xmlns:viewModels="clr-namespace:StabilityMatrix.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xaml="clr-namespace:Markdown.Xaml;assembly=Markdown.Xaml"> xmlns:xaml="clr-namespace:Markdown.Xaml;assembly=Markdown.Xaml"
xmlns:octokit="clr-namespace:Octokit;assembly=Octokit">
<ui:FluentWindow.Resources> <ui:FluentWindow.Resources>
<converters:ValueConverterGroup x:Key="InvertAndVisibilitate"> <converters:ValueConverterGroup x:Key="InvertAndVisibilitate">
@ -173,12 +174,12 @@
MinWidth="100" MinWidth="100"
SelectedItem="{Binding SelectedCommit}"> SelectedItem="{Binding SelectedCommit}">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type api:GithubCommit}"> <DataTemplate DataType="{x:Type octokit:GitHubCommit}">
<StackPanel Margin="8,0,0,0" VerticalAlignment="Top"> <StackPanel Margin="8,0,0,0" VerticalAlignment="Top">
<TextBlock <TextBlock
Margin="0,4,0,4" Margin="0,4,0,4"
Name="NameTextBlock" Name="NameTextBlock"
Text="{Binding ShaHash}" /> Text="{Binding Sha}" />
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>

13
StabilityMatrix/Models/Api/GithubAuthor.cs

@ -1,13 +0,0 @@
using System;
using System.Text.Json.Serialization;
namespace StabilityMatrix.Models.Api;
public class GithubAuthor
{
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("date")]
public DateTimeOffset DateCommitted { get; set; }
}

12
StabilityMatrix/Models/Api/GithubBranch.cs

@ -1,12 +0,0 @@
using System.Text.Json.Serialization;
namespace StabilityMatrix.Models.Api;
public class GithubBranch
{
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("commit")]
public GithubCommit Commit { get; set; }
}

12
StabilityMatrix/Models/Api/GithubCommit.cs

@ -1,12 +0,0 @@
using System.Text.Json.Serialization;
namespace StabilityMatrix.Models.Api;
public class GithubCommit
{
[JsonPropertyName("sha")]
public string ShaHash { get; set; }
[JsonPropertyName("commit")]
public GithubCommitCommit? Commit { get; set; }
}

12
StabilityMatrix/Models/Api/GithubCommitCommit.cs

@ -1,12 +0,0 @@
using System.Text.Json.Serialization;
namespace StabilityMatrix.Models.Api;
public class GithubCommitCommit
{
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("author")]
public GithubAuthor Author { get; set; }
}

12
StabilityMatrix/Models/Api/GithubRelease.cs

@ -1,12 +0,0 @@
using System.Text.Json.Serialization;
namespace StabilityMatrix.Models.Api;
public class GithubRelease
{
[JsonPropertyName("tag_name")]
public string? TagName { get; set; }
[JsonPropertyName("body")]
public string Body { get; set; }
}

4
StabilityMatrix/Models/InstalledPackage.cs

@ -17,6 +17,10 @@ public class InstalledPackage
public string? PackageName { get; set; } public string? PackageName { get; set; }
// Package version // Package version
public string? PackageVersion { get; set; } public string? PackageVersion { get; set; }
public string? InstalledBranch { get; set; }
public string? DisplayVersion { get; set; }
// Install path // Install path
public string? Path { get; set; } public string? Path { get; set; }
public string? LaunchCommand { get; set; } public string? LaunchCommand { get; set; }

1
StabilityMatrix/Models/Packages/A3WebUI.cs

@ -16,6 +16,7 @@ public class A3WebUI : BaseGitPackage
public override string DisplayName { get; set; } = "stable-diffusion-webui"; public override string DisplayName { get; set; } = "stable-diffusion-webui";
public override string Author => "AUTOMATIC1111"; public override string Author => "AUTOMATIC1111";
public override string LaunchCommand => "launch.py"; public override string LaunchCommand => "launch.py";
public override bool ShouldIgnoreReleases => false;
public string RelativeArgsDefinitionScriptPath => "modules.cmd_args"; public string RelativeArgsDefinitionScriptPath => "modules.cmd_args";

75
StabilityMatrix/Models/Packages/BaseGitPackage.cs

@ -9,11 +9,13 @@ using System.Net.Http.Headers;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using NLog; using NLog;
using Refit; using Octokit;
using StabilityMatrix.Helper; using StabilityMatrix.Helper;
using StabilityMatrix.Helper.Cache; using StabilityMatrix.Helper.Cache;
using StabilityMatrix.Models.Api; using StabilityMatrix.Models.Api;
using StabilityMatrix.Python; using StabilityMatrix.Python;
using ApiException = Refit.ApiException;
using FileMode = System.IO.FileMode;
namespace StabilityMatrix.Models.Packages; namespace StabilityMatrix.Models.Packages;
@ -42,30 +44,35 @@ public abstract class BaseGitPackage : BasePackage
public override string InstallLocation { get; set; } = public override string InstallLocation { get; set; } =
$"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages"; $"{Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)}\\StabilityMatrix\\Packages";
protected string GetDownloadUrl(string tagName) => $"https://api.github.com/repos/{Author}/{Name}/zipball/{tagName}"; protected string GetDownloadUrl(string tagName, bool isCommitHash = false)
{
return isCommitHash
? $"https://github.com/{Author}/{Name}/archive/{tagName}.zip"
: $"https://api.github.com/repos/{Author}/{Name}/zipball/{tagName}";
}
protected BaseGitPackage(IGithubApiCache githubApi, ISettingsManager settingsManager) protected BaseGitPackage(IGithubApiCache githubApi, ISettingsManager settingsManager)
{ {
this.GithubApi = githubApi; GithubApi = githubApi;
this.SettingsManager = settingsManager; SettingsManager = settingsManager;
} }
protected Task<GithubRelease> GetLatestRelease() protected Task<Release> GetLatestRelease()
{ {
return GithubApi.GetLatestRelease(Author, Name); return GithubApi.GetLatestRelease(Author, Name);
} }
public override Task<IEnumerable<GithubBranch>> GetAllBranches() public override Task<IReadOnlyList<Branch>> GetAllBranches()
{ {
return GithubApi.GetAllBranches(Author, Name); return GithubApi.GetAllBranches(Author, Name);
} }
public override Task<IEnumerable<GithubRelease>> GetAllReleases() public override Task<IOrderedEnumerable<Release>> GetAllReleases()
{ {
return GithubApi.GetAllReleases(Author, Name); return GithubApi.GetAllReleases(Author, Name);
} }
public override Task<IEnumerable<GithubCommit>> GetAllCommits(string branch, int page = 1, int perPage = 10) public override Task<IReadOnlyList<GitHubCommit>?> GetAllCommits(string branch, int page = 1, int perPage = 10)
{ {
return GithubApi.GetAllCommits(Author, Name, branch, page, perPage); return GithubApi.GetAllCommits(Author, Name, branch, page, perPage);
} }
@ -88,15 +95,15 @@ public abstract class BaseGitPackage : BasePackage
return VenvRunner; return VenvRunner;
} }
public override async Task<IEnumerable<GithubRelease>> GetReleaseTags() public override async Task<IOrderedEnumerable<Release>> GetReleaseTags()
{ {
var allReleases = await GithubApi.GetAllReleases(Author, Name); var allReleases = await GithubApi.GetAllReleases(Author, Name);
return allReleases; return allReleases;
} }
public override async Task<string?> DownloadPackage(string version, bool isUpdate = false) public override async Task<string?> DownloadPackage(string version, bool isCommitHash, bool isUpdate = false)
{ {
var downloadUrl = GetDownloadUrl(version); var downloadUrl = GetDownloadUrl(version, isCommitHash);
if (!Directory.Exists(DownloadLocation.Replace($"{Name}.zip", ""))) if (!Directory.Exists(DownloadLocation.Replace($"{Name}.zip", "")))
{ {
@ -107,7 +114,6 @@ public abstract class BaseGitPackage : BasePackage
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("StabilityMatrix", "1.0")); client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("StabilityMatrix", "1.0"));
await using var file = new FileStream(DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.None); await using var file = new FileStream(DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.None);
long contentLength = 0; long contentLength = 0;
var retryCount = 0; var retryCount = 0;
var response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead); var response = await client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead);
@ -236,18 +242,29 @@ public abstract class BaseGitPackage : BasePackage
public override async Task<bool> CheckForUpdates(string installedPackageName) public override async Task<bool> CheckForUpdates(string installedPackageName)
{ {
var currentVersion = SettingsManager.Settings.InstalledPackages.FirstOrDefault(x => x.DisplayName == installedPackageName) var package =
?.PackageVersion; SettingsManager.Settings.InstalledPackages.FirstOrDefault(x => x.DisplayName == installedPackageName);
if (string.IsNullOrWhiteSpace(currentVersion)) var currentVersion = package?.PackageVersion;
if (package == null || string.IsNullOrWhiteSpace(currentVersion))
{ {
return false; return false;
} }
try try
{ {
var latestVersion = await GetLatestVersion(); if (string.IsNullOrWhiteSpace(package.InstalledBranch))
UpdateAvailable = latestVersion != currentVersion; {
return latestVersion != currentVersion; var latestVersion = await GetLatestVersion();
UpdateAvailable = latestVersion != currentVersion;
return latestVersion != currentVersion;
}
else
{
var allCommits = await GetAllCommits(package.InstalledBranch);
var latestCommitHash = allCommits.First().Sha;
return latestCommitHash != currentVersion;
}
} }
catch (ApiException e) catch (ApiException e)
{ {
@ -256,12 +273,24 @@ public abstract class BaseGitPackage : BasePackage
} }
} }
public override async Task<string> Update() public override async Task<string> Update(InstalledPackage installedPackage)
{ {
var version = await GetLatestVersion(); if (string.IsNullOrWhiteSpace(installedPackage.InstalledBranch))
await DownloadPackage(version, true); {
await InstallPackage(true); var releases = await GetAllReleases();
return version; var latestRelease = releases.First();
await DownloadPackage(latestRelease.TagName, false);
await InstallPackage(true);
return latestRelease.TagName;
}
else
{
var allCommits = await GetAllCommits(installedPackage.InstalledBranch);
var latestCommit = allCommits.First();
await DownloadPackage(latestCommit.Sha, true, true);
await InstallPackage(true);
return latestCommit.Sha;
}
} }

15
StabilityMatrix/Models/Packages/BasePackage.cs

@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Octokit;
using StabilityMatrix.Models.Api; using StabilityMatrix.Models.Api;
namespace StabilityMatrix.Models; namespace StabilityMatrix.Models;
@ -12,23 +14,24 @@ public abstract class BasePackage
public abstract string Author { get; } public abstract string Author { get; }
public abstract string GithubUrl { get; } public abstract string GithubUrl { get; }
public abstract string LaunchCommand { get; } public abstract string LaunchCommand { get; }
public abstract bool ShouldIgnoreReleases { get; }
public virtual bool UpdateAvailable { get; set; } public virtual bool UpdateAvailable { get; set; }
public abstract Task<string?> DownloadPackage(string version, bool isUpdate = false); public abstract Task<string?> DownloadPackage(string version, bool isCommitHash, bool isUpdate = false);
public abstract Task InstallPackage(bool isUpdate = false); public abstract Task InstallPackage(bool isUpdate = false);
public abstract Task RunPackage(string installedPackagePath, string arguments); public abstract Task RunPackage(string installedPackagePath, string arguments);
public abstract Task Shutdown(); public abstract Task Shutdown();
public abstract Task<bool> CheckForUpdates(string installedPackageName); public abstract Task<bool> CheckForUpdates(string installedPackageName);
public abstract Task<string> Update(); public abstract Task<string> Update(InstalledPackage installedPackage);
public abstract Task<IEnumerable<GithubRelease>> GetReleaseTags(); public abstract Task<IOrderedEnumerable<Release>> GetReleaseTags();
public abstract List<LaunchOptionDefinition> LaunchOptions { get; } public abstract List<LaunchOptionDefinition> LaunchOptions { get; }
public virtual string? ExtraLaunchArguments { get; set; } = null; public virtual string? ExtraLaunchArguments { get; set; } = null;
public abstract Task<string> GetLatestVersion(); public abstract Task<string> GetLatestVersion();
public abstract Task<IEnumerable<PackageVersion>> GetAllVersions(bool isReleaseMode = true); public abstract Task<IEnumerable<PackageVersion>> GetAllVersions(bool isReleaseMode = true);
public abstract Task<IEnumerable<GithubCommit>> GetAllCommits(string branch, int page = 1, int perPage = 10); public abstract Task<IReadOnlyList<GitHubCommit>?> GetAllCommits(string branch, int page = 1, int perPage = 10);
public abstract Task<IEnumerable<GithubBranch>> GetAllBranches(); public abstract Task<IReadOnlyList<Branch>> GetAllBranches();
public abstract Task<IEnumerable<GithubRelease>> GetAllReleases(); public abstract Task<IOrderedEnumerable<Release>> GetAllReleases();
public abstract string DownloadLocation { get; } public abstract string DownloadLocation { get; }
public abstract string InstallLocation { get; set; } public abstract string InstallLocation { get; set; }

1
StabilityMatrix/Models/Packages/ComfyUI.cs

@ -19,6 +19,7 @@ public class ComfyUI : BaseGitPackage
public override string DisplayName { get; set; } = "ComfyUI"; public override string DisplayName { get; set; } = "ComfyUI";
public override string Author => "comfyanonymous"; public override string Author => "comfyanonymous";
public override string LaunchCommand => "main.py"; public override string LaunchCommand => "main.py";
public override bool ShouldIgnoreReleases => true;
public ComfyUI(IGithubApiCache githubApi, ISettingsManager settingsManager) : base(githubApi, settingsManager) public ComfyUI(IGithubApiCache githubApi, ISettingsManager settingsManager) : base(githubApi, settingsManager)
{ {

96
StabilityMatrix/Models/Packages/DankDiffusion.cs

@ -1,96 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using StabilityMatrix.Models.Api;
namespace StabilityMatrix.Models.Packages;
public class DankDiffusion : BasePackage
{
public override string Name => "dank-diffusion";
public override string DisplayName { get; set; } = "dank-diffusion";
public override string Author => "mohnjiles";
public override string GithubUrl => "https://github.com/mohnjiles/dank-diffusion";
public override string LaunchCommand => "";
public override Task<IEnumerable<GithubRelease>> GetReleaseTags()
{
throw new System.NotImplementedException();
}
public override List<LaunchOptionDefinition> LaunchOptions => new()
{
new LaunchOptionDefinition
{
Name = "API",
Options = new List<string> { "--api" }
},
new LaunchOptionDefinition
{
Name = "VRAM",
Options = new List<string> { "--lowvram", "--medvram" }
},
new LaunchOptionDefinition
{
Name = "Xformers",
Options = new List<string> { "--xformers" }
},
LaunchOptionDefinition.Extras
};
public override Task<string> GetLatestVersion()
{
throw new System.NotImplementedException();
}
public override Task<IEnumerable<PackageVersion>> GetAllVersions(bool isReleaseMode = true)
{
throw new System.NotImplementedException();
}
public override Task<IEnumerable<GithubCommit>> GetAllCommits(string branch, int page = 1, int perPage = 10)
{
throw new System.NotImplementedException();
}
public override Task<IEnumerable<GithubRelease>> GetAllReleases()
{
throw new System.NotImplementedException();
}
public override string DownloadLocation { get; }
public override string InstallLocation { get; set; }
public override Task<IEnumerable<GithubBranch>> GetAllBranches()
{
throw new System.NotImplementedException();
}
public override Task<string?> DownloadPackage(string version, bool isUpdate = false)
{
throw new System.NotImplementedException();
}
public override Task InstallPackage(bool isUpdate = false)
{
throw new System.NotImplementedException();
}
public override Task RunPackage(string installedPackagePath, string arguments)
{
throw new System.NotImplementedException();
}
public override Task Shutdown()
{
throw new System.NotImplementedException();
}
public override Task<bool> CheckForUpdates(string installedPackageName)
{
throw new System.NotImplementedException();
}
public override Task<string?> Update()
{
throw new System.NotImplementedException();
}
}

1
StabilityMatrix/Models/Packages/VladAutomatic.cs

@ -15,6 +15,7 @@ public class VladAutomatic : BaseGitPackage
public override string DisplayName { get; set; } = "SD.Next Web UI"; public override string DisplayName { get; set; } = "SD.Next Web UI";
public override string Author => "vladmandic"; public override string Author => "vladmandic";
public override string LaunchCommand => "launch.py"; public override string LaunchCommand => "launch.py";
public override bool ShouldIgnoreReleases => true;
public VladAutomatic(IGithubApiCache githubApi, ISettingsManager settingsManager) : base(githubApi, settingsManager) public VladAutomatic(IGithubApiCache githubApi, ISettingsManager settingsManager) : base(githubApi, settingsManager)
{ {

4
StabilityMatrix/PackageManagerPage.xaml

@ -92,7 +92,7 @@
<DataTemplate DataType="{x:Type models:InstalledPackage}"> <DataTemplate DataType="{x:Type models:InstalledPackage}">
<StackPanel Margin="8" VerticalAlignment="Top"> <StackPanel Margin="8" VerticalAlignment="Top">
<TextBlock Margin="0,5,0,5" Text="{Binding DisplayName}" /> <TextBlock Margin="0,5,0,5" Text="{Binding DisplayName}" />
<TextBlock Margin="0,0,0,5" Text="{Binding PackageVersion}" /> <TextBlock Margin="0,0,0,5" Text="{Binding DisplayVersion}" />
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
</ListView.ItemTemplate> </ListView.ItemTemplate>
@ -106,7 +106,7 @@
Text="{Binding SelectedPackage.DisplayName, FallbackValue=Stable Diffusion Web UI}" /> Text="{Binding SelectedPackage.DisplayName, FallbackValue=Stable Diffusion Web UI}" />
<TextBlock FontSize="12" Margin="0,5,0,5"> <TextBlock FontSize="12" Margin="0,5,0,5">
<Run Text="{Binding SelectedPackage.PackageName, FallbackValue=stable-diffusion-webui}" /> <Run Text="{Binding SelectedPackage.PackageName, FallbackValue=stable-diffusion-webui}" />
<Run Text="{Binding SelectedPackage.PackageVersion, FallbackValue=v1.3.37}" /> <Run Text="{Binding SelectedPackage.DisplayVersion, FallbackValue=v1.3.37}" />
</TextBlock> </TextBlock>
<TextBlock <TextBlock
FontSize="12" FontSize="12"

1
StabilityMatrix/StabilityMatrix.csproj

@ -22,6 +22,7 @@
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" /> <PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />
<PackageReference Include="NLog" Version="5.1.4" /> <PackageReference Include="NLog" Version="5.1.4" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.3" /> <PackageReference Include="NLog.Extensions.Logging" Version="5.2.3" />
<PackageReference Include="Octokit" Version="6.0.0" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" /> <PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="Polly" Version="7.2.3" /> <PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" /> <PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" />

69
StabilityMatrix/ViewModels/InstallerViewModel.cs

@ -9,11 +9,14 @@ using System.Windows.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Octokit;
using StabilityMatrix.Helper; using StabilityMatrix.Helper;
using StabilityMatrix.Models; using StabilityMatrix.Models;
using StabilityMatrix.Models.Api; using StabilityMatrix.Models.Api;
using StabilityMatrix.Python; using StabilityMatrix.Python;
using Application = System.Windows.Application;
using EventManager = StabilityMatrix.Helper.EventManager; using EventManager = StabilityMatrix.Helper.EventManager;
using PackageVersion = StabilityMatrix.Models.PackageVersion;
namespace StabilityMatrix.ViewModels; namespace StabilityMatrix.ViewModels;
@ -59,10 +62,10 @@ public partial class InstallerViewModel : ObservableObject
private ObservableCollection<BasePackage> availablePackages; private ObservableCollection<BasePackage> availablePackages;
[ObservableProperty] [ObservableProperty]
private ObservableCollection<GithubCommit> availableCommits; private ObservableCollection<GitHubCommit> availableCommits;
[ObservableProperty] [ObservableProperty]
private GithubCommit selectedCommit; private GitHubCommit selectedCommit;
[ObservableProperty] [ObservableProperty]
private string releaseNotes; private string releaseNotes;
@ -118,19 +121,31 @@ public partial class InstallerViewModel : ObservableObject
if (SelectedPackage == null) if (SelectedPackage == null)
return; return;
var releases = (await SelectedPackage.GetAllReleases()).ToList(); if (SelectedPackage.ShouldIgnoreReleases)
if (!releases.Any())
{ {
IsReleaseMode = false; IsReleaseMode = false;
} }
var versions = (await SelectedPackage.GetAllVersions()).ToList(); if (IsReleaseMode)
AvailableVersions = new ObservableCollection<PackageVersion>(versions); {
if (!AvailableVersions.Any()) var versions = (await SelectedPackage.GetAllVersions()).ToList();
return; AvailableVersions = new ObservableCollection<PackageVersion>(versions);
if (!AvailableVersions.Any())
return;
SelectedVersion = AvailableVersions[0];
}
else
{
var branches = (await SelectedPackage.GetAllBranches()).ToList();
AvailableVersions = new ObservableCollection<PackageVersion>(branches.Select(b => new PackageVersion
{
TagName = b.Name,
ReleaseNotesMarkdown = b.Commit.Label
}));
SelectedVersion = AvailableVersions.FirstOrDefault(x => x.TagName == "master") ?? AvailableVersions[0];
}
SelectedVersion = AvailableVersions[0]; ReleaseNotes = SelectedVersion.ReleaseNotesMarkdown;
ReleaseNotes = versions.First().ReleaseNotesMarkdown;
} }
partial void OnSelectedPackageChanged(BasePackage? value) partial void OnSelectedPackageChanged(BasePackage? value)
@ -140,13 +155,13 @@ public partial class InstallerViewModel : ObservableObject
InstallName = value.DisplayName; InstallName = value.DisplayName;
ReleaseNotes = string.Empty; ReleaseNotes = string.Empty;
AvailableVersions?.Clear(); AvailableVersions?.Clear();
AvailableCommits?.Clear();
// This can swallow exceptions if you don't explicitly try/catch // This can swallow exceptions if you don't explicitly try/catch
// Idk how to make it better tho // Idk how to make it better tho
Task.Run(async () => Task.Run(async () =>
{ {
var releases = (await SelectedPackage.GetAllReleases()).ToList(); if (SelectedPackage.ShouldIgnoreReleases)
if (!releases.Any())
{ {
Application.Current.Dispatcher.Invoke(() => Application.Current.Dispatcher.Invoke(() =>
{ {
@ -175,7 +190,7 @@ public partial class InstallerViewModel : ObservableObject
var commits = await value.GetAllCommits(SelectedVersion.TagName); var commits = await value.GetAllCommits(SelectedVersion.TagName);
Application.Current.Dispatcher.Invoke(() => Application.Current.Dispatcher.Invoke(() =>
{ {
AvailableCommits = new ObservableCollection<GithubCommit>(commits); AvailableCommits = new ObservableCollection<GitHubCommit>(commits);
SelectedCommit = AvailableCommits[0]; SelectedCommit = AvailableCommits[0];
SelectedVersion = AvailableVersions.First(x => x.TagName == "master"); SelectedVersion = AvailableVersions.First(x => x.TagName == "master");
}); });
@ -216,9 +231,12 @@ public partial class InstallerViewModel : ObservableObject
try try
{ {
var hashes = await SelectedPackage.GetAllCommits(value.TagName); var hashes = await SelectedPackage.GetAllCommits(value.TagName);
AvailableCommits = new ObservableCollection<GithubCommit>(hashes);
await Task.Delay(10); // or it doesn't work sometimes? lolwut? Application.Current.Dispatcher.Invoke(() =>
SelectedCommit = AvailableCommits[0]; {
AvailableCommits = new ObservableCollection<GitHubCommit>(hashes);
SelectedCommit = AvailableCommits[0];
});
} }
catch (Exception e) catch (Exception e)
{ {
@ -230,6 +248,8 @@ public partial class InstallerViewModel : ObservableObject
private async Task ActuallyInstall() private async Task ActuallyInstall()
{ {
var isCurrentlyReleaseMode = IsReleaseMode;
var installSuccess = await InstallGitIfNecessary(); var installSuccess = await InstallGitIfNecessary();
if (!installSuccess) if (!installSuccess)
{ {
@ -254,7 +274,9 @@ public partial class InstallerViewModel : ObservableObject
} }
} }
var version = await DownloadPackage(SelectedVersion.TagName); var version = isCurrentlyReleaseMode
? await DownloadPackage(SelectedVersion.TagName, false)
: await DownloadPackage(SelectedCommit.Sha, true);
await InstallPackage(); await InstallPackage();
ProgressText = "Done"; ProgressText = "Done";
@ -262,6 +284,8 @@ public partial class InstallerViewModel : ObservableObject
IsIndeterminate = false; IsIndeterminate = false;
SelectedPackageOnProgressChanged(this, 100); SelectedPackageOnProgressChanged(this, 100);
var branch = isCurrentlyReleaseMode ? null : SelectedVersion.TagName;
var package = new InstalledPackage var package = new InstalledPackage
{ {
DisplayName = SelectedPackage.DisplayName, DisplayName = SelectedPackage.DisplayName,
@ -269,6 +293,8 @@ public partial class InstallerViewModel : ObservableObject
Id = Guid.NewGuid(), Id = Guid.NewGuid(),
PackageName = SelectedPackage.Name, PackageName = SelectedPackage.Name,
PackageVersion = version, PackageVersion = version,
DisplayVersion = GetDisplayVersion(version, branch),
InstalledBranch = branch,
LaunchCommand = SelectedPackage.LaunchCommand, LaunchCommand = SelectedPackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now LastUpdateCheck = DateTimeOffset.Now
}; };
@ -278,12 +304,17 @@ public partial class InstallerViewModel : ObservableObject
ProgressValue = 0; ProgressValue = 0;
} }
private Task<string?> DownloadPackage(string version) private string GetDisplayVersion(string version, string? branch)
{
return branch == null ? version : $"{branch}@{version[..7]}";
}
private Task<string?> DownloadPackage(string version, bool isCommitHash)
{ {
SelectedPackage.DownloadProgressChanged += SelectedPackageOnProgressChanged; SelectedPackage.DownloadProgressChanged += SelectedPackageOnProgressChanged;
SelectedPackage.DownloadComplete += (_, _) => ProgressText = "Download Complete"; SelectedPackage.DownloadComplete += (_, _) => ProgressText = "Download Complete";
ProgressText = "Downloading package..."; ProgressText = "Downloading package...";
return SelectedPackage.DownloadPackage(version: version); return SelectedPackage.DownloadPackage(version, isCommitHash);
} }
private async Task InstallPackage() private async Task InstallPackage()

2
StabilityMatrix/ViewModels/OneClickInstallViewModel.cs

@ -136,7 +136,7 @@ public partial class OneClickInstallViewModel : ObservableObject
selectedPackage.DownloadProgressChanged += SelectedPackageOnProgressChanged; selectedPackage.DownloadProgressChanged += SelectedPackageOnProgressChanged;
selectedPackage.DownloadComplete += (_, _) => SubHeaderText = "Download Complete"; selectedPackage.DownloadComplete += (_, _) => SubHeaderText = "Download Complete";
SubHeaderText = "Downloading package..."; SubHeaderText = "Downloading package...";
return selectedPackage.DownloadPackage(version: version); return selectedPackage.DownloadPackage(version, false);
} }
private async Task InstallPackage(BasePackage selectedPackage) private async Task InstallPackage(BasePackage selectedPackage)

4
StabilityMatrix/ViewModels/PackageManagerViewModel.cs

@ -252,8 +252,8 @@ public partial class PackageManagerViewModel : ObservableObject
SelectedPackage.UpdateAvailable = false; SelectedPackage.UpdateAvailable = false;
UpdateAvailable = false; UpdateAvailable = false;
}; };
var updateResult = await package.Update(); var updateResult = await package.Update(SelectedPackage);
settingsManager.UpdatePackageVersionNumber(SelectedPackage.DisplayName!, updateResult!); settingsManager.UpdatePackageVersionNumber(SelectedPackage.Id, updateResult);
await OnLoaded(); await OnLoaded();
} }

Loading…
Cancel
Save