Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private void BuildExtraControls(CheckboxCard_Dict disableNotifsCard)
{
ExtraControls.Children.Clear();
var manager = ViewModel.Manager;
bool managerHasSources = manager.Capabilities.SupportsCustomSources && manager.Name != "Vcpkg";
bool managerHasSources = manager.Capabilities.SupportsCustomSources && manager.Name != "vcpkg";

if (managerHasSources)
{
Expand Down Expand Up @@ -330,7 +330,7 @@ private void BuildExtraControls(CheckboxCard_Dict disableNotifsCard)
ExtraControls.Children.Add(chocoSysChoco);
break;

case "Vcpkg":
case "vcpkg":
disableNotifsCard.CornerRadius = new CornerRadius(8, 8, 0, 0);
disableNotifsCard.BorderThickness = new Thickness(1, 1, 1, 0);
ExtraControls.Children.Add(disableNotifsCard);
Expand Down Expand Up @@ -405,7 +405,8 @@ private ButtonCard BuildVcpkgRootCard()
descPanel.Children.Add(openBtn);
vcpkgRootCard.Description = descPanel;

vcpkgRootCard.Click += (_, _) => ViewModel.PickVcpkgRootCommand.Execute(vcpkgRootCard);
vcpkgRootCard.Command = ViewModel.PickVcpkgRootCommand;
vcpkgRootCard.CommandParameter = vcpkgRootCard;
return vcpkgRootCard;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public struct OverridenInstallationOptions
public bool? RunAsAdministrator;
public bool PowerShell_DoNotSetScopeParameter = false;
public bool? WinGet_SpecifyVersion = null;
public bool Pip_BreakSystemPackages = false;

public OverridenInstallationOptions(string? scope = null, bool? runAsAdministrator = null)
{
Expand All @@ -15,6 +16,6 @@ public OverridenInstallationOptions(string? scope = null, bool? runAsAdministrat

public override string ToString()
{
return $"<Scope={Scope};RunAsAdministrator={RunAsAdministrator};WG_SpecifyVersion={WinGet_SpecifyVersion};PS_NoScope={PowerShell_DoNotSetScopeParameter}>";
return $"<Scope={Scope};RunAsAdministrator={RunAsAdministrator};WG_SpecifyVersion={WinGet_SpecifyVersion};PS_NoScope={PowerShell_DoNotSetScopeParameter};Pip_BreakSystemPackages={Pip_BreakSystemPackages}>";
}
}
48 changes: 40 additions & 8 deletions src/UniGetUI.PackageEngine.Managers.Cargo/Cargo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,16 @@ namespace UniGetUI.PackageEngine.Managers.CargoManager;

public partial class Cargo : PackageManager
{
[GeneratedRegex(@"(\w+)\s=\s""(\d+\.\d+\.\d+)""\s*#\s(.*)")]
[GeneratedRegex(@"([\w-]+)\s=\s""(\d+\.\d+\.\d+)""\s*#\s(.*)")]
private static partial Regex SearchLineRegex();

[GeneratedRegex(@"(.+)v(\d+\.\d+\.\d+)\s*v(\d+\.\d+\.\d+)\s*(Yes|No)")]
private static partial Regex UpdateLineRegex();

// Matches "ripgrep v15.1.0:" lines from `cargo install --list`
[GeneratedRegex(@"^([\w-]+)\s+v(\d+\.\d+\.\d+):")]
private static partial Regex InstallListLineRegex();

public Cargo()
{
string cargoCommand = OperatingSystem.IsWindows() ? "cargo.exe" : "cargo";
Expand Down Expand Up @@ -126,19 +130,19 @@ protected override IReadOnlyList<Package> FindPackages_UnSafe(string query)
package.VersionString
);
if (versionInfo.bin_names?.Length > 0)
{
BinPackages.Add(package);
}
}
catch (Exception ex)
{
logger.AddToStdErr($"{ex.Message}");
// On API failure, include the package rather than silently drop it
logger.AddToStdErr($"bin_names check failed for {package.Id}: {ex.Message}");
BinPackages.Add(package);
}

if (i + 1 == Packages.Count)
break;
// Crates.io api requests that we send no more than one request per second
Task.Delay(Math.Max(0, 1000 - (int)((DateTime.Now - startTime).TotalMilliseconds)))
// Crates.io requires no more than one request per second
Task.Delay(Math.Max(0, 1000 - (int)(DateTime.Now - startTime).TotalMilliseconds))
.GetAwaiter()
.GetResult();
}
Expand All @@ -158,6 +162,9 @@ protected override IReadOnlyList<Package> GetInstalledPackages_UnSafe()
return GetPackages(LoggableTaskType.ListInstalledPackages);
}

public readonly bool HasBinstall =
CoreTools.Which(OperatingSystem.IsWindows() ? "cargo-binstall.exe" : "cargo-binstall").Item1;

public override IReadOnlyList<string> FindCandidateExecutableFiles() =>
CoreTools.WhichMultiple(OperatingSystem.IsWindows() ? "cargo.exe" : "cargo");

Expand All @@ -183,6 +190,9 @@ protected override void _loadManagerVersion(out string version)
Logger.Error("cargo version error: " + error);
}

public void InvalidateInstalledCache() =>
TaskRecycler<List<Match>>.RemoveFromCache(GetInstalledCommandOutput);

private IReadOnlyList<Package> GetPackages(LoggableTaskType taskType)
{
List<Package> Packages = [];
Expand Down Expand Up @@ -214,13 +224,35 @@ private List<Match> GetInstalledCommandOutput()
logger.AddToStdOut(line);
var match = UpdateLineRegex().Match(line);
if (match.Success)
{
output.Add(match);
}
}
logger.AddToStdErr(p.StandardError.ReadToEnd());
p.WaitForExit();
logger.Close(p.ExitCode);

if (output.Count > 0)
return output;

// Fallback: cargo-update is not installed, use the built-in `cargo install --list`.
// No latest-version info is available, so updates won't be detected, but the installed
// packages list will be populated correctly.
using Process fallback = GetProcess(Status.ExecutablePath, "install --list");
IProcessTaskLogger fallbackLogger = TaskLogger.CreateNew(LoggableTaskType.OtherTask, fallback);
fallbackLogger.AddToStdOut("Falling back to `cargo install --list` (cargo-update not available)");
fallback.Start();
while ((line = fallback.StandardOutput.ReadLine()) is not null)
{
fallbackLogger.AddToStdOut(line);
var m = InstallListLineRegex().Match(line);
if (!m.Success) continue;
// Synthesise a match compatible with UpdateLineRegex (same installed and latest version → no update)
var fake = UpdateLineRegex().Match($"{m.Groups[1].Value} v{m.Groups[2].Value} v{m.Groups[2].Value} No");
if (fake.Success)
output.Add(fake);
}
fallbackLogger.AddToStdErr(fallback.StandardError.ReadToEnd());
fallback.WaitForExit();
fallbackLogger.Close(fallback.ExitCode);
return output;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ OperationType operation
{
var installVersion = options.Version == string.Empty ? package.VersionString : options.Version;

bool hasBinstall = ((Cargo)Manager).HasBinstall;

List<string> parameters;
switch (operation)
{
case OperationType.Install:
parameters = [Manager.Properties.InstallVerb, "--version", installVersion, package.Id];
if (hasBinstall)
parameters = [Manager.Properties.InstallVerb, "--version", installVersion, package.Id];
else
parameters = ["install", package.Id, "--version", installVersion];
break;

case OperationType.Update:
parameters = [Manager.Properties.UpdateVerb, package.Id];
if (hasBinstall)
parameters = [Manager.Properties.UpdateVerb, package.Id];
else
parameters = ["install", package.Id, "--force"];
break;

case OperationType.Uninstall:
Expand All @@ -36,13 +44,16 @@ OperationType operation

if (operation is OperationType.Install or OperationType.Update)
{
parameters.Add("--no-confirm");
if (hasBinstall)
{
parameters.Add("--no-confirm");

if (options.SkipHashCheck)
parameters.Add("--skip-signatures");
if (options.SkipHashCheck)
parameters.Add("--skip-signatures");

if (options.CustomInstallLocation != "")
parameters.AddRange(["--install-path", options.CustomInstallLocation]);
if (options.CustomInstallLocation != "")
parameters.AddRange(["--install-path", options.CustomInstallLocation]);
}
}

parameters.AddRange(
Expand All @@ -64,6 +75,11 @@ protected override OperationVeredict _getOperationResult(
int returnCode
)
{
return returnCode == 0 ? OperationVeredict.Success : OperationVeredict.Failure;
if (returnCode == 0)
{
((Cargo)Manager).InvalidateInstalledCache();
return OperationVeredict.Success;
}
return OperationVeredict.Failure;
}
}
38 changes: 27 additions & 11 deletions src/UniGetUI.PackageEngine.Managers.Generic.NuGet/BaseNuGet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ namespace UniGetUI.PackageEngine.Managers.PowerShellManager
{
public abstract class BaseNuGet : PackageManager
{
/// <summary>
/// When true, searches use Packages()?$filter=substringof(query,Id) which searches by
/// package name only but returns reliable results (e.g. PSGallery's Search() endpoint
/// silently omits some packages). When false, the standard Search() endpoint is used
/// which supports full-text search across name, description, and tags.
/// </summary>
protected virtual bool UseSubstringSearch => false;
public static Dictionary<long, string> Manifests = new();

public sealed override void Initialize()
Expand Down Expand Up @@ -71,17 +78,26 @@ protected sealed override IReadOnlyList<Package> FindPackages_UnSafe(string quer
{
try
{
Uri? SearchUrl = new(
$"{source.Url}/Search()"
+ $"?$filter=IsLatestVersion"
+ $"&$orderby=Id&searchTerm='{HttpUtility.UrlEncode(query)}'"
+ $"&targetFramework=''"
+ $"&includePrerelease={(canPrerelease ? "true" : "false")}"
+ $"&$skip=0"
+ $"&$top=50"
+ $"&semVerLevel=2.0.0"
);
// Uri SearchUrl = new($"{source.Url}/Search()?$filter=IsLatestVersion&searchTerm=%27{HttpUtility.UrlEncode(query)}%27&targetFramework=%27%27&includePrerelease=false");
string versionFilter = canPrerelease ? "IsAbsoluteLatestVersion eq true" : "IsLatestVersion eq true";
string odataQuery = HttpUtility.UrlEncode(query.Replace("'", "''"));
Uri? SearchUrl = UseSubstringSearch
? new Uri(
$"{source.Url}/Packages()"
+ $"?$filter=substringof('{odataQuery}',Id) and {versionFilter}"
+ $"&$orderby=DownloadCount desc"
+ $"&$skip=0"
+ $"&$top=50"
)
: new Uri(
$"{source.Url}/Search()"
+ $"?$filter=IsLatestVersion"
+ $"&$orderby=Id&searchTerm='{odataQuery}'"
+ $"&targetFramework=''"
+ $"&includePrerelease={(canPrerelease ? "true" : "false")}"
+ $"&$skip=0"
+ $"&$top=50"
+ $"&semVerLevel=2.0.0"
);
logger.Log($"Begin package search with url={SearchUrl} on manager {Name}");
Dictionary<string, SearchResult> AlreadyProcessedPackages = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ package.OverridenOptions.Scope is null
parameters.Add("--user");
}

if (package.OverridenOptions.Pip_BreakSystemPackages)
parameters.Add("--break-system-packages");

parameters.Add(Pip.GetProxyArgument());

parameters.AddRange(
Expand Down Expand Up @@ -80,6 +83,12 @@ int returnCode

string output_string = string.Join("\n", processOutput);

if (output_string.Contains("externally-managed-environment") && !package.OverridenOptions.Pip_BreakSystemPackages)
{
package.OverridenOptions.Pip_BreakSystemPackages = true;
return OperationVeredict.AutoRetry;
}

if (output_string.Contains("--user") && package.OverridenOptions.Scope != PackageScope.User)
{
package.OverridenOptions.Scope = PackageScope.User;
Expand Down
Loading
Loading