|
| 1 | +// Copyright 2023 Jetpack Technologies Inc and contributors. All rights reserved. |
| 2 | +// Use of this source code is governed by the license in the LICENSE file. |
| 3 | + |
| 4 | +package lock |
| 5 | + |
| 6 | +import ( |
| 7 | + "fmt" |
| 8 | + "time" |
| 9 | + |
| 10 | + "github.com/pkg/errors" |
| 11 | + "go.jetpack.io/devbox/internal/boxcli/featureflag" |
| 12 | + "go.jetpack.io/devbox/internal/boxcli/usererr" |
| 13 | + "go.jetpack.io/devbox/internal/nix" |
| 14 | + "go.jetpack.io/devbox/internal/searcher" |
| 15 | + "golang.org/x/exp/maps" |
| 16 | +) |
| 17 | + |
| 18 | +// FetchResolvedPackage fetches a resolution but does not write it to the lock |
| 19 | +// struct. This allows testing new versions of packages without writing to the |
| 20 | +// lock. This is useful to avoid changing nixpkgs commit hashes when version has |
| 21 | +// not changed. This can happen when doing `devbox update` and search has |
| 22 | +// a newer hash than the lock file but same version. In that case we don't want |
| 23 | +// to update because it would be slow and wasteful. |
| 24 | +func (l *File) FetchResolvedPackage(pkg string) (*Package, error) { |
| 25 | + name, version, _ := searcher.ParseVersionedPackage(pkg) |
| 26 | + if version == "" { |
| 27 | + return nil, usererr.New("No version specified for %q.", name) |
| 28 | + } |
| 29 | + |
| 30 | + packageVersion, err := searcher.Client().Resolve(name, version) |
| 31 | + if err != nil { |
| 32 | + return nil, errors.Wrapf(nix.ErrPackageNotFound, "%s@%s", name, version) |
| 33 | + } |
| 34 | + |
| 35 | + sysInfos := map[string]*SystemInfo{} |
| 36 | + if featureflag.RemoveNixpkgs.Enabled() { |
| 37 | + sysInfos = buildLockSystemInfos(packageVersion) |
| 38 | + } |
| 39 | + packageInfo, err := selectForSystem(packageVersion) |
| 40 | + if err != nil { |
| 41 | + return nil, err |
| 42 | + } |
| 43 | + |
| 44 | + if len(packageInfo.AttrPaths) == 0 { |
| 45 | + return nil, fmt.Errorf("no attr paths found for package %q", name) |
| 46 | + } |
| 47 | + |
| 48 | + return &Package{ |
| 49 | + LastModified: time.Unix(int64(packageInfo.LastUpdated), 0).UTC(). |
| 50 | + Format(time.RFC3339), |
| 51 | + Resolved: fmt.Sprintf( |
| 52 | + "github:NixOS/nixpkgs/%s#%s", |
| 53 | + packageInfo.CommitHash, |
| 54 | + packageInfo.AttrPaths[0], |
| 55 | + ), |
| 56 | + Version: packageInfo.Version, |
| 57 | + Systems: sysInfos, |
| 58 | + }, nil |
| 59 | +} |
| 60 | + |
| 61 | +func selectForSystem(pkg *searcher.PackageVersion) (searcher.PackageInfo, error) { |
| 62 | + currentSystem, err := nix.System() |
| 63 | + if err != nil { |
| 64 | + return searcher.PackageInfo{}, err |
| 65 | + } |
| 66 | + if pi, ok := pkg.Systems[currentSystem]; ok { |
| 67 | + return pi, nil |
| 68 | + } |
| 69 | + if pi, ok := pkg.Systems["x86_64-linux"]; ok { |
| 70 | + return pi, nil |
| 71 | + } |
| 72 | + if len(pkg.Systems) == 0 { |
| 73 | + return searcher.PackageInfo{}, |
| 74 | + fmt.Errorf("no systems found for package %q", pkg.Name) |
| 75 | + } |
| 76 | + return maps.Values(pkg.Systems)[0], nil |
| 77 | +} |
| 78 | + |
| 79 | +func buildLockSystemInfos(pkg *searcher.PackageVersion) map[string]*SystemInfo { |
| 80 | + sysInfos := map[string]*SystemInfo{} |
| 81 | + for sysName, sysInfo := range pkg.Systems { |
| 82 | + sysInfos[sysName] = &SystemInfo{ |
| 83 | + System: sysName, |
| 84 | + FromHash: sysInfo.StoreHash, |
| 85 | + StoreName: sysInfo.StoreName, |
| 86 | + StoreVersion: sysInfo.StoreVersion, |
| 87 | + } |
| 88 | + } |
| 89 | + return sysInfos |
| 90 | +} |
0 commit comments