Skip to content
Open
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
18 changes: 17 additions & 1 deletion internal/devbox/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ func (d *Devbox) Add(ctx context.Context, pkgsNames []string, opts devopt.AddOpt
// about not building on the current system, since user's can continue
// via --exclude-platform flag.
packageNameForConfig = pkg.Versioned()
} else if errors.Is(err, nix.ErrPackageNotFound) &&
versionedPkg.IsDevboxPackage &&
!strings.Contains(pkg.CanonicalName(), ".") {
// Heuristic: search indexes top-level nixpkgs packages, so falling
// back to nixpkgs (which requires a slow download) won't find it
// either. Nested attribute paths (e.g. stdenv.cc.cc.lib, openssl.dev,
// python3Packages.requests) are not all indexed, so those still fall
// back below.
return packageNotFoundError(pkg)
} else if !versionedPkg.IsDevboxPackage {
// This means it didn't validate and we don't want to fallback to legacy
// Just propagate the error.
Expand All @@ -146,7 +155,7 @@ func (d *Devbox) Add(ctx context.Context, pkgsNames []string, opts devopt.AddOpt
if err != nil {
// This means it looked like a devbox package or attribute path, but we
// could not find it in search or in the legacy nixpkgs path.
return usererr.New("Package %s not found", pkg.Raw)
return packageNotFoundError(pkg)
}
}

Expand All @@ -171,6 +180,13 @@ func (d *Devbox) Add(ctx context.Context, pkgsNames []string, opts devopt.AddOpt
return d.printPostAddMessage(ctx, pkgs, unchangedPackageNames, opts)
}

func packageNotFoundError(pkg *devpkg.Package) error {
return usererr.New(
"Package %q not found. To search for packages, use `devbox search %s`",
pkg.Raw, pkg.CanonicalName(),
)
}

func (d *Devbox) setPackageOptions(pkgs []string, opts devopt.AddOpts) error {
for _, pkg := range pkgs {
if err := d.cfg.PackageMutator().AddPlatforms(
Expand Down
5 changes: 4 additions & 1 deletion internal/lock/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,12 @@ func (f *File) FetchResolvedPackage(pkg string, refresh bool) (*Package, error)
}

packageVersion, err := searcher.Client().Resolve(name, version)
if err != nil {
if errors.Is(err, searcher.ErrNotFound) {
return nil, errors.Wrapf(nix.ErrPackageNotFound, "%s@%s", name, version)
}
if err != nil {
return nil, err
}

sysInfos, err := buildLockSystemInfos(packageVersion)
if err != nil {
Expand Down
43 changes: 43 additions & 0 deletions internal/lock/resolve_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2024 Jetify Inc. and contributors. All rights reserved.
// Use of this source code is governed by the license in the LICENSE file.

package lock

import (
"errors"
"net/http"
"net/http/httptest"
"testing"

"go.jetify.com/devbox/internal/envir"
"go.jetify.com/devbox/internal/nix"
)

func TestFetchResolvedPackageErrors(t *testing.T) {
for _, resolveV2 := range []string{"0", "1"} {
for _, test := range []struct {
status int
wantNotFound bool
}{
{http.StatusNotFound, true},
{http.StatusInternalServerError, false},
} {
t.Run("v2="+resolveV2+"/"+http.StatusText(test.status), func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(test.status)
}))
t.Cleanup(srv.Close)
t.Setenv(envir.DevboxSearchHost, srv.URL)
t.Setenv("DEVBOX_FEATURE_RESOLVE_V2", resolveV2)

_, err := (&File{}).FetchResolvedPackage("hello@latest", false)
if err == nil {
t.Fatal("got nil error, want an error")
}
if got := errors.Is(err, nix.ErrPackageNotFound); got != test.wantNotFound {
t.Errorf("errors.Is(err, nix.ErrPackageNotFound) = %v, want %v (err: %v)", got, test.wantNotFound, err)
}
})
}
}
}
20 changes: 20 additions & 0 deletions testscripts/add/add_not_found.test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Testscript for adding a package that doesn't exist.

exec devbox init

# A bare name that search doesn't know should fail fast without
# downloading nixpkgs.
! exec devbox add inotifywait
stderr 'Package "inotifywait" not found. To search for packages, use `devbox search inotifywait`'
! stderr 'Ensuring nixpkgs registry is downloaded'

# The search hint drops the version.
! exec devbox add hello@99999
stderr 'Package "hello@99999" not found. To search for packages, use `devbox search hello`'

json.superset devbox.json expected_devbox.json

-- expected_devbox.json --
{
"packages": []
}
Loading