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; |
||||
|
||||
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) |
||||
{ |
||||
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