diff --git a/src/UniGetUI.Core.Data/CoreData.cs b/src/UniGetUI.Core.Data/CoreData.cs index 72dcc20099..c30fbc2641 100644 --- a/src/UniGetUI.Core.Data/CoreData.cs +++ b/src/UniGetUI.Core.Data/CoreData.cs @@ -390,5 +390,6 @@ private static int GetCodePage() } } + public static readonly string PowerShell5 = Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"); } } diff --git a/src/UniGetUI.Core.SecureSettings/SecureSettings.cs b/src/UniGetUI.Core.SecureSettings/SecureSettings.cs index 7ffe30fbc7..ed496501f0 100644 --- a/src/UniGetUI.Core.SecureSettings/SecureSettings.cs +++ b/src/UniGetUI.Core.SecureSettings/SecureSettings.cs @@ -14,6 +14,7 @@ public enum K AllowPrePostOpCommand, AllowImportPrePostOpCommands, ForceUserGSudo, + AllowCustomManagerPaths, Unset }; @@ -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") diff --git a/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs b/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs index 33a55de508..2c01b4decb 100644 --- a/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs +++ b/src/UniGetUI.Core.Settings/SettingsEngine_Names.cs @@ -75,6 +75,7 @@ public enum K DisableSuccessNotifications, DisableProgressNotifications, KillProcessesThatRefuseToDie, + ManagerPaths, Test1, Test2, @@ -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", diff --git a/src/UniGetUI.Core.Tools/Tools.cs b/src/UniGetUI.Core.Tools/Tools.cs index 68d485ca02..2252b8430a 100644 --- a/src/UniGetUI.Core.Tools/Tools.cs +++ b/src/UniGetUI.Core.Tools/Tools.cs @@ -103,13 +103,13 @@ public static void RelaunchProcess() /// Finds an executable in path and returns its location /// /// The executable alias to find - /// A tuple containing: a boolean hat represents whether the path was found or not; the path to the file if found. + /// A tuple containing: a boolean that represents whether the path was found or not; the path to the file if found. public static async Task> WhichAsync(string command) { return await Task.Run(() => Which(command)); } - public static Tuple Which(string command, bool updateEnv = true) + public static List WhichMultiple(string command, bool updateEnv = true) { command = command.Replace(";", "").Replace("&", "").Trim(); Logger.Debug($"Begin \"which\" search for command {command}"); @@ -142,30 +142,36 @@ public static Tuple 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(false, ""); + return []; } - Logger.Debug($"Command {command} was found on {output}"); - return new Tuple(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 Which(string command, bool updateEnv = true) + { + var paths = WhichMultiple(command, updateEnv); + return new(paths.Any(), paths.Any() ? paths[0]: ""); + } + /// /// Formats a given package id as a name, capitalizing words and replacing separators with spaces /// diff --git a/src/UniGetUI.PAckageEngine.Interfaces/IPackageManager.cs b/src/UniGetUI.PAckageEngine.Interfaces/IPackageManager.cs index 2eea3188b9..50735edd75 100644 --- a/src/UniGetUI.PAckageEngine.Interfaces/IPackageManager.cs +++ b/src/UniGetUI.PAckageEngine.Interfaces/IPackageManager.cs @@ -68,5 +68,13 @@ public interface IPackageManager /// an example /// public void AttemptFastRepair(); + + /// + /// Find all available executable files that apply to this package manager + /// + /// + public IReadOnlyList FindCandidateExecutableFiles(); + public Tuple GetExecutableFile(); + } } diff --git a/src/UniGetUI.PAckageEngine.Interfaces/ManagerProperties.cs b/src/UniGetUI.PAckageEngine.Interfaces/ManagerProperties.cs index 56eac6ffc7..aff3376d32 100644 --- a/src/UniGetUI.PAckageEngine.Interfaces/ManagerProperties.cs +++ b/src/UniGetUI.PAckageEngine.Interfaces/ManagerProperties.cs @@ -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"; diff --git a/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs b/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs index 42a95e916c..5596a77766 100644 --- a/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs +++ b/src/UniGetUI.PackageEngine.Enums/ManagerStatus.cs @@ -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() { } } diff --git a/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs b/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs index e218e4695d..d17401ac88 100644 --- a/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs +++ b/src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs @@ -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; @@ -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) @@ -64,7 +65,6 @@ public Cargo() InstallVerb = "binstall", UninstallVerb = "uninstall", UpdateVerb = "binstall", - ExecutableCallArgs = "", DefaultSource = cratesIo, KnownSources = [cratesIo] }; @@ -136,9 +136,14 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() return GetPackages(LoggableTaskType.ListInstalledPackages); } + public override IReadOnlyList 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 = ""}; @@ -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 GetPackages(LoggableTaskType taskType) @@ -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, diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs index 0a3c486d9b..406a924dbb 100644 --- a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Chocolatey.cs @@ -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() { @@ -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/")), @@ -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)}" + @@ -89,7 +90,7 @@ protected override IReadOnlyList GetAvailableUpdates_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " outdated " + GetProxyArgument(), + Arguments = Status.ExecutableCallArgs + " outdated " + GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -143,7 +144,7 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list " + GetProxyArgument(), + Arguments = Status.ExecutableCallArgs + " list " + GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -190,18 +191,25 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() return Packages; } - protected override ManagerStatus LoadManager() + public override IReadOnlyList FindCandidateExecutableFiles() { - ManagerStatus status = new(); + List 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..."); } @@ -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); @@ -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); @@ -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()) { @@ -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) @@ -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) { @@ -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) diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs index 762f8f19d4..a90ec78369 100644 --- a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateyDetailsHelper.cs @@ -19,7 +19,7 @@ protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage StartInfo = new ProcessStartInfo { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + $" search {package.Id} --exact --all-versions " + Chocolatey.GetProxyArgument(), + Arguments = Manager.Status.ExecutableCallArgs + $" search {package.Id} --exact --all-versions " + Chocolatey.GetProxyArgument(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs index a2ab4fd9da..a6cb717f1d 100644 --- a/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.Chocolatey/Helpers/ChocolateySourceHelper.cs @@ -40,7 +40,7 @@ protected override IReadOnlyList GetSources_UnSafe() StartInfo = new() { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " source list " + Chocolatey.GetProxyArgument(), + Arguments = Manager.Status.ExecutableCallArgs + " source list " + Chocolatey.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs b/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs index 82225200c6..2d988d182f 100644 --- a/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs +++ b/src/UniGetUI.PackageEngine.Managers.Dotnet/DotNet.cs @@ -47,7 +47,6 @@ public DotNet() InstallVerb = "install", UninstallVerb = "uninstall", UpdateVerb = "update", - ExecutableCallArgs = "tool", DefaultSource = new ManagerSource(this, "nuget.org", new Uri("https://www.nuget.org/api/v2")), KnownSources = [new ManagerSource(this, "nuget.org", new Uri("https://www.nuget.org/api/v2"))], }; @@ -66,7 +65,7 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list" + (options.Scope == PackageScope.Global ? " --global" : ""), + Arguments = Status.ExecutableCallArgs + " list" + (options.Scope == PackageScope.Global ? " --global" : ""), RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -125,13 +124,20 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() return Packages; } - protected override ManagerStatus LoadManager() + public override IReadOnlyList FindCandidateExecutableFiles() { - ManagerStatus status = new(); + return CoreTools.WhichMultiple("dotnet.exe"); + } - var (found, path) = CoreTools.Which("dotnet.exe"); - status.ExecutablePath = path; - status.Found = found; + protected override ManagerStatus LoadManager() + { + var (found, path) = GetExecutableFile(); + ManagerStatus status = new() + { + ExecutablePath = path, + Found = found, + ExecutableCallArgs = "tool " + }; if (!status.Found) { @@ -143,7 +149,7 @@ protected override ManagerStatus LoadManager() StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = "tool -h", + Arguments = status.ExecutableCallArgs + "-h", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs index 1e4b78223a..bc533b6fbc 100644 --- a/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.Npm/Helpers/NpmPkgDetailsHelper.cs @@ -26,7 +26,7 @@ protected override void GetDetails_UnSafe(IPackageDetails details) p.StartInfo = new ProcessStartInfo { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " show " + details.Package.Id + " --json", + Arguments = Manager.Status.ExecutableCallArgs + " show " + details.Package.Id + " --json", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -99,7 +99,7 @@ protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage { FileName = Manager.Status.ExecutablePath, Arguments = - Manager.Properties.ExecutableCallArgs + " show " + package.Id + " versions --json", + Manager.Status.ExecutableCallArgs + " show " + package.Id + " versions --json", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs b/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs index 1592da6d11..379ab43bc2 100644 --- a/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs +++ b/src/UniGetUI.PackageEngine.Managers.Npm/Npm.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using System.Text.Json.Nodes; +using UniGetUI.Core.Data; using UniGetUI.Core.Tools; using UniGetUI.Interface.Enums; using UniGetUI.PackageEngine.Classes.Manager; @@ -37,7 +38,6 @@ public Npm() InstallVerb = "install", UninstallVerb = "uninstall", UpdateVerb = "install", - ExecutableCallArgs = " -NoProfile -ExecutionPolicy Bypass -Command npm", DefaultSource = new ManagerSource(this, "npm", new Uri("https://www.npmjs.com/")), KnownSources = [new ManagerSource(this, "npm", new Uri("https://www.npmjs.com/"))], @@ -54,7 +54,7 @@ protected override IReadOnlyList FindPackages_UnSafe(string query) StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " search \"" + query + "\" --json", + Arguments = Status.ExecutableCallArgs + " search \"" + query + "\" --json", RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -106,7 +106,7 @@ protected override IReadOnlyList GetAvailableUpdates_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " outdated --json" + (options.Scope == PackageScope.Global ? " --global" : ""), + Arguments = Status.ExecutableCallArgs + " outdated --json" + (options.Scope == PackageScope.Global ? " --global" : ""), RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -152,7 +152,7 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list --json" + (options.Scope == PackageScope.Global ? " --global" : ""), + Arguments = Status.ExecutableCallArgs + " list --json" + (options.Scope == PackageScope.Global ? " --global" : ""), RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -187,12 +187,29 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() return Packages; } + public override IReadOnlyList FindCandidateExecutableFiles() + { + /*var Paths =*/ return CoreTools.WhichMultiple("npm.ps1"); + /*foreach (string Path in CoreTools.WhichMultiple("npm")) + { + string ps1Path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Path) ?? "", "npm.ps1"); + if (File.Exists(ps1Path) && !Paths.Contains(ps1Path, StringComparer.OrdinalIgnoreCase)) + { + Paths.Add(ps1Path); + } + } + return Paths;*/ + } + protected override ManagerStatus LoadManager() { + var (found, executable) = GetExecutableFile(); + ManagerStatus status = new() { - ExecutablePath = Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"), - Found = CoreTools.Which("npm").Item1 + ExecutablePath = CoreData.PowerShell5, + ExecutableCallArgs = $"-NoProfile -ExecutionPolicy Bypass -Command \"{executable.Replace(" ", "` ")}\" ", + Found = found }; if (!status.Found) @@ -205,7 +222,7 @@ protected override ManagerStatus LoadManager() StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " --version", + Arguments = status.ExecutableCallArgs + "--version", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs index 525980ccbb..8cec49261b 100644 --- a/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.Pip/Helpers/PipPkgDetailsHelper.cs @@ -101,7 +101,7 @@ protected override IReadOnlyList GetInstallableVersions_UnSafe(IPackage StartInfo = new ProcessStartInfo { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " index versions " + package.Id + " " + Pip.GetProxyArgument(), + Arguments = Manager.Status.ExecutableCallArgs + " index versions " + package.Id + " " + Pip.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardInput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs b/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs index 7315c19d2d..86d9277e77 100644 --- a/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs +++ b/src/UniGetUI.PackageEngine.Managers.Pip/Pip.cs @@ -24,7 +24,7 @@ public Pip() // parse_pip_search is required for pip package finding to work new ManagerDependency( "parse-pip-search", - Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"), + CoreData.PowerShell5, "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {python.exe " + "-m pip install parse_pip_search; if($error.count -ne 0){pause}}\"", "python -m pip install parse_pip_search", @@ -64,7 +64,6 @@ public Pip() InstallVerb = "install", UninstallVerb = "uninstall", UpdateVerb = "install --upgrade", - ExecutableCallArgs = " -m pip", DefaultSource = new ManagerSource(this, "pip", new Uri("https://pypi.org/")), KnownSources = [new ManagerSource(this, "pip", new Uri("https://pypi.org/"))], @@ -103,7 +102,7 @@ protected override IReadOnlyList FindPackages_UnSafe(string query) StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " install parse_pip_search " + GetProxyArgument(), + Arguments = Status.ExecutableCallArgs + " install parse_pip_search " + GetProxyArgument(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -186,7 +185,7 @@ protected override IReadOnlyList GetAvailableUpdates_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list --outdated " + GetProxyArgument(), + Arguments = Status.ExecutableCallArgs + " list --outdated " + GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -248,7 +247,7 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list " + GetProxyArgument(), + Arguments = Status.ExecutableCallArgs + " list " + GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -302,13 +301,44 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() return Packages; } + public override IReadOnlyList FindCandidateExecutableFiles() + { + var FoundPaths = CoreTools.WhichMultiple("python"); + List Paths = []; + + if (FoundPaths.Any()) foreach (var Path in FoundPaths) Paths.Add(Path); + + try + { + List DirsToSearch = []; + string ProgramFiles = @"C:\Program Files"; + string? UserPythonInstallDir = null; + string? AppData = Environment.GetEnvironmentVariable("APPDATA"); + + if (AppData != null) + UserPythonInstallDir = Path.Combine(AppData, "Programs", "Python"); + + if (Directory.Exists(ProgramFiles)) DirsToSearch.Add(ProgramFiles); + if (Directory.Exists(UserPythonInstallDir)) DirsToSearch.Add(UserPythonInstallDir); + + foreach (var Dir in DirsToSearch) + { + string DirName = Path.GetFileName(Dir); + string PythonPath = Path.Join(Dir, "python.exe"); + if (DirName.StartsWith("Python") && File.Exists(PythonPath)) + Paths.Add(PythonPath); + } + } + catch (Exception) { } + + return Paths; + } + protected override ManagerStatus LoadManager() { - ManagerStatus status = new(); + var (found, path) = GetExecutableFile(); - var (found, path) = CoreTools.Which("python.exe"); - status.ExecutablePath = path; - status.Found = found; + ManagerStatus status = new() { ExecutablePath = path, Found = found, ExecutableCallArgs = "-m pip " }; if (!status.Found) { @@ -320,7 +350,7 @@ protected override ManagerStatus LoadManager() StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " --version " + GetProxyArgument(), + Arguments = status.ExecutableCallArgs + "--version " + GetProxyArgument(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs index 24aff9c25e..9c3d8ae15a 100644 --- a/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/Helpers/PowerShellSourceHelper.cs @@ -47,7 +47,7 @@ protected override IReadOnlyList GetSources_UnSafe() StartInfo = new() { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " Get-PSRepository", + Arguments = Manager.Status.ExecutableCallArgs + " Get-PSRepository", RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs index c49ea12a06..02ebe707f8 100644 --- a/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell/PowerShell.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Text; using System.Text.RegularExpressions; +using UniGetUI.Core.Data; using UniGetUI.Core.Tools; using UniGetUI.Interface.Enums; using UniGetUI.PackageEngine.Classes.Manager; @@ -47,7 +48,6 @@ public PowerShell() InstallVerb = "Install-Module", UninstallVerb = "Uninstall-Module", UpdateVerb = "Update-Module", - ExecutableCallArgs = " -NoProfile -Command", KnownSources = [new ManagerSource(this, "PSGallery", new Uri("https://www.powershellgallery.com/api/v2")), new ManagerSource(this, "PoshTestGallery", new Uri("https://www.poshtestgallery.com/api/v2"))], DefaultSource = new ManagerSource(this, "PSGallery", new Uri("https://www.powershellgallery.com/api/v2")), @@ -65,7 +65,7 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " Get-InstalledModule", + Arguments = Status.ExecutableCallArgs + " Get-InstalledModule", RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -116,13 +116,22 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() return Packages; } + public override List FindCandidateExecutableFiles() + { + var candidates = CoreTools.WhichMultiple("powershell.exe"); + if(candidates.Count is 0) candidates.Add(CoreData.PowerShell5); + return candidates; + } + protected override ManagerStatus LoadManager() { + var (found, path) = GetExecutableFile(); ManagerStatus status = new() { - ExecutablePath = Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe") + ExecutablePath = path, + Found = found, + ExecutableCallArgs = " -NoProfile -Command", }; - status.Found = File.Exists(status.ExecutablePath); if (!status.Found) { @@ -134,7 +143,7 @@ protected override ManagerStatus LoadManager() StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " \"echo $PSVersionTable\"", + Arguments = status.ExecutableCallArgs + " \"echo $PSVersionTable\"", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs index 2cf616e9bf..96b767cd2c 100644 --- a/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/Helpers/PowerShell7SourceHelper.cs @@ -47,7 +47,7 @@ protected override IReadOnlyList GetSources_UnSafe() StartInfo = new() { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " \"Get-PSRepository | Format-Table -Property " + + Arguments = Manager.Status.ExecutableCallArgs + " \"Get-PSRepository | Format-Table -Property " + "Name,@{N='SourceLocation';E={If ($_.Uri) {$_.Uri.AbsoluteUri} Else {$_.SourceLocation}}}\"", RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs b/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs index 70d2e49aa4..c8c353a81a 100644 --- a/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs +++ b/src/UniGetUI.PackageEngine.Managers.PowerShell7/PowerShell7.cs @@ -48,7 +48,6 @@ public PowerShell7() InstallVerb = "Install-PSResource", UninstallVerb = "Uninstall-PSResource", UpdateVerb = "Update-PSResource", - ExecutableCallArgs = " -NoProfile -Command", KnownSources = [new ManagerSource(this, "PSGallery", new Uri("https://www.powershellgallery.com/api/v2")), new ManagerSource(this, "PoshTestGallery", new Uri("https://www.poshtestgallery.com/api/v2"))], DefaultSource = new ManagerSource(this, "PSGallery", new Uri("https://www.powershellgallery.com/api/v2")), @@ -66,7 +65,7 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " \"Get-InstalledPSResource | Format-Table -Property Name,Version,Repository\"", + Arguments = Status.ExecutableCallArgs + " \"Get-InstalledPSResource | Format-Table -Property Name,Version,Repository\"", RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, @@ -116,14 +115,21 @@ protected override IReadOnlyList _getInstalledPackages_UnSafe() return Packages; } + + public override IReadOnlyList FindCandidateExecutableFiles() + { + return CoreTools.WhichMultiple("pwsh.exe"); + } + protected override ManagerStatus LoadManager() { - var (found, path) = CoreTools.Which("pwsh.exe"); + var (found, path) = GetExecutableFile(); ManagerStatus status = new() { ExecutablePath = path, Found = found, + ExecutableCallArgs = " -NoProfile -Command", }; if (!status.Found) diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs index 0db1abbf5b..a67eae75ce 100644 --- a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopPkgDetailsHelper.cs @@ -44,7 +44,7 @@ protected override void GetDetails_UnSafe(IPackageDetails details) StartInfo = new ProcessStartInfo { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " cat " + packageId, + Arguments = Manager.Status.ExecutableCallArgs + " cat " + packageId, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs index ef34441dff..961239d364 100644 --- a/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Helpers/ScoopSourceHelper.cs @@ -40,7 +40,7 @@ protected override IReadOnlyList GetSources_UnSafe() StartInfo = new ProcessStartInfo { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " bucket list", + Arguments = Manager.Status.ExecutableCallArgs + " bucket list", RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs b/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs index b69056427b..23ef755898 100644 --- a/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs +++ b/src/UniGetUI.PackageEngine.Managers.Scoop/Scoop.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Text.RegularExpressions; using UniGetUI.Core.Classes; +using UniGetUI.Core.Data; using UniGetUI.Core.Logging; using UniGetUI.Core.SettingsEngine; using UniGetUI.Core.Tools; @@ -32,14 +33,14 @@ public Scoop() // Scoop-Search is required for search to work new ManagerDependency( "Scoop-Search", - Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"), + CoreData.PowerShell5, "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {scoop install main/scoop-search; if($error.count -ne 0){pause}}\"", "scoop install main/scoop-search", async () => (await CoreTools.WhichAsync("scoop-search.exe")).Item1), // GIT is required for scoop updates to work new ManagerDependency( "Git", - Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"), + CoreData.PowerShell5, "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {scoop install main/git; if($error.count -ne 0){pause}}\"", "scoop install main/git", async () => (await CoreTools.WhichAsync("git.exe")).Item1) @@ -70,7 +71,6 @@ public Scoop() Description = CoreTools.Translate("Great repository of unknown but useful utilities and other interesting packages.
Contains: Utilities, Command-line programs, General Software (extras bucket required)"), IconId = IconType.Scoop, ColorIconId = "scoop_color", - ExecutableCallArgs = " -NoProfile -ExecutionPolicy Bypass -Command scoop", ExecutableFriendlyName = "scoop", InstallVerb = "install", UpdateVerb = "update", @@ -105,7 +105,7 @@ protected override IReadOnlyList FindPackages_UnSafe(string query) StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " install main/scoop-search", + Arguments = Status.ExecutableCallArgs + " install main/scoop-search", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -200,7 +200,7 @@ protected override IReadOnlyList GetAvailableUpdates_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " status", + Arguments = Status.ExecutableCallArgs + " status", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -279,7 +279,7 @@ private IReadOnlyList _getInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list", + Arguments = Status.ExecutableCallArgs + " list", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -355,7 +355,7 @@ public override void RefreshPackageIndexes() ProcessStartInfo StartInfo = new() { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " update", + Arguments = Status.ExecutableCallArgs + " update", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -372,28 +372,42 @@ public override void RefreshPackageIndexes() logger.Close(p.ExitCode); } + public override IReadOnlyList FindCandidateExecutableFiles() + { + return CoreTools.WhichMultiple("scoop.ps1"); + } + + protected override ManagerStatus LoadManager() { - string path = Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"); + string path = CoreData.PowerShell5; var pwsh7 = CoreTools.Which("pwsh.exe"); + if (pwsh7.Item1) { Logger.Info("Scoop found PowerShell7, PowerShell7 will be used..."); path = pwsh7.Item2; } - + var (found, executable) = GetExecutableFile(); ManagerStatus status = new() { - ExecutablePath = path + ExecutablePath = path, + ExecutableCallArgs = $"-NoProfile -ExecutionPolicy Bypass -Command \"{executable.Replace(" ", "` ")}\" ", + Found = found, }; + if (!status.Found) + { + return status; + } + Process process = new() { StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " --version", + Arguments = status.ExecutableCallArgs + "--version", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -403,7 +417,6 @@ protected override ManagerStatus LoadManager() }; process.Start(); status.Version = process.StandardOutput.ReadToEnd().Trim(); - status.Found = CoreTools.Which("scoop").Item1; Status = status; // Wee need this for the RunCleanup method to get the executable path if (status.Found && IsEnabled() && Settings.Get(Settings.K.EnableScoopCleanup)) @@ -424,7 +437,7 @@ private async void RunCleanup() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " " + command, + Arguments = Status.ExecutableCallArgs + " " + command, UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs index 0f84462324..d2f75d8966 100644 --- a/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs +++ b/src/UniGetUI.PackageEngine.Managers.Vcpkg/Vcpkg.cs @@ -2,6 +2,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; +using UniGetUI.Core.Data; using UniGetUI.Core.Logging; using UniGetUI.Core.SettingsEngine; using UniGetUI.Core.Tools; @@ -30,7 +31,7 @@ public Vcpkg() // GIT is required for vcpkg updates to work new ManagerDependency( "Git", - Path.Join(Environment.SystemDirectory, "windowspowershell\\v1.0\\powershell.exe"), + CoreData.PowerShell5, "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {winget install --id Git.Git --exact " + "--source winget --accept-source-agreements --accept-package-agreements --force; if($error.count -ne 0){pause}}\"", "winget install --id Git.Git --exact --source winget", @@ -62,7 +63,6 @@ public Vcpkg() { "x86-windows", new ManagerSource(this, "x86-windows", URI_VCPKG_IO) } }; - string vcpkgRoot = Settings.GetValue(Settings.K.CustomVcpkgRoot); Properties = new ManagerProperties { Name = "vcpkg", @@ -74,7 +74,6 @@ public Vcpkg() InstallVerb = "install", UninstallVerb = "remove", UpdateVerb = "upgrade", - ExecutableCallArgs = vcpkgRoot == "" ? "" : $" --vcpkg-root=\"{vcpkgRoot}\"", DefaultSource = new ManagerSource(this, DefaultTriplet, URI_VCPKG_IO), KnownSources = [.. TripletSourceMap.Values], }; @@ -93,7 +92,7 @@ protected override IReadOnlyList FindPackages_UnSafe(string query) StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + $" search \"{CoreTools.EnsureSafeQueryString(query)}\"", + Arguments = Status.ExecutableCallArgs + $" search \"{CoreTools.EnsureSafeQueryString(query)}\"", // vcpkg has an --x-json flag that would list installed packages in JSON, but it doesn't work for this call (as of 2024-09-30-ab8988503c7cffabfd440b243a383c0a352a023d) // TODO: Perhaps use --x-json when it is fixed RedirectStandardOutput = true, @@ -176,7 +175,7 @@ protected override IReadOnlyList GetAvailableUpdates_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " update", + Arguments = Status.ExecutableCallArgs + " update", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -230,7 +229,7 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " list", + Arguments = Status.ExecutableCallArgs + " list", // vcpkg has an --x-json flag that would list installed packages in JSON, but it's experimental // TODO: Once --x-json is stable migrate to --x-json RedirectStandardOutput = true, @@ -288,9 +287,23 @@ protected override IReadOnlyList GetInstalledPackages_UnSafe() return Packages; } + public override IReadOnlyList FindCandidateExecutableFiles() + { + var candidates = CoreTools.WhichMultiple("vcpkg.exe"); + + var (rootFound, rootPath) = GetVcpkgRoot(); + if (rootFound) + { + string VcpkgLocation = Path.Join(rootPath, "vcpkg.exe"); + if (File.Exists(VcpkgLocation)) candidates.Add(VcpkgLocation); + } + + return candidates; + } + protected override ManagerStatus LoadManager() { - var (exeFound, exePath) = GetVcpkgPath(); + var (exeFound, exePath) = GetExecutableFile(); var (rootFound, rootPath) = GetVcpkgRoot(); if (!exeFound) @@ -326,7 +339,7 @@ protected override ManagerStatus LoadManager() StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " version", + Arguments = status.ExecutableCallArgs + " version", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -339,20 +352,22 @@ protected override ManagerStatus LoadManager() status.Version = process.StandardOutput.ReadLine()?.Trim() ?? ""; status.Version += $"\n%VCPKG_ROOT% = {rootPath}"; + string vcpkgRoot = Settings.GetValue(Settings.K.CustomVcpkgRoot); + status.ExecutableCallArgs = vcpkgRoot == "" ? "" : $" --vcpkg-root=\"{vcpkgRoot}\""; + return status; } public override void RefreshPackageIndexes() { - var (found, _) = GetVcpkgPath(); var (vcpkgRootFound, vcpkgRoot) = GetVcpkgRoot(); var (gitFound, gitPath) = CoreTools.Which("git"); - if (!found || !gitFound || !vcpkgRootFound) + if (!Status.Found || !gitFound || !vcpkgRootFound) { INativeTaskLogger logger = TaskLogger.CreateNew(LoggableTaskType.RefreshIndexes); if (Settings.Get(Settings.K.DisableUpdateVcpkgGitPorts)) logger.Error("User has disabled updating sources"); - if (!found) logger.Error("Vcpkg was not found???"); + if (!Status.Found) logger.Error("Vcpkg was not found???"); if (!gitFound) logger.Error("Vcpkg sources won't be updated since git was not found"); if (!vcpkgRootFound) logger.Error("Cannot update vcpkg port files as requested: the VCPKG_ROOT environment variable or custom vcpkg root setting was not set"); logger.Close(Settings.Get(Settings.K.DisableUpdateVcpkgGitPorts) ? 0 : 1); @@ -404,28 +419,6 @@ public override void RefreshPackageIndexes() } } - public static Tuple GetVcpkgPath() - { - var (found, path) = CoreTools.Which("vcpkg"); - if (found) - { - return Tuple.Create(found, path); - } - - var (vcpkgRootFound, vcpkgRoot) = GetVcpkgRoot(); - if (vcpkgRootFound) - { - string vcpkgLocation = Path.Join(vcpkgRoot, "vcpkg.exe"); - - if (File.Exists(vcpkgLocation)) - { - return Tuple.Create(true, vcpkgLocation); - } - } - - return Tuple.Create(false, ""); - } - public static Tuple GetVcpkgRoot() { string? vcpkgRoot = Settings.GetValue(Settings.K.CustomVcpkgRoot); @@ -436,14 +429,18 @@ public static Tuple GetVcpkgRoot() if (vcpkgRoot == null) { - // Unfortunately, we can't use `GetVcpkgPath` for this - // as it would become a bunch of functions calling each other - var (found, path) = CoreTools.Which("vcpkg"); - path = Path.GetDirectoryName(path); - // Make sure the root is a valid root not just a random directory - if (found && Path.Exists($"{path}\\triplets")) + // Unfortunately, we can't use `GetVcpkgPath` or `GetExecutableFile` + // for this as it would become a bunch of functions calling each other + var paths = CoreTools.WhichMultiple("vcpkg"); + foreach (string path in paths) { - vcpkgRoot = path; + string dir = Path.GetDirectoryName(path); + // Make sure the root is a valid root not just a random directory + if (Path.Exists($"{dir}\\triplets")) + { + vcpkgRoot = dir; + break; + } } } diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/BundledWinGetHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/BundledWinGetHelper.cs index f00d85c1eb..af3a6d8c16 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/BundledWinGetHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/BundledWinGetHelper.cs @@ -27,8 +27,8 @@ public IReadOnlyList GetAvailableUpdates_UnSafe() { StartInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " update --include-unknown --accept-source-agreements " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, @@ -139,8 +139,8 @@ public IReadOnlyList GetInstalledPackages_UnSafe() { StartInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " list --accept-source-agreements " + WinGet.GetProxyArgument(), + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " list --accept-source-agreements " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, @@ -238,8 +238,8 @@ public IReadOnlyList FindPackages_UnSafe(string query) { StartInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " search \"" + query + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " search \"" + query + "\" --accept-source-agreements " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, @@ -336,8 +336,8 @@ public void GetPackageDetails_UnSafe(IPackageDetails details) bool LocaleFound = true; ProcessStartInfo startInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + " --disable-interactivity --accept-source-agreements --locale " + System.Globalization.CultureInfo.CurrentCulture + " " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, @@ -384,8 +384,8 @@ public void GetPackageDetails_UnSafe(IPackageDetails details) LocaleFound = true; startInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + " --disable-interactivity --accept-source-agreements --locale en-US " + " " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, @@ -428,8 +428,8 @@ public void GetPackageDetails_UnSafe(IPackageDetails details) process = new Process(); startInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + " --disable-interactivity --accept-source-agreements " + " " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, @@ -573,8 +573,8 @@ public IReadOnlyList GetInstallableVersions_Unsafe(IPackage package) { StartInfo = new ProcessStartInfo { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(package) + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(package) + $" --versions --accept-source-agreements " + " " + WinGet.GetProxyArgument(), UseShellExecute = false, RedirectStandardOutput = true, @@ -629,7 +629,7 @@ public IReadOnlyList GetSources_UnSafe() StartInfo = new() { FileName = Manager.Status.ExecutablePath, - Arguments = Manager.Properties.ExecutableCallArgs + " source list " + WinGet.GetProxyArgument(), + Arguments = Manager.Status.ExecutableCallArgs + " source list " + WinGet.GetProxyArgument(), RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs index 763fb77c58..c87ce8573e 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/ClientHelpers/NativeWinGetHelper.cs @@ -358,8 +358,8 @@ public void GetPackageDetails_UnSafe(IPackageDetails details) List output = []; ProcessStartInfo startInfo = new() { - FileName = Manager.WinGetBundledPath, - Arguments = Manager.Properties.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + + FileName = Manager.BundledWinGetPath, + Arguments = Manager.Status.ExecutableCallArgs + " show " + WinGetPkgOperationHelper.GetIdNamePiece(details.Package) + " --disable-interactivity --accept-source-agreements --source " + details.Package.Source.Name, RedirectStandardOutput = true, diff --git a/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs b/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs index b9964b730c..17e44f306e 100644 --- a/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs +++ b/src/UniGetUI.PackageEngine.Managers.WinGet/WinGet.cs @@ -30,11 +30,11 @@ public class WinGet : PackageManager public LocalWinGetSource MicrosoftStoreSource { get; } public static bool NO_PACKAGES_HAVE_BEEN_LOADED { get; private set; } - public string WinGetBundledPath; + public string BundledWinGetPath; public WinGet() { - WinGetBundledPath = Path.Join(CoreData.UniGetUIExecutableDirectory, "winget-cli_x64", "winget.exe"); + BundledWinGetPath = Path.Join(CoreData.UniGetUIExecutableDirectory, "winget-cli_x64", "winget.exe"); Capabilities = new ManagerCapabilities { @@ -71,7 +71,6 @@ public WinGet() InstallVerb = "install", UninstallVerb = "uninstall", UpdateVerb = "update", - ExecutableCallArgs = "", KnownSources = [ new ManagerSource(this, "winget", new Uri("https://cdn.winget.microsoft.com/cache")), new ManagerSource(this, "msstore", new Uri("https://storeedgefd.dsx.mp.microsoft.com/v9.0")) ], DefaultSource = new ManagerSource(this, "winget", new Uri("https://cdn.winget.microsoft.com/cache")) @@ -173,28 +172,37 @@ public ManagerSource GetLocalSource(string id) return LocalPcSource; } + public override IReadOnlyList FindCandidateExecutableFiles() + { + List candidates = new(); + if (!Settings.Get(Settings.K.ForceLegacyBundledWinGet)) + { + candidates.AddRange(CoreTools.WhichMultiple("winget.exe")); + } + + candidates.Add(BundledWinGetPath); + return candidates; + } + protected override ManagerStatus LoadManager() { - ManagerStatus status = new(); bool FORCE_BUNDLED = Settings.Get(Settings.K.ForceLegacyBundledWinGet); + var (found, path) = GetExecutableFile(); - var (found, path) = CoreTools.Which("winget.exe"); - status.ExecutablePath = path; - status.Found = found; + ManagerStatus status = new() + { + ExecutablePath = path, + ExecutableCallArgs = "", + Found = found, + }; - if (!status.Found) + if (found && status.ExecutablePath == BundledWinGetPath && !FORCE_BUNDLED) { Logger.Error("User does not have WinGet installed, forcing bundled WinGet..."); FORCE_BUNDLED = true; } - if (FORCE_BUNDLED) - { - status.ExecutablePath = WinGetBundledPath; - status.Found = File.Exists(WinGetBundledPath); - } - if (!status.Found) { return status; @@ -207,7 +215,7 @@ protected override ManagerStatus LoadManager() StartInfo = new ProcessStartInfo { FileName = status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " --version", + Arguments = status.ExecutableCallArgs + " --version", UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, @@ -348,7 +356,7 @@ public override void RefreshPackageIndexes() StartInfo = new ProcessStartInfo { FileName = Status.ExecutablePath, - Arguments = Properties.ExecutableCallArgs + " source update --disable-interactivity " + GetProxyArgument(), + Arguments = Status.ExecutableCallArgs + " source update --disable-interactivity " + GetProxyArgument(), UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, diff --git a/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs b/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs index 0e9e35ba6f..b37c8f589c 100644 --- a/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs +++ b/src/UniGetUI.PackageEngine.Operations/PackageOperations.cs @@ -96,12 +96,12 @@ protected sealed override void PrepareProcessStartInfo() } FileName = CoreData.ElevatorPath; - Arguments = $"\"{Package.Manager.Status.ExecutablePath}\" {Package.Manager.Properties.ExecutableCallArgs} {operation_args}"; + Arguments = $"\"{Package.Manager.Status.ExecutablePath}\" {Package.Manager.Status.ExecutableCallArgs} {operation_args}"; } else { FileName = Package.Manager.Status.ExecutablePath; - Arguments = $"{Package.Manager.Properties.ExecutableCallArgs} {operation_args}"; + Arguments = $"{Package.Manager.Status.ExecutableCallArgs} {operation_args}"; } if (IsAdmin && Package.Manager is WinGet) diff --git a/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs b/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs index 0bd01ed287..2916f02b09 100644 --- a/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs +++ b/src/UniGetUI.PackageEngine.Operations/SourceOperations.cs @@ -62,13 +62,13 @@ protected override void PrepareProcessStartInfo() admin = true; process.StartInfo.FileName = CoreData.ElevatorPath; - process.StartInfo.Arguments = $"\"{Source.Manager.Status.ExecutablePath}\" " + Source.Manager.Properties.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetAddSourceParameters(Source)); + process.StartInfo.Arguments = $"\"{Source.Manager.Status.ExecutablePath}\" " + Source.Manager.Status.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetAddSourceParameters(Source)); } else { process.StartInfo.FileName = Source.Manager.Status.ExecutablePath; - process.StartInfo.Arguments = Source.Manager.Properties.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetAddSourceParameters(Source)); + process.StartInfo.Arguments = Source.Manager.Status.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetAddSourceParameters(Source)); } ApplyCapabilities(admin, false, false, null); @@ -115,12 +115,12 @@ protected override void PrepareProcessStartInfo() admin = true; process.StartInfo.FileName = CoreData.ElevatorPath; - process.StartInfo.Arguments = $"\"{Source.Manager.Status.ExecutablePath}\" " + Source.Manager.Properties.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetRemoveSourceParameters(Source)); + process.StartInfo.Arguments = $"\"{Source.Manager.Status.ExecutablePath}\" " + Source.Manager.Status.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetRemoveSourceParameters(Source)); } else { process.StartInfo.FileName = Source.Manager.Status.ExecutablePath; - process.StartInfo.Arguments = Source.Manager.Properties.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetRemoveSourceParameters(Source)); + process.StartInfo.Arguments = Source.Manager.Status.ExecutableCallArgs + " " + string.Join(" ", Source.Manager.SourcesHelper.GetRemoveSourceParameters(Source)); } ApplyCapabilities(admin, false, false, null); } diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs index 0fce81ae8d..b14fdb7392 100644 --- a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/Classes/NullPackageManager.cs @@ -43,7 +43,6 @@ public NullPackageManager() Description = "Unset", IconId = IconType.Help, ColorIconId = "Unset", - ExecutableCallArgs = "Unset", ExecutableFriendlyName = "Unset", InstallVerb = "Unset", UpdateVerb = "Unset", @@ -55,54 +54,41 @@ public NullPackageManager() Status = new ManagerStatus { ExecutablePath = "C:/file.exe", + ExecutableCallArgs = "Unset", Found = false, Version = "0" }; Dependencies = []; } - public IReadOnlyList FindPackages(string query) => throw new NotImplementedException(); - public IReadOnlyList GetAvailableUpdates() => throw new NotImplementedException(); - public IReadOnlyList GetInstalledPackages() => throw new NotImplementedException(); - public void Initialize() => throw new NotImplementedException(); - public bool IsEnabled() => throw new NotImplementedException(); - public bool IsReady() => throw new NotImplementedException(); - public void RefreshPackageIndexes() => throw new NotImplementedException(); - public void AttemptFastRepair() => throw new NotImplementedException(); + public IReadOnlyList FindCandidateExecutableFiles() => throw new NotImplementedException(); + public Tuple GetExecutableFile() => throw new NotImplementedException(); } internal class NullSourceHelper : IMultiSourceHelper { public ISourceFactory Factory => throw new NotImplementedException(); - public string[] GetAddSourceParameters(IManagerSource source) => throw new NotImplementedException(); - public string[] GetRemoveSourceParameters(IManagerSource source) => throw new NotImplementedException(); - public OperationVeredict GetAddOperationVeredict(IManagerSource source, int ReturnCode, string[] Output) => throw new NotImplementedException(); - public OperationVeredict GetRemoveOperationVeredict(IManagerSource source, int ReturnCode, string[] Output) => throw new NotImplementedException(); - public IReadOnlyList GetSources() => throw new NotImplementedException(); + } internal sealed class NullPkgDetailsHelper : IPackageDetailsHelper { public void GetDetails(IPackageDetails details) => throw new NotImplementedException(); - public IReadOnlyList GetVersions(IPackage package) => throw new NotImplementedException(); - public CacheableIcon? GetIcon(IPackage package) => throw new NotImplementedException(); - public IReadOnlyList GetScreenshots(IPackage package) => throw new NotImplementedException(); - public string? GetInstallLocation(IPackage package) => throw new NotImplementedException(); } diff --git a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs index 5a3068c019..06b352f169 100644 --- a/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs +++ b/src/UniGetUI.PackageEngine.PackageManagerClasses/Manager/PackageManager.cs @@ -1,5 +1,6 @@ using UniGetUI.Core.Logging; using UniGetUI.Core.SettingsEngine; +using UniGetUI.Core.SettingsEngine.SecureSettings; using UniGetUI.PackageEngine.Classes.Manager; using UniGetUI.PackageEngine.Classes.Manager.Classes; using UniGetUI.PackageEngine.Classes.Manager.ManagerHelpers; @@ -59,7 +60,7 @@ public virtual void Initialize() // END integrity check Properties.DefaultSource.RefreshSourceNames(); - foreach(var source in Properties.KnownSources) + foreach (var source in Properties.KnownSources) { source.RefreshSourceNames(); } @@ -95,7 +96,7 @@ public virtual void Initialize() (Status.Found ? "\n█ Fancy exe name: " + Properties.ExecutableFriendlyName + "\n█ Executable path: " + Status.ExecutablePath + - "\n█ Call arguments: " + Properties.ExecutableCallArgs + + "\n█ Call arguments: " + Status.ExecutableCallArgs + "\n█ Version: \n" + "█ " + Status.Version.Replace("\n", "\n█ ") : "\n█ THE MANAGER WAS NOT FOUND. PERHAPS IT IS NOT " + @@ -116,6 +117,59 @@ public virtual void Initialize() } } + /// + /// Returns a list of paths that could be used for this package manager. + /// For example, if you have three Pythons installed on your system, this would return those three Pythons. + /// + /// A tuple containing: a boolean that represents whether the path was found or not; the path to the file if found. + public abstract IReadOnlyList FindCandidateExecutableFiles(); + + public Tuple GetExecutableFile() + { + var candidates = FindCandidateExecutableFiles(); + if (candidates.Count == 0) + { + // No paths were found + return new (false, ""); + } + + // If custom package manager paths are DISABLED, get the first one (as old UniGetUI did) and return it. + if(!SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths)) + { + return new(true, candidates[0]); + } + else + { + string? exeSelection = Settings.GetDictionaryItem(Settings.K.ManagerPaths, Name); + // If there is no executable selection for this package manager + if (string.IsNullOrEmpty(exeSelection)) + { + return new(true, candidates[0]); + } + else if (!File.Exists(exeSelection)) + { + Logger.Error($"The selected executable path {exeSelection} for manager {Name} does not exist, the default one will be used..."); + return new(true, candidates[0]); + } + + // While technically executables that are not in the path should work, + // since detection of executables will be performed in the path only, it is more consistent + // to throw an error when a non-path executable is used. Furthermore, doing this we can filter out + // any invalid paths or files + if (candidates.Select(x => x.ToLower()).Contains(exeSelection.ToLower())) + { + return new(true, exeSelection); + } + else + { + Logger.Error($"The selected executable path {exeSelection} for manager {Name} was not found in path " + + $"(executables found in path are [{string.Join(',', candidates)}]), the default will be used..."); + return new(true, candidates[0]); + } + + } + } + /// /// Returns a ManagerStatus object representing the current status of the package manager. This method runs asynchronously. /// diff --git a/src/UniGetUI/Controls/SettingsWidgets/ComboboxCard.cs b/src/UniGetUI/Controls/SettingsWidgets/ComboboxCard.cs index a1d8755516..3c29cc974d 100644 --- a/src/UniGetUI/Controls/SettingsWidgets/ComboboxCard.cs +++ b/src/UniGetUI/Controls/SettingsWidgets/ComboboxCard.cs @@ -84,5 +84,6 @@ public void ShowAddedItems() } public string SelectedValue() => _combobox.SelectedValue.ToString() ?? throw new InvalidCastException(); + public void SelectIndex(int index) => _combobox.SelectedIndex = index; } } diff --git a/src/UniGetUI/MainWindow.xaml.cs b/src/UniGetUI/MainWindow.xaml.cs index 9923d6cf87..d4298d46b5 100644 --- a/src/UniGetUI/MainWindow.xaml.cs +++ b/src/UniGetUI/MainWindow.xaml.cs @@ -56,7 +56,7 @@ public MainWindow() DialogHelper.Window = this; WindowManager.Get(this).IsMinimizable = false; - WindowManager.Get(this).IsMaximizable = false; + // WindowManager.Get(this).IsMaximizable = false; InitializeComponent(); DismissableNotification.CloseButtonContent = CoreTools.Translate("Close"); diff --git a/src/UniGetUI/Pages/DialogPages/DialogHelper_Generic.cs b/src/UniGetUI/Pages/DialogPages/DialogHelper_Generic.cs index 1ab9f7465f..bc4e3d9bb4 100644 --- a/src/UniGetUI/Pages/DialogPages/DialogHelper_Generic.cs +++ b/src/UniGetUI/Pages/DialogPages/DialogHelper_Generic.cs @@ -399,9 +399,7 @@ public static async void HandleBrokenWinGet() { StartInfo = new() { - FileName = - Path.Join(Environment.SystemDirectory, - "windowspowershell\\v1.0\\powershell.exe"), + FileName = CoreData.PowerShell5, Arguments = "-ExecutionPolicy Bypass -NoLogo -NoProfile -Command \"& {" + "cmd.exe /C \"rmdir /Q /S `\"%temp%\\WinGet`\"\"; " + diff --git a/src/UniGetUI/Pages/LogPages/UniGetUILogPage.cs b/src/UniGetUI/Pages/LogPages/UniGetUILogPage.cs index 19b62d1ce2..7135094bc9 100644 --- a/src/UniGetUI/Pages/LogPages/UniGetUILogPage.cs +++ b/src/UniGetUI/Pages/LogPages/UniGetUILogPage.cs @@ -20,6 +20,9 @@ protected override void LoadLogLevels() LogLevelCombo.Items.Add(CoreTools.Translate("4 - Information (more)")); LogLevelCombo.Items.Add(CoreTools.Translate("5 - information (debug)")); LogLevelCombo.SelectedIndex = 3; +#if DEBUG + LogLevelCombo.SelectedIndex = 4; +#endif } public override void LoadLog(bool isReload = false) diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml index 6128421e16..0626706c1a 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml @@ -73,6 +73,18 @@ Text="Ignore custom pre-install and post-install commands when importing packages from a bundle" WarningText="Pre and post install commands will be run before and after a package gets installed, upgraded or uninstalled. Be aware that they may break things unless used carefully" /> + + + + + diff --git a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs index 81aa4dda69..b7e9957aeb 100644 --- a/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs +++ b/src/UniGetUI/Pages/SettingsPages/GeneralPages/Administrator.xaml.cs @@ -15,7 +15,7 @@ public Administrator() { this.InitializeComponent(); - if(DoCacheAdminRights.Checked && DoCacheAdminRightsForBatches.Checked) + if (DoCacheAdminRights.Checked && DoCacheAdminRightsForBatches.Checked) { DoCacheAdminRights.IsEnabled = true; DoCacheAdminRightsForBatches.IsEnabled = true; @@ -23,9 +23,11 @@ public Administrator() WarningTitlebar.Title = CoreTools.Translate("Warning") + "!"; WarningTitlebar.Message = - CoreTools.Translate("The following settings may pose a security risk, hence they are disabled by default.") + " " + - CoreTools.Translate("Enable the settings below if and only if you fully understand what they do, and the implications they may have.") + "\n\n" + + CoreTools.Translate("The following settings may pose a security risk, hence they are disabled by default.") + " " + + CoreTools.Translate("Enable the settings below if and only if you fully understand what they do, and the implications they may have.") + "\n\n" + CoreTools.Translate("The settings will list, in their descriptions, the potential security issues they may have.") + " "; + + AllowCustomManagerPaths.StateChanged += (_, _) => RestartRequired?.Invoke(this, EventArgs.Empty); // The following settings may pose a security risk, hence they are disabled by default. Enable them ONLY if you undertsand what you are doing. Some of those settings will show a UAC prompt before being enabled." diff --git a/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml b/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml index 3265be3212..dfd82fc083 100644 --- a/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml +++ b/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml @@ -52,9 +52,66 @@ Visibility="Collapsed" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml.cs b/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml.cs index d1b1959b6c..3be4474825 100644 --- a/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml.cs +++ b/src/UniGetUI/Pages/SettingsPages/ManagersPages/PackageManager.xaml.cs @@ -21,6 +21,10 @@ using UniGetUI.Core.Data; using UniGetUI.Pages.DialogPages; using UniGetUI.Core.SettingsEngine; +using UniGetUI.PackageEngine.ManagerClasses.Manager; +using UniGetUI.Core.Logging; +using UniGetUI.Core.SettingsEngine.SecureSettings; +using UniGetUI.Interface; // To learn more about WinUI, the WinUI project structure, // and more about our project templates, see: http://aka.ms/winui-project-info. @@ -37,7 +41,7 @@ public sealed partial class PackageManagerPage : Page, ISettingsPage public event EventHandler? NavigationRequested; public event EventHandler? ReapplyProperties; public bool CanGoBack => true; - public string ShortTitle => Manager is null? "": CoreTools.Translate("{0} settings", Manager.DisplayName); + public string ShortTitle => Manager is null ? "" : CoreTools.Translate("{0} settings", Manager.DisplayName); public PackageManagerPage() { @@ -67,7 +71,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e) LongVersionTextBlock.Text = Manager.Status.Version + "\n"; SetManagerStatus(false); - LocationLabel.Text = Manager.Status.ExecutablePath + Manager.Properties.ExecutableCallArgs; + LocationLabel.Text = Manager.Status.ExecutablePath + " " + Manager.Status.ExecutableCallArgs.Trim(); if (LocationLabel.Text == "") LocationLabel.Text = CoreTools.Translate("The executable file for {0} was not found", Manager.DisplayName); EnableManager.KeyName = Manager.Name; EnableManager.Text = CoreTools.Translate("Enable {pm}").Replace("{pm}", Manager.DisplayName); @@ -86,18 +90,39 @@ protected override void OnNavigatedTo(NavigationEventArgs e) ManagerLogsLabel.Text = CoreTools.Translate("View {0} logs", Manager.DisplayName); + // ----------------- EXECUTABLE FILE PICKER ----------------- + ExeFileWarningText.Visibility = SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths) ? Visibility.Collapsed : Visibility.Visible; + GoToSecureSettingsBtn.Visibility = SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths) ? Visibility.Collapsed : Visibility.Visible; + ExecutableComboBox.IsEnabled = SecureSettings.Get(SecureSettings.K.AllowCustomManagerPaths); + ExecutableComboBox.Items.Clear(); + foreach(var path in Manager.FindCandidateExecutableFiles()) + { + ExecutableComboBox.Items.Add(path); + } + + string selectedValue = Settings.GetDictionaryItem(Settings.K.ManagerPaths, Manager.Name) ?? ""; + if (string.IsNullOrEmpty(selectedValue)) + { + var exe = Manager.GetExecutableFile(); + selectedValue = exe.Item1? exe.Item2: ""; + } + + ExecutableComboBox.SelectedValue = selectedValue; + ExecutableComboBox.SelectionChanged += ExecutableComboBox_SelectionChanged; + InstallOptionsPanel.Description = new InstallOptions_Manager(Manager); // ----------------------- SOURCES CONTROL ------------------- ExtraControls.Children.Clear(); - if(Manager.Capabilities.SupportsCustomSources && Manager is not Vcpkg) + if (Manager.Capabilities.SupportsCustomSources && Manager is not Vcpkg) { - SettingsCard SourceManagerCard = new() { + SettingsCard SourceManagerCard = new() + { Resources = { ["SettingsCardLeftIndention"] = 10 }, CornerRadius = new CornerRadius(8), - Margin = new Thickness(0,0,0,16) + Margin = new Thickness(0, 0, 0, 16) }; var man = new SourceManager(Manager); SourceManagerCard.Description = man; @@ -334,7 +359,18 @@ protected override void OnNavigatedTo(NavigationEventArgs e) ExtraControls.Children.Add(DisableNotifsCard); } - base.OnNavigatedTo(e); + // Hide the AppExecutionAliasWarning element if Manager is not Pip + if (Manager is Pip) + { + ManagerLogs.CornerRadius = new CornerRadius(8, 8, 0, 0); + AppExecutionAliasWarningLabel.Text = "If Python cannot be found or is not listing packages but is installed on the system, you may need to disable the \"python.exe\" App Execution Alias in the settings."; + } + else + { + AppExecutionAliasWarning.Visibility = Visibility.Collapsed; + } + + base.OnNavigatedTo(e); } private void ShowVersionHyperlink_Click(object sender, RoutedEventArgs e) @@ -353,7 +389,7 @@ void SetManagerStatus(bool ShowVersion = false) if (!Manager.Status.Version.Contains('\n')) { ManagerStatusBar.Message = - CoreTools.Translate("{pm} version:", new Dictionary {{ "pm", Manager.DisplayName }}) + $" {Manager.Status.Version}"; + CoreTools.Translate("{pm} version:", new Dictionary { { "pm", Manager.DisplayName } }) + $" {Manager.Status.Version}"; } else if (ShowVersion) { @@ -398,5 +434,19 @@ private void ManagerLogs_Click(object sender, RoutedEventArgs e) { MainApp.Instance.MainWindow.NavigationPage.OpenManagerLogs(Manager as IPackageManager); } + + private void ExecutableComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (string.IsNullOrEmpty(ExecutableComboBox.SelectedValue.ToString())) + return; + + Settings.SetDictionaryItem(Settings.K.ManagerPaths, Manager!.Name, ExecutableComboBox.SelectedValue.ToString()); + RestartRequired?.Invoke(this, EventArgs.Empty); + } + + private void GoToSecureSettingsBtn_Click(object sender, RoutedEventArgs e) + { + MainApp.Instance.MainWindow.NavigationPage.OpenSettingsPage(typeof(Administrator)); + } } }