diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3be855..a94c5738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Improved low disk space handling ### Fixed - Fixed denoise strength in Inference Text to Image +- Fixed PathTooLongException for IPAdapter folders when using ComfyUI in Symlink mode +- Fixed configs and symlinks not being cleaned up when switched to the opposite mode ## v2.7.3 ### Added diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs index 182280de..e6d1c6a8 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageCardViewModel.cs @@ -97,10 +97,7 @@ public partial class PackageCardViewModel : ProgressViewModel if (string.IsNullOrWhiteSpace(value?.PackageName)) return; - if ( - value.PackageName == UnknownPackage.Key - || packageFactory.FindPackageByName(value.PackageName) is null - ) + if (value.PackageName == UnknownPackage.Key || packageFactory.FindPackageByName(value.PackageName) is null) { IsUnknownPackage = true; CardImageSource = ""; @@ -114,11 +111,9 @@ public partial class PackageCardViewModel : ProgressViewModel CardImageSource = basePackage?.PreviewImageUri.ToString() ?? Assets.NoImage.ToString(); InstalledVersion = value.Version?.DisplayVersion ?? "Unknown"; CanUseConfigMethod = - basePackage?.AvailableSharedFolderMethods.Contains(SharedFolderMethod.Configuration) - ?? false; + basePackage?.AvailableSharedFolderMethods.Contains(SharedFolderMethod.Configuration) ?? false; CanUseSymlinkMethod = - basePackage?.AvailableSharedFolderMethods.Contains(SharedFolderMethod.Symlink) - ?? false; + basePackage?.AvailableSharedFolderMethods.Contains(SharedFolderMethod.Symlink) ?? false; UseSharedOutput = Package?.UseSharedOutputFolder ?? false; CanUseSharedOutput = basePackage?.SharedOutputFolders != null; } @@ -126,22 +121,13 @@ public partial class PackageCardViewModel : ProgressViewModel public override async Task OnLoadedAsync() { - if ( - Design.IsDesignMode - || !settingsManager.IsLibraryDirSet - || Package is not { } currentPackage - ) + if (Design.IsDesignMode || !settingsManager.IsLibraryDirSet || Package is not { } currentPackage) return; - if ( - packageFactory.FindPackageByName(currentPackage.PackageName) - is { } basePackage - and not UnknownPackage - ) + if (packageFactory.FindPackageByName(currentPackage.PackageName) is { } basePackage and not UnknownPackage) { // Migrate old packages with null preferred shared folder method - currentPackage.PreferredSharedFolderMethod ??= - basePackage.RecommendedSharedFolderMethod; + currentPackage.PreferredSharedFolderMethod ??= basePackage.RecommendedSharedFolderMethod; switch (currentPackage.PreferredSharedFolderMethod) { @@ -199,18 +185,11 @@ public partial class PackageCardViewModel : ProgressViewModel var packagePath = new DirectoryPath(settingsManager.LibraryDir, Package.LibraryPath); var deleteTask = packagePath.DeleteVerboseAsync(logger); - var taskResult = await notificationService.TryAsync( - deleteTask, - Resources.Text_SomeFilesCouldNotBeDeleted - ); + var taskResult = await notificationService.TryAsync(deleteTask, Resources.Text_SomeFilesCouldNotBeDeleted); if (taskResult.IsSuccessful) { notificationService.Show( - new Notification( - Resources.Label_PackageUninstalled, - Package.DisplayName, - NotificationType.Success - ) + new Notification(Resources.Label_PackageUninstalled, Package.DisplayName, NotificationType.Success) ); if (!IsUnknownPackage) @@ -238,10 +217,7 @@ public partial class PackageCardViewModel : ProgressViewModel var basePackage = packageFactory[Package.PackageName!]; if (basePackage == null) { - logger.LogWarning( - "Could not find package {SelectedPackagePackageName}", - Package.PackageName - ); + logger.LogWarning("Could not find package {SelectedPackagePackageName}", Package.PackageName); notificationService.Show( Resources.Label_InvalidPackageType, Package.PackageName.ToRepr(), @@ -278,12 +254,7 @@ public partial class PackageCardViewModel : ProgressViewModel versionOptions.CommitHash = latest.Sha; } - var updatePackageStep = new UpdatePackageStep( - settingsManager, - Package, - versionOptions, - basePackage - ); + var updatePackageStep = new UpdatePackageStep(settingsManager, Package, versionOptions, basePackage); var steps = new List { updatePackageStep }; EventManager.Instance.OnPackageInstallProgressAdded(runner); @@ -321,9 +292,7 @@ public partial class PackageCardViewModel : ProgressViewModel var viewModel = vmFactory.Get(vm => { - vm.PackagePath = new DirectoryPath( - Package?.FullPath ?? throw new InvalidOperationException() - ); + vm.PackagePath = new DirectoryPath(Package?.FullPath ?? throw new InvalidOperationException()); }); var dialog = new TaskDialog @@ -349,9 +318,7 @@ public partial class PackageCardViewModel : ProgressViewModel await using (new MinimumDelay(200, 300)) { - var result = await notificationService.TryAsync( - viewModel.AddPackageWithCurrentInputs() - ); + var result = await notificationService.TryAsync(viewModel.AddPackageWithCurrentInputs()); if (result.IsSuccessful) { EventManager.Instance.OnInstalledPackagesChanged(); @@ -398,10 +365,7 @@ public partial class PackageCardViewModel : ProgressViewModel var basePackage = packageFactory[Package.PackageName!]; if (basePackage == null) { - logger.LogWarning( - "Could not find package {SelectedPackagePackageName}", - Package.PackageName - ); + logger.LogWarning("Could not find package {SelectedPackagePackageName}", Package.PackageName); return; } @@ -417,9 +381,7 @@ public partial class PackageCardViewModel : ProgressViewModel if (basePackage == null) return false; - var canCheckUpdate = - Package.LastUpdateCheck == null - || Package.LastUpdateCheck < DateTime.Now.AddMinutes(-15); + var canCheckUpdate = Package.LastUpdateCheck == null || Package.LastUpdateCheck < DateTime.Now.AddMinutes(-15); if (!canCheckUpdate) { @@ -482,13 +444,6 @@ public partial class PackageCardViewModel : ProgressViewModel if (newValue != Package!.PreferredSharedFolderMethod is SharedFolderMethod.Symlink) { - if (!newValue) - { - var basePackage = packageFactory[Package!.PackageName!]; - basePackage!.RemoveModelFolderLinks(Package.FullPath!, SharedFolderMethod.Symlink); - return; - } - using var st = settingsManager.BeginTransaction(); Package.PreferredSharedFolderMethod = SharedFolderMethod.Symlink; } @@ -498,6 +453,11 @@ public partial class PackageCardViewModel : ProgressViewModel IsSharedModelConfig = false; IsSharedModelDisabled = false; } + else + { + var basePackage = packageFactory[Package!.PackageName!]; + basePackage!.RemoveModelFolderLinks(Package.FullPath!, SharedFolderMethod.Symlink); + } } partial void OnIsSharedModelConfigChanged(bool oldValue, bool newValue) @@ -507,16 +467,6 @@ public partial class PackageCardViewModel : ProgressViewModel if (newValue != Package!.PreferredSharedFolderMethod is SharedFolderMethod.Configuration) { - if (!newValue) - { - var basePackage = packageFactory[Package!.PackageName!]; - basePackage!.RemoveModelFolderLinks( - Package.FullPath!, - SharedFolderMethod.Configuration - ); - return; - } - using var st = settingsManager.BeginTransaction(); Package.PreferredSharedFolderMethod = SharedFolderMethod.Configuration; } @@ -526,6 +476,11 @@ public partial class PackageCardViewModel : ProgressViewModel IsSharedModelSymlink = false; IsSharedModelDisabled = false; } + else + { + var basePackage = packageFactory[Package!.PackageName!]; + basePackage!.RemoveModelFolderLinks(Package.FullPath!, SharedFolderMethod.Configuration); + } } partial void OnIsSharedModelDisabledChanged(bool value) diff --git a/StabilityMatrix.Core/Helper/SharedFolders.cs b/StabilityMatrix.Core/Helper/SharedFolders.cs index 2e2f2115..33fbc914 100644 --- a/StabilityMatrix.Core/Helper/SharedFolders.cs +++ b/StabilityMatrix.Core/Helper/SharedFolders.cs @@ -35,7 +35,9 @@ public class SharedFolders : ISharedFolders else { // Create parent directory if it doesn't exist, since CreateSymbolicLink doesn't seem to - new DirectoryPath(junctionDir).Parent?.Create(); + new DirectoryPath(junctionDir) + .Parent + ?.Create(); Directory.CreateSymbolicLink(junctionDir, targetDir); } } @@ -70,9 +72,7 @@ public class SharedFolders : ISharedFolders // If link is already the same, just skip if (destinationDir.Info.LinkTarget == sourceDir) { - Logger.Info( - $"Skipped updating matching folder link ({destinationDir} -> ({sourceDir})" - ); + Logger.Info($"Skipped updating matching folder link ({destinationDir} -> ({sourceDir})"); return; } @@ -113,9 +113,7 @@ public class SharedFolders : ISharedFolders var sharedFolders = basePackage.SharedFolders; if (sharedFolders == null) return; - UpdateLinksForPackage(sharedFolders, modelsDirectory, installDirectory) - .GetAwaiter() - .GetResult(); + UpdateLinksForPackage(sharedFolders, modelsDirectory, installDirectory).GetAwaiter().GetResult(); } /// @@ -137,11 +135,18 @@ public class SharedFolders : ISharedFolders var sourceDir = new DirectoryPath(modelsDirectory, folderType.GetStringValue()); var destinationDir = installDirectory.JoinDir(relativePath); - await CreateOrUpdateLink( - sourceDir, - destinationDir, - recursiveDelete: recursiveDelete - ) + // Check and remove destinationDir parent if it's a link + if (destinationDir.Parent is { IsSymbolicLink: true } parentLink) + { + Logger.Info("Deleting parent junction at target {Path}", parentLink.ToString()); + + await parentLink.DeleteAsync(false).ConfigureAwait(false); + + // Recreate + parentLink.Create(); + } + + await CreateOrUpdateLink(sourceDir, destinationDir, recursiveDelete: recursiveDelete) .ConfigureAwait(false); } } @@ -189,12 +194,8 @@ public class SharedFolders : ISharedFolders } var sharedFolderMethod = - package.PreferredSharedFolderMethod - ?? basePackage.RecommendedSharedFolderMethod; - basePackage - .RemoveModelFolderLinks(package.FullPath, sharedFolderMethod) - .GetAwaiter() - .GetResult(); + package.PreferredSharedFolderMethod ?? basePackage.RecommendedSharedFolderMethod; + basePackage.RemoveModelFolderLinks(package.FullPath, sharedFolderMethod).GetAwaiter().GetResult(); } catch (Exception e) { diff --git a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs index 6f3efd8d..c26f52b5 100644 --- a/StabilityMatrix.Core/Models/Packages/A3WebUI.cs +++ b/StabilityMatrix.Core/Models/Packages/A3WebUI.cs @@ -267,23 +267,4 @@ public class A3WebUI( VenvRunner.RunDetached(args.TrimEnd(), HandleConsoleOutput, OnExit); } - - /// - public override async Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) - { - // Migration for `controlnet` -> `controlnet/ControlNet` and `controlnet/T2IAdapter` - // If the original link exists, delete it first - if (installDirectory.JoinDir("models/controlnet") is { IsSymbolicLink: true } controlnetOldLink) - { - Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink); - await controlnetOldLink.DeleteAsync(false).ConfigureAwait(false); - } - - // Resume base setup - await base.SetupModelFolders(installDirectory, sharedFolderMethod).ConfigureAwait(false); - } - - /// - public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => - SetupModelFolders(installDirectory, sharedFolderMethod); } diff --git a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs index bd09057c..3848697b 100644 --- a/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs +++ b/StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs @@ -405,34 +405,46 @@ public abstract class BaseGitPackage : BasePackage }; } - public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) + public override async Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) { - if (sharedFolderMethod == SharedFolderMethod.Symlink && SharedFolders is { } folders) + if (sharedFolderMethod != SharedFolderMethod.Symlink || SharedFolders is not { } sharedFolders) { - return StabilityMatrix - .Core - .Helper - .SharedFolders - .UpdateLinksForPackage(folders, SettingsManager.ModelsDirectory, installDirectory); + return; } - return Task.CompletedTask; - } + // fix duplicate links in models dir + // see https://github.com/LykosAI/StabilityMatrix/issues/338 + var modelsDir = new DirectoryPath(SettingsManager.ModelsDirectory); - public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) - { - if (sharedFolderMethod == SharedFolderMethod.Symlink && SharedFolders is { } sharedFolders) + string[] duplicatePaths = + [ + Path.Combine("ControlNet", "ControlNet"), + Path.Combine("IPAdapter", "base"), + Path.Combine("IPAdapter", "sd15"), + Path.Combine("IPAdapter", "sdxl") + ]; + + foreach (var duplicatePath in duplicatePaths) { - return StabilityMatrix - .Core - .Helper - .SharedFolders - .UpdateLinksForPackage(sharedFolders, SettingsManager.ModelsDirectory, installDirectory); + var linkDir = modelsDir.JoinDir(duplicatePath); + if (!linkDir.IsSymbolicLink) + continue; + + Logger.Info("Removing duplicate junction at {Path}", linkDir.ToString()); + await linkDir.DeleteAsync(false).ConfigureAwait(false); } - return Task.CompletedTask; + await StabilityMatrix + .Core + .Helper + .SharedFolders + .UpdateLinksForPackage(sharedFolders, SettingsManager.ModelsDirectory, installDirectory) + .ConfigureAwait(false); } + public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => + SetupModelFolders(installDirectory, sharedFolderMethod); + public override Task RemoveModelFolderLinks(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) { if (SharedFolders is not null && sharedFolderMethod == SharedFolderMethod.Symlink) diff --git a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs index 0f425da3..81a415c4 100644 --- a/StabilityMatrix.Core/Models/Packages/ComfyUI.cs +++ b/StabilityMatrix.Core/Models/Packages/ComfyUI.cs @@ -242,15 +242,12 @@ public class ComfyUI( public override Task SetupModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => sharedFolderMethod switch { - SharedFolderMethod.Symlink => SetupModelFoldersSymlink(installDirectory), + SharedFolderMethod.Symlink => base.SetupModelFolders(installDirectory, SharedFolderMethod.Symlink), SharedFolderMethod.Configuration => SetupModelFoldersConfig(installDirectory), SharedFolderMethod.None => Task.CompletedTask, _ => throw new ArgumentOutOfRangeException(nameof(sharedFolderMethod), sharedFolderMethod, null) }; - public override Task UpdateModelFolders(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) => - SetupModelFolders(installDirectory, sharedFolderMethod); - public override Task RemoveModelFolderLinks(DirectoryPath installDirectory, SharedFolderMethod sharedFolderMethod) { return sharedFolderMethod switch @@ -262,20 +259,6 @@ public class ComfyUI( }; } - private async Task SetupModelFoldersSymlink(DirectoryPath installDirectory) - { - // Migration for `controlnet` -> `controlnet/ControlNet` and `controlnet/T2IAdapter` - // If the original link exists, delete it first - if (installDirectory.JoinDir("models/controlnet") is { IsSymbolicLink: true } controlnetOldLink) - { - Logger.Info("Migration: Removing old controlnet link {Path}", controlnetOldLink); - await controlnetOldLink.DeleteAsync(false).ConfigureAwait(false); - } - - // Resume base setup - await base.SetupModelFolders(installDirectory, SharedFolderMethod.Symlink).ConfigureAwait(false); - } - private async Task SetupModelFoldersConfig(DirectoryPath installDirectory) { var extraPathsYamlPath = installDirectory.JoinFile("extra_model_paths.yaml");