Files
OmniNX-Installer-Payload/desktop/OmniNX.DesktopInstaller/Services/PathUtils.cs
T
niklascfw 91133f7098
Build / Build (push) Successful in 13s
Build Desktop Installer / Build (win-arm64) (push) Successful in 10s
Build Desktop Installer / Build (win-x64) (push) Successful in 10s
Desktop installer: release channel, saved choices, robust delete, logs
- Channel radio (Release / Master (Instabil)); master installs the
  rolling 'master' release from OmniNX/OmniNX-Master. Preselected from
  release_channel in the card's manifest.ini.
- Variant, RAM (8gb) and Hekate-Pro choice are prefilled from the card
  (manifest.ini / config.ini) like the payload does, instead of
  silently switching users back to 4 GB / Standard.
- Clear read-only attributes before deleting folders.
- Remove leftover "OmniNX <Variant>" pack folders after installing.
- Create empty folders from the pack.
- Save every run's log to %LocalAppData%\OmniNX-Desktop-Installer\logs,
  plus a "Save log" button.
2026-11-14 13:10:41 +01:00

151 lines
4.6 KiB
C#

using OmniNX.DesktopInstaller.Models;
namespace OmniNX.DesktopInstaller.Services;
public static class VariantHelper
{
public static string GetDisplayName(OmniNxVariant variant) => variant switch
{
OmniNxVariant.Light => "Light",
OmniNxVariant.Standard => "Standard",
OmniNxVariant.Oc => "OC",
_ => "None",
};
public static string GetStagingFolderName(OmniNxVariant variant) => variant switch
{
OmniNxVariant.Light => "OmniNX Light",
OmniNxVariant.Standard => "OmniNX Standard",
OmniNxVariant.Oc => "OmniNX OC",
_ => string.Empty,
};
public static string GetZipAssetPrefix(OmniNxVariant variant) => variant switch
{
OmniNxVariant.Light => "OmniNX-Light",
OmniNxVariant.Standard => "OmniNX-Standard",
OmniNxVariant.Oc => "OmniNX-OC",
_ => string.Empty,
};
public static OmniNxVariant ParsePackName(string? value)
{
if (string.IsNullOrWhiteSpace(value))
return OmniNxVariant.None;
return value.Trim() switch
{
"Light" => OmniNxVariant.Light,
"Standard" => OmniNxVariant.Standard,
"OC" => OmniNxVariant.Oc,
_ => OmniNxVariant.None,
};
}
}
public static class PathUtils
{
public static string NormalizeDriveRoot(string driveRoot)
{
var root = driveRoot.Trim();
if (!root.EndsWith(Path.DirectorySeparatorChar))
root += Path.DirectorySeparatorChar;
return root;
}
public static string ToDrivePath(string driveRoot, string sdRelative)
{
var rel = sdRelative.Replace("sd:/", string.Empty).Replace("sd:\\", string.Empty)
.Replace('/', Path.DirectorySeparatorChar);
return Path.Combine(NormalizeDriveRoot(driveRoot), rel);
}
public static string RelativeFromDrive(string driveRoot, string fullPath)
{
var root = NormalizeDriveRoot(driveRoot);
if (fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase))
return fullPath[root.Length..];
return fullPath;
}
public static bool PathExists(string path)
{
return Directory.Exists(path) || File.Exists(path);
}
public static void EnsureDirectory(string path)
{
Directory.CreateDirectory(path);
}
public static void CopyFile(string src, string dst, bool overwrite = true)
{
var dir = Path.GetDirectoryName(dst);
if (!string.IsNullOrEmpty(dir))
Directory.CreateDirectory(dir);
File.Copy(src, dst, overwrite);
}
public static void CopyDirectory(string src, string dst, IProgress<(int current, int total, string file)>? progress = null)
{
if (!Directory.Exists(src))
return;
// Folders first, so empty folders from the pack exist on the SD as well.
Directory.CreateDirectory(dst);
foreach (var dir in Directory.GetDirectories(src, "*", SearchOption.AllDirectories))
Directory.CreateDirectory(Path.Combine(dst, Path.GetRelativePath(src, dir)));
var files = Directory.GetFiles(src, "*", SearchOption.AllDirectories);
var total = files.Length;
var current = 0;
foreach (var file in files)
{
var rel = Path.GetRelativePath(src, file);
var target = Path.Combine(dst, rel);
CopyFile(file, target);
current++;
progress?.Report((current, total, rel));
}
}
public static void DeletePath(string path)
{
if (File.Exists(path))
{
File.SetAttributes(path, FileAttributes.Normal);
File.Delete(path);
return;
}
if (Directory.Exists(path))
{
// Directory.Delete fails on read-only entries (common on cards from other packs or macOS).
var root = new DirectoryInfo(path);
foreach (var entry in root.EnumerateFileSystemInfos("*", SearchOption.AllDirectories))
{
if (entry.Attributes.HasFlag(FileAttributes.ReadOnly))
entry.Attributes &= ~FileAttributes.ReadOnly;
}
if (root.Attributes.HasFlag(FileAttributes.ReadOnly))
root.Attributes &= ~FileAttributes.ReadOnly;
root.Delete(recursive: true);
}
}
public static int CountItemsRecursive(string path)
{
if (File.Exists(path))
return 1;
if (!Directory.Exists(path))
return 0;
var count = 1;
foreach (var entry in Directory.EnumerateFileSystemEntries(path, "*", SearchOption.AllDirectories))
count++;
return count;
}
}