ionite34
11 months ago
15 changed files with 441 additions and 55 deletions
@ -0,0 +1,13 @@ |
|||||||
|
namespace StabilityMatrix.Core.Models; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Union of either Tag or Branch + CommitSha. |
||||||
|
/// </summary> |
||||||
|
public record GitVersion |
||||||
|
{ |
||||||
|
public string? Tag { get; init; } |
||||||
|
|
||||||
|
public string? Branch { get; init; } |
||||||
|
|
||||||
|
public string? CommitSha { get; init; } |
||||||
|
} |
@ -1,15 +1,24 @@ |
|||||||
using StabilityMatrix.Core.Models.FileInterfaces; |
using StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
using StabilityMatrix.Core.Models.Packages.Extensions; |
|
||||||
using StabilityMatrix.Core.Models.Progress; |
using StabilityMatrix.Core.Models.Progress; |
||||||
|
|
||||||
namespace StabilityMatrix.Core.Models.PackageModification; |
namespace StabilityMatrix.Core.Models.PackageModification; |
||||||
|
|
||||||
public class InstallExtensionStep(ExtensionBase extension, DirectoryPath extensionsDir) : IPackageStep |
public class InstallExtensionStep( |
||||||
|
IPackageExtensionManager extensionManager, |
||||||
|
InstalledPackage installedPackage, |
||||||
|
PackageExtension packageExtension, |
||||||
|
PackageExtensionVersion? extensionVersion = null |
||||||
|
) : IPackageStep |
||||||
{ |
{ |
||||||
public Task ExecuteAsync(IProgress<ProgressReport>? progress = null) |
public Task ExecuteAsync(IProgress<ProgressReport>? progress = null) |
||||||
{ |
{ |
||||||
return extension.InstallExtensionAsync(extensionsDir, extension.MainBranch); |
return extensionManager.InstallExtensionAsync( |
||||||
|
packageExtension, |
||||||
|
installedPackage, |
||||||
|
extensionVersion, |
||||||
|
progress |
||||||
|
); |
||||||
} |
} |
||||||
|
|
||||||
public string ProgressTitle => $"Installing {extension.DisplayName}"; |
public string ProgressTitle => $"Installing Extension {packageExtension.Title}"; |
||||||
} |
} |
||||||
|
@ -0,0 +1,43 @@ |
|||||||
|
using System.Text.Json.Serialization; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
|
|
||||||
|
public record ComfyExtensionManifest |
||||||
|
{ |
||||||
|
public required IEnumerable<ManifestEntry> CustomNodes { get; init; } |
||||||
|
|
||||||
|
public IEnumerable<PackageExtension> GetPackageExtensions() |
||||||
|
{ |
||||||
|
return CustomNodes.Select( |
||||||
|
x => |
||||||
|
new PackageExtension |
||||||
|
{ |
||||||
|
Author = x.Author, |
||||||
|
Title = x.Title, |
||||||
|
Reference = x.Reference, |
||||||
|
Files = x.Files, |
||||||
|
Description = x.Description, |
||||||
|
InstallType = x.InstallType |
||||||
|
} |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public record ManifestEntry |
||||||
|
{ |
||||||
|
public required string Author { get; init; } |
||||||
|
|
||||||
|
public required string Title { get; init; } |
||||||
|
|
||||||
|
public required Uri Reference { get; init; } |
||||||
|
|
||||||
|
public required IEnumerable<Uri> Files { get; init; } |
||||||
|
|
||||||
|
public string? Description { get; init; } |
||||||
|
|
||||||
|
public string? InstallType { get; init; } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower)] |
||||||
|
[JsonSerializable(typeof(ComfyExtensionManifest))] |
||||||
|
internal partial class ComfyExtensionManifestSerializerContext : JsonSerializerContext; |
@ -1,24 +0,0 @@ |
|||||||
using StabilityMatrix.Core.Models.FileInterfaces; |
|
||||||
|
|
||||||
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
|
||||||
|
|
||||||
public abstract class ExtensionBase |
|
||||||
{ |
|
||||||
public string ByAuthor => $"By {Author}"; |
|
||||||
|
|
||||||
public abstract string RepoName { get; } |
|
||||||
public abstract string DisplayName { get; set; } |
|
||||||
public abstract string Author { get; } |
|
||||||
|
|
||||||
public abstract string Blurb { get; } |
|
||||||
public abstract IEnumerable<string> CompatibleWith { get; } |
|
||||||
public abstract string MainBranch { get; } |
|
||||||
|
|
||||||
public abstract Task InstallExtensionAsync( |
|
||||||
DirectoryPath installDirectory, |
|
||||||
string branch, |
|
||||||
CancellationToken cancellationToken = default |
|
||||||
); |
|
||||||
|
|
||||||
public string GithubUrl => $"https://github.com/{Author}/{RepoName}"; |
|
||||||
} |
|
@ -0,0 +1,3 @@ |
|||||||
|
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
|
|
||||||
|
public record ExtensionManifest(Uri Uri); |
@ -0,0 +1,144 @@ |
|||||||
|
using KGySoft.CoreLibraries; |
||||||
|
using StabilityMatrix.Core.Helper; |
||||||
|
using StabilityMatrix.Core.Models.FileInterfaces; |
||||||
|
using StabilityMatrix.Core.Models.Progress; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
|
|
||||||
|
public abstract class GitPackageExtensionManager(IPrerequisiteHelper prerequisiteHelper) |
||||||
|
: IPackageExtensionManager |
||||||
|
{ |
||||||
|
public abstract string RelativeInstallDirectory { get; } |
||||||
|
|
||||||
|
protected virtual IEnumerable<string> IndexRelativeDirectories => [RelativeInstallDirectory]; |
||||||
|
|
||||||
|
public abstract Task<IEnumerable<PackageExtension>> GetManifestExtensionsAsync( |
||||||
|
ExtensionManifest manifest, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
); |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
Task<IEnumerable<PackageExtension>> IPackageExtensionManager.GetManifestExtensionsAsync( |
||||||
|
ExtensionManifest manifest, |
||||||
|
CancellationToken cancellationToken |
||||||
|
) |
||||||
|
{ |
||||||
|
return GetManifestExtensionsAsync(manifest, cancellationToken); |
||||||
|
} |
||||||
|
|
||||||
|
protected abstract IEnumerable<ExtensionManifest> GetManifests(InstalledPackage installedPackage); |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
IEnumerable<ExtensionManifest> IPackageExtensionManager.GetManifests(InstalledPackage installedPackage) |
||||||
|
{ |
||||||
|
return GetManifests(installedPackage); |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
public async Task<IEnumerable<InstalledPackageExtension>> GetInstalledExtensionsAsync( |
||||||
|
InstalledPackage installedPackage, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
) |
||||||
|
{ |
||||||
|
if (installedPackage.FullPath is not { } packagePath) |
||||||
|
{ |
||||||
|
return Enumerable.Empty<InstalledPackageExtension>(); |
||||||
|
} |
||||||
|
|
||||||
|
var extensions = new List<InstalledPackageExtension>(); |
||||||
|
|
||||||
|
// Search for installed extensions in the package's index directories. |
||||||
|
foreach ( |
||||||
|
var indexDirectory in IndexRelativeDirectories.Select( |
||||||
|
path => new DirectoryPath(packagePath, path) |
||||||
|
) |
||||||
|
) |
||||||
|
{ |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
|
||||||
|
// Check subdirectories of the index directory |
||||||
|
foreach (var subDirectory in indexDirectory.EnumerateDirectories()) |
||||||
|
{ |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
|
||||||
|
// Skip if not valid git repository |
||||||
|
if (await prerequisiteHelper.CheckIsGitRepository(subDirectory).ConfigureAwait(false) != true) |
||||||
|
continue; |
||||||
|
|
||||||
|
// Get git version |
||||||
|
var version = await prerequisiteHelper |
||||||
|
.GetGitRepositoryVersion(subDirectory) |
||||||
|
.ConfigureAwait(false); |
||||||
|
|
||||||
|
extensions.Add( |
||||||
|
new InstalledPackageExtension |
||||||
|
{ |
||||||
|
Paths = [subDirectory], |
||||||
|
Version = new PackageExtensionVersion |
||||||
|
{ |
||||||
|
Tag = version.Tag, |
||||||
|
Branch = version.Branch, |
||||||
|
CommitSha = version.CommitSha |
||||||
|
} |
||||||
|
} |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return extensions; |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
public async Task InstallExtensionAsync( |
||||||
|
PackageExtension extension, |
||||||
|
InstalledPackage installedPackage, |
||||||
|
PackageExtensionVersion? version = null, |
||||||
|
IProgress<ProgressReport>? progress = null, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
) |
||||||
|
{ |
||||||
|
if (installedPackage.FullPath is not { } packagePath) |
||||||
|
throw new ArgumentException("Package must have a valid path.", nameof(installedPackage)); |
||||||
|
|
||||||
|
// Ensure type |
||||||
|
if (extension.InstallType?.ToLowerInvariant() != "git-clone") |
||||||
|
{ |
||||||
|
throw new ArgumentException( |
||||||
|
$"Extension must have install type 'git-clone' but has '{extension.InstallType}'.", |
||||||
|
nameof(extension) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// Git clone all files |
||||||
|
var cloneRoot = new DirectoryPath(packagePath, RelativeInstallDirectory); |
||||||
|
|
||||||
|
foreach (var repositoryUri in extension.Files) |
||||||
|
{ |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
|
||||||
|
progress?.Report(new ProgressReport(0f, $"Cloning {repositoryUri}", isIndeterminate: true)); |
||||||
|
|
||||||
|
await prerequisiteHelper |
||||||
|
.CloneGitRepository(cloneRoot, repositoryUri.ToString(), version) |
||||||
|
.ConfigureAwait(false); |
||||||
|
|
||||||
|
progress?.Report(new ProgressReport(1f, $"Cloned {repositoryUri}")); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
public async Task UninstallExtensionAsync( |
||||||
|
InstalledPackageExtension installedExtension, |
||||||
|
InstalledPackage installedPackage, |
||||||
|
IProgress<ProgressReport>? progress = null, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
) |
||||||
|
{ |
||||||
|
foreach (var path in installedExtension.Paths.Where(p => p.Exists)) |
||||||
|
{ |
||||||
|
cancellationToken.ThrowIfCancellationRequested(); |
||||||
|
|
||||||
|
await path.DeleteAsync().ConfigureAwait(false); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
using StabilityMatrix.Core.Models.FileInterfaces; |
||||||
|
using StabilityMatrix.Core.Models.Progress; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Interface for a package extension manager. |
||||||
|
/// </summary> |
||||||
|
public interface IPackageExtensionManager |
||||||
|
{ |
||||||
|
IEnumerable<ExtensionManifest> GetManifests(InstalledPackage installedPackage); |
||||||
|
|
||||||
|
Task<IEnumerable<PackageExtension>> GetManifestExtensionsAsync( |
||||||
|
ExtensionManifest manifest, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
); |
||||||
|
|
||||||
|
Task<IEnumerable<InstalledPackageExtension>> GetInstalledExtensionsAsync( |
||||||
|
InstalledPackage installedPackage, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
); |
||||||
|
|
||||||
|
Task InstallExtensionAsync( |
||||||
|
PackageExtension extension, |
||||||
|
InstalledPackage installedPackage, |
||||||
|
PackageExtensionVersion? version = null, |
||||||
|
IProgress<ProgressReport>? progress = null, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
); |
||||||
|
|
||||||
|
Task UninstallExtensionAsync( |
||||||
|
InstalledPackageExtension installedExtension, |
||||||
|
InstalledPackage installedPackage, |
||||||
|
IProgress<ProgressReport>? progress = null, |
||||||
|
CancellationToken cancellationToken = default |
||||||
|
); |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
using StabilityMatrix.Core.Models.FileInterfaces; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
|
|
||||||
|
public record InstalledPackageExtension |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// All folders or files of the extension. |
||||||
|
/// </summary> |
||||||
|
public required IEnumerable<IPathObject> Paths { get; init; } |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// The version of the extension. |
||||||
|
/// </summary> |
||||||
|
public PackageExtensionVersion? Version { get; init; } |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// |
||||||
|
/// </summary> |
||||||
|
public PackageExtension? Definition { get; init; } |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
namespace StabilityMatrix.Core.Models.Packages.Extensions; |
||||||
|
|
||||||
|
public record PackageExtension |
||||||
|
{ |
||||||
|
public required string Author { get; init; } |
||||||
|
|
||||||
|
public required string Title { get; init; } |
||||||
|
|
||||||
|
public required Uri Reference { get; init; } |
||||||
|
|
||||||
|
public required IEnumerable<Uri> Files { get; init; } |
||||||
|
|
||||||
|
public string? Description { get; init; } |
||||||
|
|
||||||
|
public string? InstallType { get; init; } |
||||||
|
} |
Loading…
Reference in new issue