diff --git a/.gitignore b/.gitignore index 94851d6..c2cc6a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ src/cmd/apt_query/apt_query* +apt_query_test* *.log \ No newline at end of file diff --git a/apt_query-arm64 b/apt_query-arm64 index b0bfb8f..647417b 100755 Binary files a/apt_query-arm64 and b/apt_query-arm64 differ diff --git a/apt_query-x86 b/apt_query-x86 index 70ec608..d56e820 100755 Binary files a/apt_query-x86 and b/apt_query-x86 differ diff --git a/src/cmd/apt_query/main_test.go b/src/cmd/apt_query/main_test.go index 49e040d..41a55be 100644 --- a/src/cmd/apt_query/main_test.go +++ b/src/cmd/apt_query/main_test.go @@ -68,3 +68,9 @@ func TestNormalizedList_VirtualPackagesExists_StdoutsConcretePackage(t *testing. result := cmdtesting.New(t, createReplayLogs).Run("normalized-list", "libvips") result.ExpectSuccessfulOut("libvips42=8.9.1-2") } + +func TestNormalizedList_VirtualPackageWithNoProviders_StderrsErrorMessage(t *testing.T) { + var result = cmdtesting.New(t, createReplayLogs).Run("normalized-list", "python") + result.ExpectError(`Encountered error resolving some or all package names, see combined std[out,err] below. +virtual package 'python' has no concrete package providers available`) +} diff --git a/src/cmd/apt_query/testlogs/testnormalizedlist_virtualpackagewithnoproviders_stderrserrormessage.log b/src/cmd/apt_query/testlogs/testnormalizedlist_virtualpackagewithnoproviders_stderrserrormessage.log new file mode 100644 index 0000000..2329244 --- /dev/null +++ b/src/cmd/apt_query/testlogs/testnormalizedlist_virtualpackagewithnoproviders_stderrserrormessage.log @@ -0,0 +1,17 @@ +2025/10/04 06:59:56 Debug log created at /home/runner/work/cache-apt-pkgs-action/cache-apt-pkgs-action/src/cmd/apt_query/apt_query.log +2025/10/04 07:00:00 EXECUTION-OBJ-START +{ + "Cmd": "apt-cache --quiet=0 --no-all-versions show python", + "CombinedOut": "N: Can't select candidate version from package python as it has no candidate\nN: Can't select versions from package 'python' as it is purely virtual\nN: No packages found\n", + "ExitCode": 0 +} +EXECUTION-OBJ-END +2025/10/04 07:00:00 EXECUTION-OBJ-START +{ + "Cmd": "bash -c apt-cache showpkg python | grep -A 1 \"Reverse Provides\" | tail -1", + "CombinedOut": "Reverse Provides: \n", + "ExitCode": 0 +} +EXECUTION-OBJ-END +2025/10/04 07:00:00 Encountered error resolving some or all package names, see combined std[out,err] below. +virtual package 'python' has no concrete package providers available diff --git a/src/internal/common/apt.go b/src/internal/common/apt.go index b497a66..926fc09 100644 --- a/src/internal/common/apt.go +++ b/src/internal/common/apt.go @@ -31,7 +31,13 @@ func isErrLine(line string) bool { return strings.HasPrefix(line, "E: ") || strings.HasPrefix(line, "N: ") } +// isVirtualPackage checks if a string indicates a purely virtual package message. +func isVirtualPackage(message string) bool { + return strings.Contains(message, "as it is purely virtual") +} + // Resolves virtual packages names to their concrete one. +// Returns the first available concrete package provider, or an error if none exist. func getNonVirtualPackage(executor exec.Executor, name string) (pkg *AptPackage, err error) { execution := executor.Exec("bash", "-c", fmt.Sprintf("apt-cache showpkg %s | grep -A 1 \"Reverse Provides\" | tail -1", name)) err = execution.Error() @@ -42,10 +48,19 @@ func getNonVirtualPackage(executor exec.Executor, name string) (pkg *AptPackage, if isErrLine(execution.CombinedOut) { return pkg, execution.Error() } + + // Check if the output is just "Reverse Provides:" with no actual package info + trimmedOutput := strings.TrimSpace(execution.CombinedOut) + if trimmedOutput == "Reverse Provides:" { + return pkg, fmt.Errorf("virtual package '%s' has no concrete package providers available", name) + } + splitLine := GetSplitLine(execution.CombinedOut, " ", 3) if len(splitLine.Words) < 2 { return pkg, fmt.Errorf("unable to parse space delimited line's package name and version from apt-cache showpkg output below:\n%s", execution.CombinedOut) } + + // Successfully found a concrete package provider return &AptPackage{Name: splitLine.Words[0], Version: splitLine.Words[1]}, nil } @@ -67,7 +82,7 @@ func getPackage(executor exec.Executor, paragraph string) (pkg *AptPackage, err case "N": // e.g. Can't select versions from package 'libvips' as it is purely virtual - if strings.Contains(splitLine.Words[1], "as it is purely virtual") { + if isVirtualPackage(splitLine.Words[1]) { return getNonVirtualPackage(executor, GetSplitLine(splitLine.Words[1], "'", 4).Words[2]) } if strings.HasPrefix(splitLine.Words[1], "Unable to locate package") && !ArrContainsString(errMsgs, splitLine.Line) { @@ -112,10 +127,6 @@ func GetAptPackages(executor exec.Executor, names []string) (AptPackages, error) } } - if len(errMsgs) > 0 { - errMsgs = append(errMsgs, strings.Join(errMsgs, "\n")) - } - sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].Name < pkgs[j].Name })