Skip to content

Commit d4e3231

Browse files
committed
parrrrrralllllllllllllellllllllllll
1 parent d062d40 commit d4e3231

33 files changed

Lines changed: 338 additions & 209 deletions

go/osv/ecosystem/bioconductor.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import (
2222

2323
type bioconductorEcosystem struct {
2424
semverLikeEcosystem
25+
26+
p *Provider
2527
}
2628

2729
var _ Ecosystem = bioconductorEcosystem{}
@@ -56,7 +58,7 @@ func (e bioconductorEcosystem) getVersions(pkg string) ([]string, error) {
5658
var data struct {
5759
Version string `json:"version"`
5860
}
59-
if err := fetchJSON(apiPackageURLPositBioconductor(pkg, biocVersion), &data); err != nil {
61+
if err := e.p.fetchJSON(apiPackageURLPositBioconductor(pkg, biocVersion), &data); err != nil {
6062
if errors.Is(err, ErrPackageNotFound) {
6163
continue
6264
}
@@ -81,7 +83,7 @@ func (e bioconductorEcosystem) getBiocVersions() ([]string, error) {
8183
BiocVersion string `json:"bioc_version"`
8284
} `json:"bioc_versions"`
8385
}
84-
if err := fetchJSON(apiBiocVersionsURL, &data); err != nil {
86+
if err := e.p.fetchJSON(apiBiocVersionsURL, &data); err != nil {
8587
return nil, fmt.Errorf("failed to get Bioconductor versions: %w", err)
8688
}
8789
versions := make([]string, 0, len(data.BiocVersions))

go/osv/ecosystem/bioconductor_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import (
1111

1212
func TestBioconductor_GetBiocVersions(t *testing.T) {
1313
t.SkipNow()
14-
setupHTTPClientForTest(t)
15-
versions, err := bioconductorEcosystem{}.getBiocVersions()
14+
p := getTestProvider(t)
15+
versions, err := bioconductorEcosystem{p: p}.getBiocVersions()
1616
if err != nil {
1717
t.Errorf("getBiocVersions() error = %v", err)
1818
return
@@ -29,8 +29,8 @@ func TestBioconductor_GetBiocVersions(t *testing.T) {
2929

3030
func TestBioconductor_GetVersions(t *testing.T) {
3131
t.SkipNow()
32-
setupHTTPClientForTest(t)
33-
versions, err := bioconductorEcosystem{}.getVersions("a4") // TODO(michaelkedar): getVersions -> GetVersions
32+
p := getTestProvider(t)
33+
versions, err := bioconductorEcosystem{p: p}.getVersions("a4") // TODO(michaelkedar): getVersions -> GetVersions
3434
if err != nil {
3535
t.Errorf("GetVersions() error = %v", err)
3636
return
@@ -47,8 +47,8 @@ func TestBioconductor_GetVersions(t *testing.T) {
4747

4848
func TestBioconductor_GetVersionsNotFound(t *testing.T) {
4949
t.SkipNow()
50-
setupHTTPClientForTest(t)
51-
_, err := bioconductorEcosystem{}.getVersions("doesnotexist123456") // TODO(michaelkedar): getVersions -> GetVersions
50+
p := getTestProvider(t)
51+
_, err := bioconductorEcosystem{p: p}.getVersions("doesnotexist123456") // TODO(michaelkedar): getVersions -> GetVersions
5252
if !errors.Is(err, ErrPackageNotFound) {
5353
t.Errorf("GetVersions() error = %v, want %v", err, ErrPackageNotFound)
5454
}

go/osv/ecosystem/cran.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import (
2121
"github.com/google/osv-scalibr/semantic"
2222
)
2323

24-
type cranEcosystem struct{}
24+
type cranEcosystem struct {
25+
p *Provider
26+
}
2527

2628
var _ Enumerable = cranEcosystem{}
2729

@@ -57,7 +59,7 @@ func (e cranEcosystem) GetVersions(pkg string) ([]string, error) {
5759
Version string `json:"version"`
5860
} `json:"archived"`
5961
}
60-
if err := fetchJSON(cranAPIURL(pkg), &data); err != nil {
62+
if err := e.p.fetchJSON(cranAPIURL(pkg), &data); err != nil {
6163
return nil, fmt.Errorf("failed to get CRAN versions for %s: %w", pkg, err)
6264
}
6365
var versions []string

go/osv/ecosystem/cran_test.go

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ import (
66
)
77

88
func TestCRAN_GetVersions(t *testing.T) {
9-
setupHTTPClientForTest(t)
10-
ecosystem := cranEcosystem{}
9+
t.Parallel()
10+
p := getTestProvider(t)
11+
e, ok := p.Get("CRAN")
12+
if !ok {
13+
t.Fatalf("Failed to retrieve CRAN ecosystem")
14+
}
15+
ecosystem := e.(Enumerable)
1116

1217
t.Run("readxl", func(t *testing.T) {
1318
versions, err := ecosystem.GetVersions("readxl")
@@ -30,8 +35,13 @@ func TestCRAN_GetVersions(t *testing.T) {
3035
}
3136

3237
func TestCRAN_GetVersions_NotFound(t *testing.T) {
33-
setupHTTPClientForTest(t)
34-
ecosystem := cranEcosystem{}
38+
t.Parallel()
39+
p := getTestProvider(t)
40+
e, ok := p.Get("CRAN")
41+
if !ok {
42+
t.Fatalf("Failed to retrieve CRAN ecosystem")
43+
}
44+
ecosystem := e.(Enumerable)
3545
_, err := ecosystem.GetVersions("doesnotexist123456")
3646
if !errors.Is(err, ErrPackageNotFound) {
3747
t.Errorf("expected ErrPackageNotFound, got %v", err)

go/osv/ecosystem/debian.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,22 @@ type debianEcosystem struct {
2727
dpkgEcosystem
2828

2929
release string
30+
p *Provider
3031
}
3132

3233
var _ Enumerable = debianEcosystem{}
3334

3435
const debianSnapshotURL = "https://snapshot.debian.org/mr/package/%s/"
3536
const debianFirstPackageOutputURL = "https://storage.googleapis.com/debian-osv/first_package_output/%s.json"
3637

37-
func getDebianFirstPackageVersion(release, pkg string) (string, error) {
38-
if release == "" {
38+
func (e debianEcosystem) getDebianFirstPackageVersion(pkg string) (string, error) {
39+
if e.release == "" {
3940
return "0", nil
4041
}
41-
urlStr := fmt.Sprintf(debianFirstPackageOutputURL, url.PathEscape(release))
42+
urlStr := fmt.Sprintf(debianFirstPackageOutputURL, url.PathEscape(e.release))
4243
var data map[string]string
43-
if err := fetchJSON(urlStr, &data); err != nil {
44-
return "0", fmt.Errorf("failed to load release cache %s: %w", release, err)
44+
if err := e.p.fetchJSON(urlStr, &data); err != nil {
45+
return "0", fmt.Errorf("failed to load release cache %s: %w", e.release, err)
4546
}
4647
if v, ok := data[pkg]; ok {
4748
return v, nil
@@ -59,7 +60,7 @@ func (e debianEcosystem) GetVersions(pkg string) ([]string, error) {
5960
} `json:"result"`
6061
}
6162

62-
if err := fetchJSON(urlStr, &data); err != nil {
63+
if err := e.p.fetchJSON(urlStr, &data); err != nil {
6364
return nil, fmt.Errorf("failed to get Debian versions for %s: %w", pkg, err)
6465
}
6566

@@ -93,7 +94,7 @@ func (e debianEcosystem) GetVersions(pkg string) ([]string, error) {
9394
return nil, err
9495
}
9596

96-
firstVersion, err := getDebianFirstPackageVersion(e.release, pkg)
97+
firstVersion, err := e.getDebianFirstPackageVersion(pkg)
9798
if err != nil {
9899
return nil, err
99100
}

go/osv/ecosystem/debian_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import (
55
)
66

77
func TestDebian_GetVersions(t *testing.T) {
8-
setupHTTPClientForTest(t)
9-
e, ok := Get("Debian:11")
8+
t.Parallel()
9+
p := getTestProvider(t)
10+
e, ok := p.Get("Debian:11")
1011
if !ok {
1112
t.Fatalf("Failed to retrieve Debian ecosystem")
1213
}
@@ -27,7 +28,10 @@ func TestDebian_GetVersions(t *testing.T) {
2728
checkNextVersion(t, versions, "7.74.0-1.3", "7.74.0-1.3+deb11u1")
2829
})
2930

30-
e9, _ := Get("Debian:9")
31+
e9, ok := p.Get("Debian:9")
32+
if !ok {
33+
t.Fatalf("Failed to retrieve Debian 9 ecosystem")
34+
}
3135
en9 := e9.(Enumerable)
3236

3337
t.Run("nginx", func(t *testing.T) {

go/osv/ecosystem/ecosystem.go

Lines changed: 15 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ package ecosystem
1717

1818
import (
1919
"errors"
20-
"net/http"
21-
"strings"
2220

2321
"github.com/google/osv-scalibr/semantic"
2422
"github.com/ossf/osv-schema/bindings/go/osvconstants"
@@ -28,77 +26,52 @@ var ErrCoarseNotSupported = errors.New("coarse version not supported")
2826
var ErrVersionEcosystemMismatch = errors.New("version ecosystem mismatch")
2927
var ErrPackageNotFound = errors.New("package not found")
3028

31-
// HTTPClient is the global HTTP client used by ecosystems for fetching
32-
// version information and other external data. It may be overridden for testing.
33-
var HTTPClient = http.DefaultClient
29+
type ecosystemFactory func(p *Provider, suffix string) Ecosystem
3430

35-
// Get returns an ecosystem for the given ecosystem name.
36-
// If the ecosystem is not found, it returns nil, false.
37-
//
38-
// The ecosystem name can optionally include a version suffix (e.g. "Debian:10").
39-
func Get(ecosystem string) (Ecosystem, bool) {
40-
name, suffix, _ := strings.Cut(ecosystem, ":")
41-
f, ok := ecosystems[osvconstants.Ecosystem(name)]
42-
if !ok {
43-
return nil, false
44-
}
45-
// Wrap the ecosystem to handle "0" versions.
46-
e := f(suffix)
47-
if enum, ok := e.(Enumerable); ok {
48-
return &enumerableWrapper{Enumerable: enum}, true
49-
}
50-
51-
return &ecosystemWrapper{Ecosystem: e}, true
52-
}
53-
54-
type ecosystemFactory func(suffix string) Ecosystem
55-
56-
// statelessFactory returns a factory for the given ecosystem type that ignores the suffix
57-
// and returns the zero value of E.
58-
func statelessFactory[E Ecosystem](_ string) Ecosystem {
31+
func statelessFactory[E Ecosystem](_ *Provider, _ string) Ecosystem {
5932
var e E
6033
return e
6134
}
6235

6336
// debianFactory returns a factory that injects the release suffix.
64-
func debianFactory(suffix string) Ecosystem {
65-
return debianEcosystem{release: suffix}
37+
func debianFactory(p *Provider, suffix string) Ecosystem {
38+
return debianEcosystem{release: suffix, p: p}
6639
}
6740

6841
var ecosystems = map[osvconstants.Ecosystem]ecosystemFactory{
6942
osvconstants.EcosystemAlmaLinux: statelessFactory[rpmEcosystem],
7043
osvconstants.EcosystemAlpaquita: statelessFactory[apkEcosystem],
7144
osvconstants.EcosystemAlpine: statelessFactory[apkEcosystem],
7245
osvconstants.EcosystemBellSoftHardenedContainers: statelessFactory[apkEcosystem],
73-
osvconstants.EcosystemBioconductor: statelessFactory[bioconductorEcosystem],
46+
osvconstants.EcosystemBioconductor: func(p *Provider, _ string) Ecosystem { return bioconductorEcosystem{p: p} },
7447
osvconstants.EcosystemBitnami: statelessFactory[semverEcosystem],
7548
osvconstants.EcosystemChainguard: statelessFactory[apkEcosystem],
7649
osvconstants.EcosystemCleanStart: statelessFactory[apkEcosystem],
77-
osvconstants.EcosystemCRAN: statelessFactory[cranEcosystem],
50+
osvconstants.EcosystemCRAN: func(p *Provider, _ string) Ecosystem { return cranEcosystem{p: p} },
7851
osvconstants.EcosystemCratesIO: statelessFactory[semverEcosystem],
7952
osvconstants.EcosystemDebian: debianFactory,
8053
osvconstants.EcosystemDockerHardenedImages: statelessFactory[semverEcosystem],
8154
osvconstants.EcosystemEcho: statelessFactory[dpkgEcosystem],
82-
osvconstants.EcosystemGHC: statelessFactory[ghcEcosystem],
55+
osvconstants.EcosystemGHC: func(p *Provider, _ string) Ecosystem { return ghcEcosystem{p: p} },
8356
osvconstants.EcosystemGo: statelessFactory[semverEcosystem],
84-
osvconstants.EcosystemHackage: statelessFactory[hackageEcosystem],
85-
osvconstants.EcosystemHex: statelessFactory[hexEcosystem],
57+
osvconstants.EcosystemHackage: func(p *Provider, _ string) Ecosystem { return hackageEcosystem{p: p} },
58+
osvconstants.EcosystemHex: func(p *Provider, _ string) Ecosystem { return hexEcosystem{p: p} },
8659
osvconstants.EcosystemJulia: statelessFactory[semverEcosystem],
8760
osvconstants.EcosystemMageia: statelessFactory[rpmEcosystem],
88-
osvconstants.EcosystemMaven: statelessFactory[mavenEcosystem],
61+
osvconstants.EcosystemMaven: func(p *Provider, _ string) Ecosystem { return mavenEcosystem{p: p} },
8962
osvconstants.EcosystemMinimOS: statelessFactory[apkEcosystem],
9063
osvconstants.EcosystemNPM: statelessFactory[semverEcosystem],
91-
osvconstants.EcosystemNuGet: statelessFactory[nugetEcosystem],
64+
osvconstants.EcosystemNuGet: func(p *Provider, _ string) Ecosystem { return nugetEcosystem{p: p} },
9265
osvconstants.EcosystemOpam: statelessFactory[opamEcosystem],
9366
osvconstants.EcosystemOpenEuler: statelessFactory[rpmEcosystem],
9467
osvconstants.EcosystemOpenSUSE: statelessFactory[rpmEcosystem],
95-
osvconstants.EcosystemPackagist: statelessFactory[packagistEcosystem],
96-
osvconstants.EcosystemPub: statelessFactory[pubEcosystem],
97-
osvconstants.EcosystemPyPI: statelessFactory[pyPIEcosystem],
68+
osvconstants.EcosystemPackagist: func(p *Provider, _ string) Ecosystem { return packagistEcosystem{p: p} },
69+
osvconstants.EcosystemPub: func(p *Provider, _ string) Ecosystem { return pubEcosystem{p: p} },
70+
osvconstants.EcosystemPyPI: func(p *Provider, _ string) Ecosystem { return pypiEcosystem{p: p} },
9871
osvconstants.EcosystemRedHat: statelessFactory[rpmEcosystem],
9972
osvconstants.EcosystemRockyLinux: statelessFactory[rpmEcosystem],
10073
osvconstants.EcosystemRoot: rootEcosystemFactory,
101-
osvconstants.EcosystemRubyGems: statelessFactory[rubyGemsEcosystem],
74+
osvconstants.EcosystemRubyGems: func(p *Provider, _ string) Ecosystem { return rubyGemsEcosystem{p: p} },
10275
osvconstants.EcosystemSUSE: statelessFactory[rpmEcosystem],
10376
osvconstants.EcosystemSwiftURL: statelessFactory[semverEcosystem],
10477
osvconstants.EcosystemUbuntu: statelessFactory[dpkgEcosystem],

go/osv/ecosystem/ghc.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424

2525
type ghcEcosystem struct {
2626
semverLikeEcosystem
27+
28+
p *Provider
2729
}
2830

2931
var _ Enumerable = ghcEcosystem{}
@@ -60,7 +62,7 @@ func (e ghcEcosystem) GetVersions(_ string) ([]string, error) {
6062
return nil, err
6163
}
6264

63-
resp, err := HTTPClient.Do(req)
65+
resp, err := e.p.Client.Do(req)
6466
if err != nil {
6567
return nil, err
6668
}

go/osv/ecosystem/ghc_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@ import (
55
)
66

77
func TestGHC_GetVersions(t *testing.T) {
8-
setupHTTPClientForTest(t)
9-
e := ghcEcosystem{}
8+
t.Parallel()
9+
p := getTestProvider(t)
10+
ecosystem := ghcEcosystem{p: p}
1011

1112
t.Run("ghc", func(t *testing.T) {
12-
versions, err := e.GetVersions("ghc")
13+
versions, err := ecosystem.GetVersions("ghc")
1314
if err != nil {
1415
t.Fatalf("GetVersions() err = %v", err)
1516
}

go/osv/ecosystem/hackage.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import (
2121
"github.com/google/osv-scalibr/semantic"
2222
)
2323

24-
type hackageEcosystem struct{}
24+
type hackageEcosystem struct {
25+
p *Provider
26+
}
2527

2628
var _ Enumerable = hackageEcosystem{}
2729

@@ -48,7 +50,7 @@ func hackageAPIURL(pkg string) string {
4850

4951
func (e hackageEcosystem) GetVersions(pkg string) ([]string, error) {
5052
var data map[string]any
51-
if err := fetchJSON(hackageAPIURL(pkg), &data); err != nil {
53+
if err := e.p.fetchJSON(hackageAPIURL(pkg), &data); err != nil {
5254
return nil, fmt.Errorf("failed to get Hackage versions for %s: %w", pkg, err)
5355
}
5456

0 commit comments

Comments
 (0)