internal/pkg: improve error resolution
All checks were successful
Test / Create distribution (push) Successful in 58s
Test / Sandbox (push) Successful in 2m35s
Test / Hakurei (push) Successful in 3m40s
Test / ShareFS (push) Successful in 3m54s
Test / Hpkg (push) Successful in 4m31s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 5m57s
Test / Flake checks (push) Successful in 1m33s

This was taking way too long for early failures.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2026-02-03 09:50:35 +09:00
parent 443911ada1
commit f982b13a59
2 changed files with 55 additions and 22 deletions

View File

@@ -1188,39 +1188,38 @@ func (e *CureError) Error() string { return e.Err.Error() }
// A DependencyCureError wraps errors returned while curing dependencies. // A DependencyCureError wraps errors returned while curing dependencies.
type DependencyCureError []*CureError type DependencyCureError []*CureError
// sort sorts underlying errors by their identifier. // unwrapM recursively expands underlying errors into a caller-supplied map.
func (e *DependencyCureError) sort() { func (e *DependencyCureError) unwrapM(me map[unique.Handle[ID]]*CureError) {
var identBuf [2]ID for _, err := range *e {
slices.SortFunc(*e, func(a, b *CureError) int { if _e, ok := err.Err.(*DependencyCureError); ok {
identBuf[0], identBuf[1] = a.Ident.Value(), b.Ident.Value() _e.unwrapM(me)
return slices.Compare(identBuf[0][:], identBuf[1][:]) continue
}) }
me[err.Ident] = err
}
} }
// unwrap recursively expands and deduplicates underlying errors. // unwrap recursively expands and deduplicates underlying errors.
func (e *DependencyCureError) unwrap() DependencyCureError { func (e *DependencyCureError) unwrap() DependencyCureError {
errs := make(DependencyCureError, 0, len(*e)) me := make(map[unique.Handle[ID]]*CureError)
for _, err := range *e { e.unwrapM(me)
if _e, ok := err.Err.(*DependencyCureError); ok { errs := slices.AppendSeq(
errs = append(errs, _e.unwrap()...)
continue
}
errs = append(errs, err)
}
me := make(map[unique.Handle[ID]]*CureError, len(errs))
for _, err := range errs {
me[err.Ident] = err
}
return slices.AppendSeq(
make(DependencyCureError, 0, len(me)), make(DependencyCureError, 0, len(me)),
maps.Values(me), maps.Values(me),
) )
var identBuf [2]ID
slices.SortFunc(errs, func(a, b *CureError) int {
identBuf[0], identBuf[1] = a.Ident.Value(), b.Ident.Value()
return slices.Compare(identBuf[0][:], identBuf[1][:])
})
return errs
} }
// Unwrap returns a deduplicated slice of underlying errors. // Unwrap returns a deduplicated slice of underlying errors.
func (e *DependencyCureError) Unwrap() []error { func (e *DependencyCureError) Unwrap() []error {
errs := e.unwrap() errs := e.unwrap()
errs.sort()
_errs := make([]error, len(errs)) _errs := make([]error, len(errs))
for i, err := range errs { for i, err := range errs {
_errs[i] = err _errs[i] = err
@@ -1231,7 +1230,6 @@ func (e *DependencyCureError) Unwrap() []error {
// Error returns a user-facing multiline error message. // Error returns a user-facing multiline error message.
func (e *DependencyCureError) Error() string { func (e *DependencyCureError) Error() string {
errs := e.unwrap() errs := e.unwrap()
errs.sort()
if len(errs) == 0 { if len(errs) == 0 {
return "invalid dependency cure outcome" return "invalid dependency cure outcome"
} }

View File

@@ -15,6 +15,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"strconv"
"syscall" "syscall"
"testing" "testing"
"unique" "unique"
@@ -1137,6 +1138,40 @@ func TestDependencyCureError(t *testing.T) {
} }
} }
// earlyFailureF is a [FloodArtifact] with a large dependency graph resulting in
// a large [DependencyCureError].
type earlyFailureF int
func (earlyFailureF) Kind() pkg.Kind { return pkg.KindExec }
func (earlyFailureF) Params(*pkg.IContext) {}
func (earlyFailureF) IsExclusive() bool { return false }
func (a earlyFailureF) Dependencies() []pkg.Artifact {
deps := make([]pkg.Artifact, a)
for i := range deps {
deps[i] = a - 1
}
return deps
}
func (a earlyFailureF) Cure(*pkg.FContext) error {
if a != 0 {
panic("unexpected cure on " + strconv.Itoa(int(a)))
}
return stub.UniqueError(0xcafe)
}
func TestDependencyCureErrorEarly(t *testing.T) {
checkWithCache(t, []cacheTestCase{
{"early", nil, func(t *testing.T, _ *check.Absolute, c *pkg.Cache) {
_, _, err := c.Cure(earlyFailureF(8))
if !errors.Is(err, stub.UniqueError(0xcafe)) {
t.Fatalf("Cure: error = %v", err)
}
}, pkg.MustDecode("E4vEZKhCcL2gPZ2Tt59FS3lDng-d_2SKa2i5G_RbDfwGn6EemptFaGLPUDiOa94C")},
})
}
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
t.Parallel() t.Parallel()