Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9818bd8
Update WindowsSdkPackageVersion
mrixner May 30, 2025
5b5832b
Open the debug logs by default in a debug build
mrixner May 30, 2025
c32f443
Allow for a `which` search to return all the findings, not just the f…
mrixner May 30, 2025
5f0e2d6
Add a warning about the Python App Execution Alias (address marticlim…
mrixner May 30, 2025
9d29cf6
Allow package managers to declare any paths they have
mrixner May 30, 2025
cb4c8b9
GetManagerExecutablePath loads the executable from the user's settings
mrixner May 30, 2025
bf1fdcc
Only read / write settings if the setting is not blank
mrixner May 30, 2025
9547294
Allow ComboboxCard index selection
mrixner May 30, 2025
081fcd0
Change LoadAvailablePaths and GetManagerExecutablePath to public
mrixner May 30, 2025
3452fd5
Allow the user to change package manager executable paths in the sett…
mrixner May 30, 2025
ac5f4bc
Update chocolatey path retrievals
mrixner May 30, 2025
4588d65
Fix the 'Restart UniGetUI' notification appearing even when no change…
mrixner May 30, 2025
3974632
Make sure the Chocolatey porter actually ports to system chocolatey a…
mrixner May 30, 2025
43c041c
Merge branch 'main' into 'select-executables'
mrixner Jun 7, 2025
588b9d7
Proper PowerShell path retrieval
mrixner Jul 1, 2025
40a0d4c
Merge branch 'select-executables' of https://github.com/mrixner/UniGe…
mrixner Jul 1, 2025
d6a5cb0
Search for Chocolatey in the ChocolateyInstall environment variable
mrixner Jul 1, 2025
2a8ac79
Merge branch 'main' into 'select-executables'
mrixner Jul 1, 2025
6cad1c0
Lock path changes behind a secure setting
mrixner Jul 1, 2025
d513d90
Properly customize NPM and Scoop scripts
mrixner Jul 1, 2025
a069315
Fix Chocolatey loading order
mrixner Jul 1, 2025
5a59fa4
Check all vcpkg folders for the vcpkg root
mrixner Jul 1, 2025
3d31aeb
Merge branch 'main' into 'select-executables'
mrixner Jul 1, 2025
2c478ed
Merge branch 'main' into select-executables
marticliment Jul 1, 2025
ac9b038
Update Vcpkg.cs
mrixner Jul 3, 2025
482668e
Merge branch 'main' into select-executables
marticliment Jul 4, 2025
64be175
WhichMultiple can return a list only. The boolean is redundant to lis…
marticliment Jul 4, 2025
70d49d1
HashSets are unordered. This could cause weird bugs where paths get r…
marticliment Jul 4, 2025
618e760
Add LoadAvailablePaths to IPackageManager
marticliment Jul 4, 2025
17de48c
Update Scoop.cs
mrixner Jul 4, 2025
a7d0410
Migrate Manager.Properties.ExecutableCallArguments to Manager.Status.…
marticliment Jul 4, 2025
9c121de
Improvements to how arguments are called
marticliment Jul 4, 2025
20bf789
Move powershell5 exe name to CoreData
marticliment Jul 5, 2025
74aa11f
Simplification of ManagerStatus creation
marticliment Jul 5, 2025
f099871
More descriptive method names
marticliment Jul 5, 2025
c7eea03
rename method that is public, for coherence with naming conventions
marticliment Jul 5, 2025
248b8b0
Make GetExecutableFile() more straight forward
marticliment Jul 5, 2025
3959a38
Update PackageManager.cs
marticliment Jul 5, 2025
c3145a3
Instead of migrating the UseSystemChocolatey setting, the toggle can …
marticliment Jul 5, 2025
6f9fd08
Make WinGet compatible again with the "Use bundled WinGet" toggle
marticliment Jul 5, 2025
fe58bac
add .exe when searching for executable files (prevent interferences f…
marticliment Jul 5, 2025
8cd001e
Merge branch 'main' into select-executables
marticliment Jul 5, 2025
b063ad6
Improvements to the "Select package manager executable" control on th…
marticliment Jul 5, 2025
6b5230f
improvements to Administrator settings page
marticliment Jul 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/UniGetUI.Core.Data/CoreData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
}
} else if (IS_PORTABLE is true)
{
return PORTABLE_PATH ?? throw new Exception("This shouldn't be possible");

Check warning on line 61 in src/UniGetUI.Core.Data/CoreData.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)

Check warning on line 61 in src/UniGetUI.Core.Data/CoreData.cs

View workflow job for this annotation

GitHub Actions / test-codebase

Exception type System.Exception is not sufficiently specific (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2201)
}

string old_path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".wingetui");
Expand Down Expand Up @@ -390,5 +390,6 @@
}
}

public static readonly string PowerShell5 = Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe");
}
}
2 changes: 2 additions & 0 deletions src/UniGetUI.Core.SecureSettings/SecureSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public enum K
AllowPrePostOpCommand,
AllowImportPrePostOpCommands,
ForceUserGSudo,
AllowCustomManagerPaths,
Unset
};

Expand All @@ -26,6 +27,7 @@ public static string ResolveKey(K key)
K.AllowPrePostOpCommand => "AllowPrePostInstallCommands",
K.AllowImportPrePostOpCommands => "AllowImportingPrePostInstallCommands",
K.ForceUserGSudo => "ForceUserGSudo",
K.AllowCustomManagerPaths => "AllowCustomManagerPaths",

K.Unset => throw new InvalidDataException("SecureSettings key was unset!"),
_ => throw new KeyNotFoundException($"The SecureSettings key {key} was not found on the ResolveKey map")
Expand Down
2 changes: 2 additions & 0 deletions src/UniGetUI.Core.Settings/SettingsEngine_Names.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public enum K
DisableSuccessNotifications,
DisableProgressNotifications,
KillProcessesThatRefuseToDie,
ManagerPaths,

Test1,
Test2,
Expand Down Expand Up @@ -161,6 +162,7 @@ public static string ResolveKey(K key)
K.DisableSuccessNotifications => "DisableSuccessNotifications",
K.DisableProgressNotifications => "DisableProgressNotifications",
K.KillProcessesThatRefuseToDie => "KillProcessesThatRefuseToDie",
K.ManagerPaths => "ManagerPaths",

K.Test1 => "TestSetting1",
K.Test2 => "TestSetting2",
Expand Down
30 changes: 18 additions & 12 deletions src/UniGetUI.Core.Tools/Tools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,13 @@ public static void RelaunchProcess()
/// Finds an executable in path and returns its location
/// </summary>
/// <param name="command">The executable alias to find</param>
/// <returns>A tuple containing: a boolean hat represents whether the path was found or not; the path to the file if found.</returns>
/// <returns>A tuple containing: a boolean that represents whether the path was found or not; the path to the file if found.</returns>
public static async Task<Tuple<bool, string>> WhichAsync(string command)
{
return await Task.Run(() => Which(command));
}

public static Tuple<bool, string> Which(string command, bool updateEnv = true)
public static List<string> WhichMultiple(string command, bool updateEnv = true)
{
command = command.Replace(";", "").Replace("&", "").Trim();
Logger.Debug($"Begin \"which\" search for command {command}");
Expand Down Expand Up @@ -142,30 +142,36 @@ public static Tuple<bool, string> Which(string command, bool updateEnv = true)
try
{
process.Start();
string? line = process.StandardOutput.ReadLine();
string output;

if (line is null) output = "";
else output = line.Trim();
string[] lines = process.StandardOutput.ReadToEnd()
.Split(["\r\n", "\n"], StringSplitOptions.RemoveEmptyEntries);

process.WaitForExit();

if (process.ExitCode != 0 || output == "")
if (process.ExitCode is not 0)
Logger.Warn($"Call to WhichMultiple with file {command} returned non-zero status {process.ExitCode}");

if (lines.Length is 0)
{
Logger.ImportantInfo($"Command {command} was not found on the system");
return new Tuple<bool, string>(false, "");
return [];
}

Logger.Debug($"Command {command} was found on {output}");
return new Tuple<bool, string>(File.Exists(output), output);
Logger.Debug($"Command {command} was found on {lines[0]} (with {lines.Length-1} more occurrences)");
return lines.ToList();
}
catch
{
if (updateEnv) return Which(command, false);
if (updateEnv) return WhichMultiple(command, false);
throw;
}
}

public static Tuple<bool, string> Which(string command, bool updateEnv = true)
{
var paths = WhichMultiple(command, updateEnv);
return new(paths.Any(), paths.Any() ? paths[0]: "");
}

/// <summary>
/// Formats a given package id as a name, capitalizing words and replacing separators with spaces
/// </summary>
Expand Down
8 changes: 8 additions & 0 deletions src/UniGetUI.PAckageEngine.Interfaces/IPackageManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,13 @@ public interface IPackageManager
/// an example
/// </summary>
public void AttemptFastRepair();

/// <summary>
/// Find all available executable files that apply to this package manager
/// </summary>
/// <returns></returns>
public IReadOnlyList<string> FindCandidateExecutableFiles();
public Tuple<bool, string> GetExecutableFile();

}
}
2 changes: 1 addition & 1 deletion src/UniGetUI.PAckageEngine.Interfaces/ManagerProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public struct ManagerProperties
public string Description { get; set; } = "Unset";
public IconType IconId { get; set; } = IconType.Help;
public string ColorIconId { get; set; } = "Unset";
public string ExecutableCallArgs { get; set; } = "Unset";
// public string ExecutableCallArgs { get; set; } = "Unset";
public string ExecutableFriendlyName { get; set; } = "Unset";
public string InstallVerb { get; set; } = "Unset";
public string UpdateVerb { get; set; } = "Unset";
Expand Down
1 change: 1 addition & 0 deletions src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public struct ManagerStatus
public string Version = "";
public bool Found = false;
public string ExecutablePath = "";
public string ExecutableCallArgs { get; set; } = "Unset";
public ManagerStatus()
{ }
}
Expand Down
17 changes: 11 additions & 6 deletions src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using System.Text.RegularExpressions;
using UniGetUI.Core.Classes;
using UniGetUI.Core.Data;
using UniGetUI.Core.Logging;
using UniGetUI.Core.Tools;
using UniGetUI.PackageEngine.Classes.Manager;
Expand Down Expand Up @@ -29,14 +30,14 @@ public Cargo()
// cargo-update is required to check for installed and upgradable packages
new ManagerDependency(
"cargo-update",
Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"),
CoreData.PowerShell5,
"-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {cargo install cargo-update; if ($error.count -ne 0){pause}}\"",
"cargo install cargo-update",
async () => (await CoreTools.WhichAsync("cargo-install-update.exe")).Item1),
// Cargo-binstall is required to install and update cargo binaries
new ManagerDependency(
"cargo-binstall",
Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"),
CoreData.PowerShell5,
"-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {Set-ExecutionPolicy Unrestricted -Scope Process; iex (iwr \\\"https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.ps1\\\").Content; if ($error.count -ne 0){pause}}\"",
"Set-ExecutionPolicy Unrestricted -Scope Process; iex (iwr \"https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.ps1\").Content",
async () => (await CoreTools.WhichAsync("cargo-binstall.exe")).Item1)
Expand Down Expand Up @@ -64,7 +65,6 @@ public Cargo()
InstallVerb = "binstall",
UninstallVerb = "uninstall",
UpdateVerb = "binstall",
ExecutableCallArgs = "",
DefaultSource = cratesIo,
KnownSources = [cratesIo]
};
Expand Down Expand Up @@ -136,9 +136,14 @@ protected override IReadOnlyList<Package> GetInstalledPackages_UnSafe()
return GetPackages(LoggableTaskType.ListInstalledPackages);
}

public override IReadOnlyList<string> FindCandidateExecutableFiles()
{
return CoreTools.WhichMultiple("cargo.exe");
}

protected override ManagerStatus LoadManager()
{
var (found, executablePath) = CoreTools.Which("cargo");
var (found, executablePath) = GetExecutableFile();
if (!found)
{
return new(){ ExecutablePath = executablePath, Found = false, Version = ""};
Expand All @@ -153,7 +158,7 @@ protected override ManagerStatus LoadManager()
Logger.Error("cargo version error: " + error);
}

return new() { ExecutablePath = executablePath, Found = found, Version = version };
return new() { ExecutablePath = executablePath, Found = found, Version = version, ExecutableCallArgs = ""};
}

private IReadOnlyList<Package> GetPackages(LoggableTaskType taskType)
Expand Down Expand Up @@ -204,7 +209,7 @@ private Process GetProcess(string fileName, string extraArguments)
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = Properties.ExecutableCallArgs + " " + extraArguments,
Arguments = Status.ExecutableCallArgs + " " + extraArguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
Expand Down
79 changes: 37 additions & 42 deletions src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ namespace UniGetUI.PackageEngine.Managers.ChocolateyManager
{
public class Chocolatey : BaseNuGet
{
public static new string[] FALSE_PACKAGE_IDS = ["Directory", "", "Did", "Features?", "Validation", "-", "being", "It", "Error", "L'accs", "Maximum", "This", "Output is package name ", "operable", "Invalid"];
public static new string[] FALSE_PACKAGE_VERSIONS = ["", "of", "Did", "Features?", "Validation", "-", "being", "It", "Error", "L'accs", "Maximum", "This", "packages", "current version", "installed version", "is", "program", "validations", "argument", "no"];
public static readonly string[] FALSE_PACKAGE_IDS = ["Directory", "", "Did", "Features?", "Validation", "-", "being", "It", "Error", "L'accs", "Maximum", "This", "Output is package name ", "operable", "Invalid"];
public static readonly string[] FALSE_PACKAGE_VERSIONS = ["", "of", "Did", "Features?", "Validation", "-", "being", "It", "Error", "L'accs", "Maximum", "This", "packages", "current version", "installed version", "is", "program", "validations", "argument", "no"];
private static readonly string OldChocoPath = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs\\WingetUI\\choco-cli");
private static readonly string NewChocoPath = Path.Join(CoreData.UniGetUIDataDirectory, "Chocolatey");

public Chocolatey()
{
Expand Down Expand Up @@ -54,7 +56,6 @@ public Chocolatey()
InstallVerb = "install",
UninstallVerb = "uninstall",
UpdateVerb = "upgrade",
ExecutableCallArgs = "",
KnownSources = [new ManagerSource(this, "community", new Uri("https://community.chocolatey.org/api/v2/"))],
DefaultSource = new ManagerSource(this, "community", new Uri("https://community.chocolatey.org/api/v2/")),

Expand All @@ -75,7 +76,7 @@ public static string GetProxyArgument()
return $"--proxy {proxyUri.ToString()}";

var creds = Settings.GetProxyCredentials();
if(creds is null)
if (creds is null)
return $"--proxy {proxyUri.ToString()}";

return $"--proxy={proxyUri.ToString()} --proxy-user={Uri.EscapeDataString(creds.UserName)}" +
Expand All @@ -89,7 +90,7 @@ protected override IReadOnlyList<Package> GetAvailableUpdates_UnSafe()
StartInfo = new ProcessStartInfo
{
FileName = Status.ExecutablePath,
Arguments = Properties.ExecutableCallArgs + " outdated " + GetProxyArgument(),
Arguments = Status.ExecutableCallArgs + " outdated " + GetProxyArgument(),
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
Expand Down Expand Up @@ -143,7 +144,7 @@ protected override IReadOnlyList<Package> _getInstalledPackages_UnSafe()
StartInfo = new ProcessStartInfo
{
FileName = Status.ExecutablePath,
Arguments = Properties.ExecutableCallArgs + " list " + GetProxyArgument(),
Arguments = Status.ExecutableCallArgs + " list " + GetProxyArgument(),
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
Expand Down Expand Up @@ -190,18 +191,25 @@ protected override IReadOnlyList<Package> _getInstalledPackages_UnSafe()
return Packages;
}

protected override ManagerStatus LoadManager()
public override IReadOnlyList<string> FindCandidateExecutableFiles()
{
ManagerStatus status = new();
List<string> candidates = [];

string old_choco_path = Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs\\WingetUI\\choco-cli");
string new_choco_path = Path.Join(CoreData.UniGetUIDataDirectory, "Chocolatey");
if (!Settings.Get(Settings.K.UseSystemChocolatey))
{
candidates.Add(Path.Join(NewChocoPath, "choco.exe"));
}
candidates.AddRange(CoreTools.WhichMultiple("choco.exe"));
return candidates;
}

if (!Directory.Exists(old_choco_path))
protected override ManagerStatus LoadManager()
{
if (!Directory.Exists(OldChocoPath))
{
Logger.Debug("Old chocolatey path does not exist, not migrating Chocolatey");
}
else if (CoreTools.IsSymbolicLinkDir(old_choco_path))
else if (CoreTools.IsSymbolicLinkDir(OldChocoPath))
{
Logger.ImportantInfo("Old chocolatey path is a symbolic link, not migrating Chocolatey...");
}
Expand All @@ -217,20 +225,20 @@ protected override ManagerStatus LoadManager()

string current_env_var =
Environment.GetEnvironmentVariable("chocolateyinstall", EnvironmentVariableTarget.User) ?? "";
if (current_env_var != "" && Path.GetRelativePath(current_env_var, old_choco_path) == ".")
if (current_env_var != "" && Path.GetRelativePath(current_env_var, OldChocoPath) == ".")
{
Logger.ImportantInfo("Migrating ChocolateyInstall environment variable to new location");
Environment.SetEnvironmentVariable("chocolateyinstall", new_choco_path, EnvironmentVariableTarget.User);
Environment.SetEnvironmentVariable("chocolateyinstall", NewChocoPath, EnvironmentVariableTarget.User);
}

if (!Directory.Exists(new_choco_path))
if (!Directory.Exists(NewChocoPath))
{
Directory.CreateDirectory(new_choco_path);
Directory.CreateDirectory(NewChocoPath);
}

foreach (string old_subdir in Directory.GetDirectories(old_choco_path, "*", SearchOption.AllDirectories))
foreach (string old_subdir in Directory.GetDirectories(OldChocoPath, "*", SearchOption.AllDirectories))
{
string new_subdir = old_subdir.Replace(old_choco_path, new_choco_path);
string new_subdir = old_subdir.Replace(OldChocoPath, NewChocoPath);
if (!Directory.Exists(new_subdir))
{
Logger.Debug("New directory: " + new_subdir);
Expand All @@ -242,9 +250,9 @@ protected override ManagerStatus LoadManager()
}
}

foreach (string old_file in Directory.GetFiles(old_choco_path, "*", SearchOption.AllDirectories))
foreach (string old_file in Directory.GetFiles(OldChocoPath, "*", SearchOption.AllDirectories))
{
string new_file = old_file.Replace(old_choco_path, new_choco_path);
string new_file = old_file.Replace(OldChocoPath, NewChocoPath);
if (!File.Exists(new_file))
{
Logger.Info("Copying " + old_file);
Expand All @@ -257,7 +265,7 @@ protected override ManagerStatus LoadManager()
}
}

foreach (string old_subdir in Directory.GetDirectories(old_choco_path, "*", SearchOption.AllDirectories).Reverse())
foreach (string old_subdir in Directory.GetDirectories(OldChocoPath, "*", SearchOption.AllDirectories).Reverse())
{
if (!Directory.EnumerateFiles(old_subdir).Any() && !Directory.EnumerateDirectories(old_subdir).Any())
{
Expand All @@ -266,15 +274,15 @@ protected override ManagerStatus LoadManager()
}
}

if (!Directory.EnumerateFiles(old_choco_path).Any() && !Directory.EnumerateDirectories(old_choco_path).Any())
if (!Directory.EnumerateFiles(OldChocoPath).Any() && !Directory.EnumerateDirectories(OldChocoPath).Any())
{
Logger.Info("Deleting old Chocolatey directory " + old_choco_path);
Directory.Delete(old_choco_path);
Logger.Info("Deleting old Chocolatey directory " + OldChocoPath);
Directory.Delete(OldChocoPath);
}

CoreTools.CreateSymbolicLinkDir(old_choco_path, new_choco_path);
CoreTools.CreateSymbolicLinkDir(OldChocoPath, NewChocoPath);
Settings.Set(Settings.K.ChocolateySymbolicLinkCreated, true);
Logger.Info($"Symbolic link created successfully from {old_choco_path} to {new_choco_path}.");
Logger.Info($"Symbolic link created successfully from {OldChocoPath} to {NewChocoPath}.");

}
catch (Exception e)
Expand All @@ -284,21 +292,8 @@ protected override ManagerStatus LoadManager()
}
}

if (Settings.Get(Settings.K.UseSystemChocolatey))
{
status.ExecutablePath = CoreTools.Which("choco.exe").Item2;
}
else if (File.Exists(Path.Join(new_choco_path, "choco.exe")))
{
status.ExecutablePath = Path.Join(new_choco_path, "choco.exe");
}
else
{
status.ExecutablePath = Path.Join(CoreData.UniGetUIDataDirectory, "Chocolatey", "choco.exe");
if (!File.Exists(status.ExecutablePath)) status.ExecutablePath = "";
}

status.Found = File.Exists(status.ExecutablePath);
var (found, executable) = GetExecutableFile();
ManagerStatus status = new() { Found = found, ExecutablePath = executable, ExecutableCallArgs = "", };

if (!status.Found)
{
Expand All @@ -324,7 +319,7 @@ protected override ManagerStatus LoadManager()
// If the user is running bundled chocolatey and chocolatey is not in path, add chocolatey to path
if (!Settings.Get(Settings.K.UseSystemChocolatey)
&& !File.Exists("C:\\ProgramData\\Chocolatey\\bin\\choco.exe"))
/* && Settings.Get(Settings.K.ShownWelcomeWizard)) */
/* && Settings.Get(Settings.K.ShownWelcomeWizard)) */
{
string? path = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.User);
if (!path?.Contains(status.ExecutablePath.Replace("\\choco.exe", "\\bin")) ?? false)
Expand Down
Loading
Loading