aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-02-03 09:50:35 +0900
committerOphestra <cat@gensokyo.uk>2026-02-03 10:01:44 +0900
commitf982b13a59a59e22d1ff3fdf791c1aa86b9420df (patch)
tree5d65ec444eba5b187fcce2979db98e929f2522c9
parent443911ada191fdd8848709824a03e228a72a86e0 (diff)
internal/pkg: improve error resolution
This was taking way too long for early failures. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/pkg/pkg.go38
-rw-r--r--internal/pkg/pkg_test.go35
2 files changed, 53 insertions, 20 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index 99772c8f..76bae916 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -1188,39 +1188,38 @@ func (e *CureError) Error() string { return e.Err.Error() }
// A DependencyCureError wraps errors returned while curing dependencies.
type DependencyCureError []*CureError
-// sort sorts underlying errors by their identifier.
-func (e *DependencyCureError) sort() {
- var identBuf [2]ID
- slices.SortFunc(*e, func(a, b *CureError) int {
- identBuf[0], identBuf[1] = a.Ident.Value(), b.Ident.Value()
- return slices.Compare(identBuf[0][:], identBuf[1][:])
- })
-}
-
-// unwrap recursively expands and deduplicates underlying errors.
-func (e *DependencyCureError) unwrap() DependencyCureError {
- errs := make(DependencyCureError, 0, len(*e))
+// unwrapM recursively expands underlying errors into a caller-supplied map.
+func (e *DependencyCureError) unwrapM(me map[unique.Handle[ID]]*CureError) {
for _, err := range *e {
if _e, ok := err.Err.(*DependencyCureError); ok {
- errs = append(errs, _e.unwrap()...)
+ _e.unwrapM(me)
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(
+}
+
+// unwrap recursively expands and deduplicates underlying errors.
+func (e *DependencyCureError) unwrap() DependencyCureError {
+ me := make(map[unique.Handle[ID]]*CureError)
+ e.unwrapM(me)
+ errs := slices.AppendSeq(
make(DependencyCureError, 0, len(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.
func (e *DependencyCureError) Unwrap() []error {
errs := e.unwrap()
- errs.sort()
_errs := make([]error, len(errs))
for i, err := range errs {
_errs[i] = err
@@ -1231,7 +1230,6 @@ func (e *DependencyCureError) Unwrap() []error {
// Error returns a user-facing multiline error message.
func (e *DependencyCureError) Error() string {
errs := e.unwrap()
- errs.sort()
if len(errs) == 0 {
return "invalid dependency cure outcome"
}
diff --git a/internal/pkg/pkg_test.go b/internal/pkg/pkg_test.go
index 719bf718..d03cd833 100644
--- a/internal/pkg/pkg_test.go
+++ b/internal/pkg/pkg_test.go
@@ -15,6 +15,7 @@ import (
"os"
"path/filepath"
"reflect"
+ "strconv"
"syscall"
"testing"
"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) {
t.Parallel()