github.com/google/osv-scalibr@v0.4.1/clients/resolution/override_client.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package resolution 16 17 import ( 18 "context" 19 "slices" 20 21 "deps.dev/util/resolve" 22 ) 23 24 // OverrideClient wraps a resolve.Client, allowing for custom packages & versions to be added 25 type OverrideClient struct { 26 resolve.Client 27 28 // Can't quite reuse resolve.LocalClient because it automatically creates dependencies 29 pkgVers map[resolve.PackageKey][]resolve.Version // versions of a package 30 verDeps map[resolve.VersionKey][]resolve.RequirementVersion // dependencies of a version 31 } 32 33 // NewOverrideClient makes a new OverrideClient. 34 func NewOverrideClient(c resolve.Client) *OverrideClient { 35 return &OverrideClient{ 36 Client: c, 37 pkgVers: make(map[resolve.PackageKey][]resolve.Version), 38 verDeps: make(map[resolve.VersionKey][]resolve.RequirementVersion), 39 } 40 } 41 42 // AddVersion adds the specified version and dependencies to the client. 43 func (c *OverrideClient) AddVersion(v resolve.Version, deps []resolve.RequirementVersion) { 44 // TODO: Inserting multiple co-dependent requirements may not work, depending on order 45 versions := c.pkgVers[v.PackageKey] 46 sem := v.Semver() 47 // Only add it to the versions if not already there (and keep versions sorted) 48 idx, ok := slices.BinarySearchFunc(versions, v, func(a, b resolve.Version) int { 49 return sem.Compare(a.Version, b.Version) 50 }) 51 if !ok { 52 versions = slices.Insert(versions, idx, v) 53 } 54 c.pkgVers[v.PackageKey] = versions 55 c.verDeps[v.VersionKey] = slices.Clone(deps) // overwrites dependencies if called multiple times with same version 56 } 57 58 // Version returns the version specified by the VersionKey. 59 func (c *OverrideClient) Version(ctx context.Context, vk resolve.VersionKey) (resolve.Version, error) { 60 for _, v := range c.pkgVers[vk.PackageKey] { 61 if v.VersionKey == vk { 62 return v, nil 63 } 64 } 65 66 return c.Client.Version(ctx, vk) 67 } 68 69 // Versions returns the versions of a package specified by the PackageKey. 70 func (c *OverrideClient) Versions(ctx context.Context, pk resolve.PackageKey) ([]resolve.Version, error) { 71 if vers, ok := c.pkgVers[pk]; ok { 72 return vers, nil 73 } 74 75 return c.Client.Versions(ctx, pk) 76 } 77 78 // Requirements returns the requirement versions of the version specified by the VersionKey. 79 func (c *OverrideClient) Requirements(ctx context.Context, vk resolve.VersionKey) ([]resolve.RequirementVersion, error) { 80 if deps, ok := c.verDeps[vk]; ok { 81 return deps, nil 82 } 83 84 return c.Client.Requirements(ctx, vk) 85 } 86 87 // MatchingVersions returns the versions matching the requirement specified by the VersionKey. 88 func (c *OverrideClient) MatchingVersions(ctx context.Context, vk resolve.VersionKey) ([]resolve.Version, error) { 89 if vs, ok := c.pkgVers[vk.PackageKey]; ok { 90 return resolve.MatchRequirement(vk, vs), nil 91 } 92 93 return c.Client.MatchingVersions(ctx, vk) 94 }