Browse Source

Merge pull request #115 from ionite34/setup-dependencies

Selectable library path
pull/5/head
Ionite 1 year ago committed by GitHub
parent
commit
01ee1e1b82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 18
      StabilityMatrix.Tests/Models/InstalledPackageTests.cs
  2. 2
      StabilityMatrix.Tests/Python/PyRunnerTests.cs
  3. 29
      StabilityMatrix/App.xaml.cs
  4. 4
      StabilityMatrix/Helper/ArchiveHelper.cs
  5. 7
      StabilityMatrix/Helper/IPrerequisiteHelper.cs
  6. 17
      StabilityMatrix/Helper/ISettingsManager.cs
  7. 39
      StabilityMatrix/Helper/PrerequisiteHelper.cs
  8. 141
      StabilityMatrix/Helper/SettingsManager.cs
  9. 26
      StabilityMatrix/Models/GlobalConfig.cs
  10. 107
      StabilityMatrix/Models/InstalledPackage.cs
  11. 6
      StabilityMatrix/Models/LibrarySettings.cs
  12. 11
      StabilityMatrix/Models/Packages/VladAutomatic.cs
  13. 2
      StabilityMatrix/Models/Settings.cs
  14. 2
      StabilityMatrix/Models/SharedFolders.cs
  15. 4
      StabilityMatrix/Python/PyRunner.cs
  16. 10
      StabilityMatrix/SettingsPage.xaml
  17. 2
      StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs
  18. 2
      StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs
  19. 6
      StabilityMatrix/ViewModels/SettingsViewModel.cs
  20. 2
      StabilityMatrix/ViewModels/TextToImageViewModel.cs

18
StabilityMatrix.Tests/Models/InstalledPackageTests.cs

@ -0,0 +1,18 @@
using StabilityMatrix.Models;
namespace StabilityMatrix.Tests.Models;
[TestClass]
public class InstalledPackageTests
{
[DataTestMethod]
[DataRow("C:\\User\\AppData\\StabilityMatrix", "C:\\User\\Other", null)]
[DataRow("C:\\Data", "D:\\Data\\abc", null)]
[DataRow("C:\\Data", "C:\\Data\\abc", "abc")]
[DataRow("C:\\User\\AppData\\StabilityMatrix", "C:\\User\\AppData\\StabilityMatrix\\Packages\\abc", "Packages\\abc")]
public void TestGetSubPath(string relativeTo, string path, string? expected)
{
var result = InstalledPackage.GetSubPath(relativeTo, path);
Assert.AreEqual(expected, result);
}
}

2
StabilityMatrix.Tests/Python/PyRunnerTests.cs

@ -11,6 +11,8 @@ public class PyRunnerTests
[ClassInitialize]
public static async Task TestInitialize(TestContext testContext)
{
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
PyRunner.HomeDir = Path.Combine(appData, "StabilityMatrix");
await PyRunner.Initialize();
}

29
StabilityMatrix/App.xaml.cs

@ -138,6 +138,33 @@ namespace StabilityMatrix
return logConfig;
}
// Find library and initialize settings
private static SettingsManager CreateSettingsManager()
{
var settings = new SettingsManager();
var found = settings.TryFindLibrary();
// Not found, we need to show dialog to choose library location
if (!found)
{
// See if this is an existing user for message variation
var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var settingsPath = Path.Combine(appDataPath, "StabilityMatrix", "settings.json");
var isExistingUser = File.Exists(settingsPath);
// TODO: Show dialog
// 1. For portable mode, call settings.SetPortableMode()
// 2. For custom path, call settings.SetLibraryPath(path)
// TryFindLibrary should succeed now unless weird issue
if (!settings.TryFindLibrary())
{
throw new Exception("Could not set library path.");
}
}
return settings;
}
private void App_OnStartup(object sender, StartupEventArgs e)
{
var serviceCollection = new ServiceCollection();
@ -176,7 +203,7 @@ namespace StabilityMatrix
serviceCollection.Configure<DebugOptions>(Config.GetSection(nameof(DebugOptions)));
var settingsManager = new SettingsManager();
var settingsManager = CreateSettingsManager();
serviceCollection.AddSingleton<ISettingsManager>(settingsManager);
serviceCollection.AddSingleton<BasePackage, A3WebUI>();

4
StabilityMatrix/Helper/ArchiveHelper.cs

@ -20,8 +20,8 @@ public static class ArchiveHelper
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly string AppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
private static readonly string HomeDir = Path.Combine(AppDataDir, "StabilityMatrix");
// HomeDir is set by ISettingsManager.TryFindLibrary()
public static string HomeDir { get; set; } = string.Empty;
public static string SevenZipPath => Path.Combine(HomeDir, "Assets", "7za.exe");
private static readonly Regex Regex7ZOutput = new(@"(?<=Size:\s*)\d+|(?<=Compressed:\s*)\d+");

7
StabilityMatrix/Helper/IPrerequisiteHelper.cs

@ -6,6 +6,8 @@ namespace StabilityMatrix.Helper;
public interface IPrerequisiteHelper
{
string GitBinPath { get; }
bool IsPythonInstalled { get; }
Task InstallAllIfNecessary(IProgress<ProgressReport>? progress = null);
@ -14,6 +16,11 @@ public interface IPrerequisiteHelper
Task InstallVcRedistIfNecessary(IProgress<ProgressReport>? progress = null);
Task InstallPythonIfNecessary(IProgress<ProgressReport>? progress = null);
/// <summary>
/// Run embedded git with the given arguments.
/// </summary>
Task RunGit(params string[] args);
Task SetupPythonDependencies(string installLocation, string requirementsFileName,
IProgress<ProgressReport>? progress = null, Action<string?>? onConsoleOutput = null);
}

17
StabilityMatrix/Helper/ISettingsManager.cs

@ -7,13 +7,21 @@ namespace StabilityMatrix.Helper;
public interface ISettingsManager
{
public string AppDataDir { get; }
public string AppHomeDir { get; }
public string DatabasePath { get; }
Settings Settings { get; }
event EventHandler<bool>? ModelBrowserNsfwEnabledChanged;
// Library settings
bool IsPortableMode { get; }
string LibraryDir { get; }
bool TryFindLibrary();
// Dynamic paths from library
string DatabasePath { get; }
string ModelsDirectory { get; }
// Migration
IEnumerable<InstalledPackage> GetOldInstalledPackages();
void SetTheme(string theme);
void AddInstalledPackage(InstalledPackage p);
void RemoveInstalledPackage(InstalledPackage p);
@ -37,7 +45,6 @@ public interface ISettingsManager
string? GetActivePackagePort();
void SetWebApiHost(string? host);
void SetWebApiPort(string? port);
void SetModelsDirectory(string? directory);
void SetFirstLaunchSetupComplete(bool firstLaunchSetupCompleted);
void SetModelBrowserNsfwEnabled(bool value);
void SetSharedFolderCategoryVisible(SharedFolderType type, bool visible);

39
StabilityMatrix/Helper/PrerequisiteHelper.cs

@ -23,26 +23,25 @@ public class PrerequisiteHelper : IPrerequisiteHelper
private const string VcRedistDownloadUrl = "https://aka.ms/vs/16/release/vc_redist.x64.exe";
private const string PythonDownloadUrl = "https://www.python.org/ftp/python/3.10.11/python-3.10.11-embed-amd64.zip";
private static readonly string AppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
private static readonly string HomeDir = Path.Combine(AppDataDir, "StabilityMatrix");
private string HomeDir => settingsManager.LibraryDir;
private static readonly string VcRedistDownloadPath = Path.Combine(HomeDir, "vcredist.x64.exe");
private string VcRedistDownloadPath => Path.Combine(HomeDir, "vcredist.x64.exe");
private static readonly string AssetsDir = Path.Combine(HomeDir, "Assets");
private static readonly string SevenZipPath = Path.Combine(AssetsDir, "7za.exe");
private string AssetsDir => Path.Combine(HomeDir, "Assets");
private string SevenZipPath => Path.Combine(AssetsDir, "7za.exe");
private static readonly string PythonDownloadPath = Path.Combine(AssetsDir, "python-3.10.11-embed-amd64.zip");
private static readonly string PythonDir = Path.Combine(AssetsDir, "Python310");
private static readonly string PythonDllPath = Path.Combine(PythonDir, "python310.dll");
private static readonly string PythonLibraryZipPath = Path.Combine(PythonDir, "python310.zip");
private static readonly string GetPipPath = Path.Combine(PythonDir, "get-pip.pyc");
private string PythonDownloadPath => Path.Combine(AssetsDir, "python-3.10.11-embed-amd64.zip");
private string PythonDir => Path.Combine(AssetsDir, "Python310");
private string PythonDllPath => Path.Combine(PythonDir, "python310.dll");
private string PythonLibraryZipPath => Path.Combine(PythonDir, "python310.zip");
private string GetPipPath => Path.Combine(PythonDir, "get-pip.pyc");
// Temporary directory to extract venv to during python install
private static readonly string VenvTempDir = Path.Combine(PythonDir, "venv");
private string VenvTempDir => Path.Combine(PythonDir, "venv");
private static readonly string PortableGitInstallDir = Path.Combine(HomeDir, "PortableGit");
private static readonly string PortableGitDownloadPath = Path.Combine(HomeDir, "PortableGit.7z.exe");
private static readonly string GitExePath = Path.Combine(PortableGitInstallDir, "bin", "git.exe");
public static readonly string GitBinPath = Path.Combine(PortableGitInstallDir, "bin");
private string PortableGitInstallDir => Path.Combine(HomeDir, "PortableGit");
private string PortableGitDownloadPath => Path.Combine(HomeDir, "PortableGit.7z.exe");
private string GitExePath => Path.Combine(PortableGitInstallDir, "bin", "git.exe");
public string GitBinPath => Path.Combine(PortableGitInstallDir, "bin");
public bool IsPythonInstalled => File.Exists(PythonDllPath);
@ -55,6 +54,12 @@ public class PrerequisiteHelper : IPrerequisiteHelper
this.settingsManager = settingsManager;
}
public async Task RunGit(params string[] args)
{
var process = ProcessRunner.StartProcess(GitExePath, args);
await ProcessRunner.WaitForExitConditionAsync(process);
}
public async Task InstallAllIfNecessary(IProgress<ProgressReport>? progress = null)
{
await InstallVcRedistIfNecessary(progress);
@ -206,11 +211,11 @@ public class PrerequisiteHelper : IPrerequisiteHelper
{
if (File.Exists(GitExePath))
{
logger.LogDebug($"Git already installed at {GitExePath}");
logger.LogDebug("Git already installed at {GitExePath}", GitExePath);
return;
}
logger.LogInformation($"Git not found at {GitExePath}, downloading...");
logger.LogInformation("Git not found at {GitExePath}, downloading...", GitExePath);
var portableGitUrl =
"https://github.com/git-for-windows/git/releases/download/v2.41.0.windows.1/PortableGit-2.41.0-64-bit.7z.exe";

141
StabilityMatrix/Helper/SettingsManager.cs

@ -5,56 +5,123 @@ using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using NLog;
using StabilityMatrix.Models;
using StabilityMatrix.Python;
using Wpf.Ui.Controls.Window;
namespace StabilityMatrix.Helper;
public class SettingsManager : ISettingsManager
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly ReaderWriterLockSlim FileLock = new();
/// <summary>
/// Directory of %AppData%
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
public string AppDataDir => Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
private readonly string? originalEnvPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
/// <summary>
/// Directory of %AppData%\StabilityMatrix
/// </summary>
public string AppHomeDir => Path.Combine(AppDataDir, "StabilityMatrix");
// Library properties
public bool IsPortableMode { get; set; }
public string LibraryDir { get; set; } = string.Empty;
/// <summary>
/// Path to database file
/// </summary>
public string DatabasePath => Path.Combine(AppHomeDir, "StabilityMatrix.db");
private const string SettingsFileName = "settings.json";
private string SettingsPath => Path.Combine(AppHomeDir, SettingsFileName);
private readonly string? originalEnvPath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
// Dynamic paths from library
public string DatabasePath => Path.Combine(LibraryDir, "StabilityMatrix.db");
private string SettingsPath => Path.Combine(LibraryDir, "settings.json");
public string ModelsDirectory => Path.Combine(LibraryDir, "Models");
public Settings Settings { get; private set; } = new();
public event EventHandler<bool>? ModelBrowserNsfwEnabledChanged;
public SettingsManager()
/// <summary>
/// Attempts to locate and set the library path
/// Return true if found, false otherwise
/// </summary>
public bool TryFindLibrary()
{
if (!Directory.Exists(SettingsPath.Replace(SettingsFileName, "")))
// 1. Check portable mode
var appDir = AppContext.BaseDirectory;
IsPortableMode = File.Exists(Path.Combine(appDir, ".sm-portable"));
if (IsPortableMode)
{
Directory.CreateDirectory(SettingsPath.Replace(SettingsFileName, ""));
LibraryDir = Path.Combine(appDir, "Data");
SetStaticLibraryPaths();
return true;
}
if (!File.Exists(SettingsPath))
// 2. Check %APPDATA%/StabilityMatrix/library.json
var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var libraryJsonPath = Path.Combine(appDataDir, "StabilityMatrix", "library.json");
if (File.Exists(libraryJsonPath))
{
File.Create(SettingsPath).Close();
Settings.Theme = "Dark";
Settings.WindowBackdropType = WindowBackdropType.Mica;
var defaultSettingsJson = JsonSerializer.Serialize(Settings);
File.WriteAllText(SettingsPath, defaultSettingsJson);
try
{
var libraryJson = File.ReadAllText(libraryJsonPath);
var library = JsonSerializer.Deserialize<LibrarySettings>(libraryJson);
if (!string.IsNullOrWhiteSpace(library?.LibraryPath))
{
LibraryDir = library.LibraryPath;
SetStaticLibraryPaths();
return true;
}
}
catch (Exception e)
{
Logger.Warn("Failed to read library.json in AppData: {Message}", e.Message);
}
}
return false;
}
// Set static classes requiring library path
private void SetStaticLibraryPaths()
{
GlobalConfig.LibraryDir = LibraryDir;
ArchiveHelper.HomeDir = LibraryDir;
PyRunner.HomeDir = LibraryDir;
}
/// <summary>
/// Save a new library path to %APPDATA%/StabilityMatrix/library.json
/// </summary>
public void SetLibraryPath(string path)
{
var appDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var homeDir = Path.Combine(appDataDir, "StabilityMatrix");
Directory.CreateDirectory(homeDir);
var libraryJsonPath = Path.Combine(homeDir, "library.json");
var library = new LibrarySettings { LibraryPath = path };
var libraryJson = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(libraryJsonPath, libraryJson);
}
LoadSettings();
/// <summary>
/// Enable and create settings files for portable mode
/// Creates the ./Data directory and the `.sm-portable` marker file
/// </summary>
public void SetPortableMode()
{
// Get app directory
var appDir = AppContext.BaseDirectory;
// Create data directory
var dataDir = Path.Combine(appDir, "Data");
Directory.CreateDirectory(dataDir);
// Create marker file
File.Create(Path.Combine(dataDir, ".sm-portable")).Close();
}
/// <summary>
/// Iterable of installed packages using the old absolute path format.
/// Can be called with Any() to check if the user needs to migrate.
/// </summary>
public IEnumerable<InstalledPackage> GetOldInstalledPackages()
{
var installed = Settings.InstalledPackages;
// Absolute paths are old formats requiring migration
foreach (var package in installed.Where(package => Path.IsPathRooted(package.Path)))
{
yield return package;
}
}
public void SetTheme(string theme)
@ -205,12 +272,6 @@ public class SettingsManager : ISettingsManager
SaveSettings();
}
public void SetModelsDirectory(string? directory)
{
Settings.ModelsDirectory = directory;
SaveSettings();
}
public void SetFirstLaunchSetupComplete(bool value)
{
Settings.FirstLaunchSetupComplete = value;
@ -245,11 +306,25 @@ public class SettingsManager : ISettingsManager
return Settings.SharedFolderVisibleCategories?.HasFlag(type) ?? false;
}
/// <summary>
/// Loads settings from the settings file
/// If the settings file does not exist, it will be created with default values
/// </summary>
private void LoadSettings()
{
FileLock.EnterReadLock();
try
{
if (!File.Exists(SettingsPath))
{
File.Create(SettingsPath).Close();
Settings.Theme = "Dark";
Settings.WindowBackdropType = WindowBackdropType.Mica;
var defaultSettingsJson = JsonSerializer.Serialize(Settings);
File.WriteAllText(SettingsPath, defaultSettingsJson);
return;
}
var settingsContent = File.ReadAllText(SettingsPath);
Settings = JsonSerializer.Deserialize<Settings>(settingsContent, new JsonSerializerOptions
{

26
StabilityMatrix/Models/GlobalConfig.cs

@ -0,0 +1,26 @@
using System;
namespace StabilityMatrix.Models;
public static class GlobalConfig
{
private static string? libraryDir;
/// <summary>
/// Absolute path to the library directory.
/// Needs to be set by SettingsManager.TryFindLibrary() before being accessed.
/// </summary>
/// <exception cref="Exception"></exception>
public static string LibraryDir
{
get
{
if (string.IsNullOrEmpty(libraryDir))
{
throw new Exception("GlobalConfig.LibraryDir was not set before being accessed.");
}
return libraryDir;
}
set => libraryDir = value;
}
}

107
StabilityMatrix/Models/InstalledPackage.cs

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace StabilityMatrix.Models;
@ -18,14 +20,113 @@ public class InstalledPackage
// Package version
public string? PackageVersion { get; set; }
public string? InstalledBranch { get; set; }
public string? DisplayVersion { get; set; }
// Install path
// Old type absolute path
[Obsolete("Use LibraryPath instead. (Kept for migration)")]
public string? Path { get; set; }
/// <summary>
/// Relative path from the library root.
/// </summary>
public string? LibraryPath { get; set; }
/// <summary>
/// Full path to the package, using LibraryPath and GlobalConfig.LibraryDir.
/// </summary>
public string? FullPath => LibraryPath != null ? System.IO.Path.Combine(GlobalConfig.LibraryDir, LibraryPath) : null;
public string? LaunchCommand { get; set; }
public List<LaunchOption>? LaunchArgs { get; set; }
public DateTimeOffset? LastUpdateCheck { get; set; }
[JsonIgnore] public bool UpdateAvailable { get; set; } = false;
[JsonIgnore] public bool UpdateAvailable { get; set; }
/// <summary>
/// Get the path as a relative sub-path of the relative path.
/// If not a sub-path, return null.
/// </summary>
internal static string? GetSubPath(string relativeTo, string path)
{
var relativePath = System.IO.Path.GetRelativePath(relativeTo, path);
// GetRelativePath returns the path if it's not relative
if (relativePath == path) return null;
// Further check if the path is a sub-path of the library
var isSubPath = relativePath != "."
&& relativePath != ".."
&& !relativePath.StartsWith("..\\")
&& !System.IO.Path.IsPathRooted(relativePath);
return isSubPath ? relativePath : null;
}
/// <summary>
/// Migrates the old Path to the new LibraryPath.
/// If libraryDirectory is null, GlobalConfig.LibraryDir is used.
/// </summary>
/// <returns>True if the path was migrated, false otherwise.</returns>
public bool TryPureMigratePath(string? libraryDirectory = null)
{
#pragma warning disable CS0618
var oldPath = Path;
#pragma warning restore CS0618
if (oldPath == null) return false;
// Check if the path is a sub-path of the library
var library = libraryDirectory ?? GlobalConfig.LibraryDir;
var relativePath = GetSubPath(library, oldPath);
// If so we migrate without any IO operations
if (relativePath != null)
{
LibraryPath = relativePath;
#pragma warning disable CS0618
Path = null;
#pragma warning restore CS0618
return true;
}
return false;
}
/// <summary>
/// Migrate the old Path to the new LibraryPath.
/// If libraryDirectory is null, GlobalConfig.LibraryDir is used.
/// Will move the package directory to Library/Packages if not relative.
/// </summary>
public async Task MigratePath(string? libraryDirectory = null)
{
#pragma warning disable CS0618
var oldPath = Path;
#pragma warning restore CS0618
if (oldPath == null) return;
// Try using pure migration first
if (TryPureMigratePath(libraryDirectory)) return;
// If not, we need to move the package directory
var packageFolderName = new DirectoryInfo(oldPath).Name;
// Get the new Library/Packages path
var library = libraryDirectory ?? GlobalConfig.LibraryDir;
var newPackagesDir = System.IO.Path.Combine(library, "Packages");
// Get the new target path
var newPackagePath = System.IO.Path.Combine(newPackagesDir, packageFolderName);
// Ensure it is not already there, if so, add a suffix until it's not
var suffix = 2;
while (Directory.Exists(newPackagePath))
{
newPackagePath = System.IO.Path.Combine(newPackagesDir, $"{packageFolderName}-{suffix}");
suffix++;
}
// Move the package directory
await Task.Run(() => Directory.Move(oldPath, newPackagePath));
// Update the paths
#pragma warning disable CS0618
Path = null;
#pragma warning restore CS0618
LibraryPath = System.IO.Path.Combine("Packages", packageFolderName);
}
}

6
StabilityMatrix/Models/LibrarySettings.cs

@ -0,0 +1,6 @@
namespace StabilityMatrix.Models;
public class LibrarySettings
{
public string? LibraryPath { get; set; }
}

11
StabilityMatrix/Models/Packages/VladAutomatic.cs

@ -102,15 +102,8 @@ public class VladAutomatic : BaseGitPackage
Directory.CreateDirectory(InstallLocation);
var gitCloneProcess =
ProcessRunner.StartProcess(Path.Combine(Helper.PrerequisiteHelper.GitBinPath, "git.exe"),
"clone https://github.com/vladmandic/automatic.git .", InstallLocation);
await gitCloneProcess.WaitForExitAsync();
var gitCheckoutProcess =
ProcessRunner.StartProcess(Path.Combine(Helper.PrerequisiteHelper.GitBinPath, "git.exe"),
$"checkout {version}", InstallLocation);
await gitCheckoutProcess.WaitForExitAsync();
await PrerequisiteHelper.RunGit("clone", "https://github.com/vladmandic/automatic.git", InstallLocation);
await PrerequisiteHelper.RunGit("checkout", version, InstallLocation);
return version;
}

2
StabilityMatrix/Models/Settings.cs

@ -10,6 +10,7 @@ namespace StabilityMatrix.Models;
public class Settings
{
public int? Version { get; set; } = 1;
public bool FirstLaunchSetupComplete { get; set; }
public string? Theme { get; set; }
public WindowBackdropType? WindowBackdropType { get; set; }
@ -20,7 +21,6 @@ public class Settings
public List<string>? PathExtensions { get; set; }
public string? WebApiHost { get; set; }
public string? WebApiPort { get; set; }
public string ModelsDirectory { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "StabilityMatrix", "Models");
public bool ModelBrowserNsfwEnabled { get; set; }
public SharedFolderType? SharedFolderVisibleCategories { get; set; } =

2
StabilityMatrix/Models/SharedFolders.cs

@ -29,7 +29,7 @@ public class SharedFolders : ISharedFolders
var provider = ReparsePointFactory.Provider;
foreach (var (folderType, relativePath) in sharedFolders)
{
var source = Path.Combine(settingsManager.Settings.ModelsDirectory, folderType.GetStringValue());
var source = Path.Combine(settingsManager.ModelsDirectory, folderType.GetStringValue());
var destination = Path.GetFullPath(Path.Combine(installPath, relativePath));
// Create source folder if it doesn't exist
if (!Directory.Exists(source))

4
StabilityMatrix/Python/PyRunner.cs

@ -15,8 +15,8 @@ public class PyRunner : IPyRunner
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private static readonly string AppDataDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
private static readonly string HomeDir = Path.Combine(AppDataDir, "StabilityMatrix");
// Set by ISettingsManager.TryFindLibrary()
public static string HomeDir { get; set; } = string.Empty;
public static string PythonDir => Path.Combine(HomeDir, "Assets", "Python310");
public static string PythonDllPath => Path.Combine(PythonDir, "python310.dll");

10
StabilityMatrix/SettingsPage.xaml

@ -199,6 +199,7 @@
FontWeight="Bold"
Margin="0,8"
Text="Directories" />
<StackPanel Orientation="Horizontal">
<ui:Button
Command="{Binding OpenAppDataDirectoryCommand}"
Content="App Data"
@ -207,6 +208,15 @@
<ui:SymbolIcon Margin="4" Symbol="Open32" />
</ui:Button.Icon>
</ui:Button>
<ui:Button
Command="{Binding OpenLibraryDirectoryCommand}"
Content="Library"
Margin="8">
<ui:Button.Icon>
<ui:SymbolIcon Margin="4" Symbol="Open32" />
</ui:Button.Icon>
</ui:Button>
</StackPanel>
</StackPanel>
</ui:Card>

2
StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs

@ -88,7 +88,7 @@ public partial class CheckpointBrowserCardViewModel : ProgressViewModel
var latestModelFile = latestVersion.Files[0];
var fileExpectedSha256 = latestModelFile.Hashes.SHA256;
var downloadFolder = Path.Combine(settingsManager.Settings.ModelsDirectory,
var downloadFolder = Path.Combine(settingsManager.ModelsDirectory,
model.Type.ConvertTo<SharedFolderType>().GetStringValue());
// Folders might be missing if user didn't install any packages yet
Directory.CreateDirectory(downloadFolder);

2
StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs

@ -27,7 +27,7 @@ public partial class CheckpointManagerViewModel : ObservableObject
public async Task OnLoaded()
{
var modelsDirectory = settingsManager.Settings.ModelsDirectory;
var modelsDirectory = settingsManager.ModelsDirectory;
// Get all folders within the shared folder root
if (string.IsNullOrWhiteSpace(modelsDirectory))
{

6
StabilityMatrix/ViewModels/SettingsViewModel.cs

@ -317,6 +317,12 @@ public partial class SettingsViewModel : ObservableObject
Process.Start("explorer.exe", appPath);
}
[RelayCommand]
private void OpenLibraryDirectory()
{
Process.Start("explorer.exe", settingsManager.LibraryDir);
}
[RelayCommand]
private async Task OpenLicenseDialog()
{

2
StabilityMatrix/ViewModels/TextToImageViewModel.cs

@ -97,7 +97,7 @@ public partial class TextToImageViewModel : ObservableObject
}
// Set the diffusion checkpoint folder
var sdModelsDir = Path.Join(settingsManager.Settings.ModelsDirectory, SharedFolderType.StableDiffusion.GetStringValue());
var sdModelsDir = Path.Join(settingsManager.ModelsDirectory, SharedFolderType.StableDiffusion.GetStringValue());
if (!Directory.Exists(sdModelsDir))
{
logger.LogWarning("Skipped model folder index - {SdModelsDir} does not exist", sdModelsDir);

Loading…
Cancel
Save