Skip to content

Commit bb360a3

Browse files
authored
Merge pull request #41 from git-pkgs/self-name
Add package Name and Version to ParseResult
2 parents 07b99c8 + 45da16f commit bb360a3

99 files changed

Lines changed: 1636 additions & 1244 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func main() {
2828

2929
fmt.Printf("Ecosystem: %s\n", result.Ecosystem)
3030
fmt.Printf("Kind: %s\n", result.Kind)
31+
fmt.Printf("Package: %s %s\n", result.Name, result.Version)
3132
for _, dep := range result.Dependencies {
3233
fmt.Printf(" %s@%s (%s)\n", dep.Name, dep.Version, dep.Scope)
3334
}
@@ -181,10 +182,14 @@ When a dependency comes from a non-default registry, the PURL includes a `reposi
181182
type ParseResult struct {
182183
Ecosystem string // npm, gem, pypi, golang, cargo, etc.
183184
Kind Kind // manifest, lockfile, or supplement
185+
Name string // the package's own name, when the format declares one
186+
Version string // the package's own version, when declared
184187
Dependencies []Dependency
185188
}
186189
```
187190

191+
`Name` and `Version` are populated for manifest formats that declare their own package identity (Cargo.toml `[package]`, package.json `"name"`, go.mod `module`, `.gemspec`, and so on). They are empty for lockfiles and for dependency-only files like Gemfile or requirements.txt.
192+
188193
### Kind
189194

190195
```go

internal/alpine/alpine.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ var (
1818
apkVarRegex = regexp.MustCompile(`^(\w+)="([^"]*)"`)
1919
// Matches multi-line variable start: depends="
2020
apkVarStartRegex = regexp.MustCompile(`^(\w+)="([^"]*)$`)
21+
// Matches unquoted scalar assignments like: pkgname=curl
22+
apkScalarRegex = regexp.MustCompile(`^(\w+)=([^\s"]+)`)
2123
// Matches package with optional version: pkg>=1.0 or pkg
2224
apkDepRegex = regexp.MustCompile(`^([a-zA-Z0-9_][a-zA-Z0-9_+.-]*)(>=|<=|>|<|=)?(.*)$`)
2325
)
2426

25-
func (p *apkbuildParser) Parse(filename string, content []byte) ([]core.Dependency, error) {
27+
func (p *apkbuildParser) Parse(filename string, content []byte) (*core.Result, error) {
2628
vars := parseApkbuildVars(string(content))
2729

2830
var deps []core.Dependency
@@ -55,7 +57,7 @@ func (p *apkbuildParser) Parse(filename string, content []byte) ([]core.Dependen
5557
deps = append(deps, dep)
5658
}
5759

58-
return deps, nil
60+
return &core.Result{Name: vars["pkgname"], Version: vars["pkgver"], Dependencies: deps}, nil
5961
}
6062

6163
func parseApkbuildVars(content string) map[string]string {
@@ -97,6 +99,12 @@ func parseApkbuildVars(content string) map[string]string {
9799
if match := apkVarStartRegex.FindStringSubmatch(line); match != nil {
98100
currentVar = match[1]
99101
currentValue.WriteString(match[2])
102+
continue
103+
}
104+
105+
// Check for unquoted scalar (pkgname=foo, pkgver=1.0)
106+
if match := apkScalarRegex.FindStringSubmatch(line); match != nil {
107+
vars[match[1]] = match[2]
100108
}
101109
}
102110

internal/alpine/alpine_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ func TestAPKBUILD(t *testing.T) {
1414
}
1515

1616
parser := &apkbuildParser{}
17-
deps, err := parser.Parse("APKBUILD", content)
17+
res, err := parser.Parse("APKBUILD", content)
1818
if err != nil {
1919
t.Fatalf("Parse failed: %v", err)
2020
}
2121

22-
if len(deps) != 13 {
23-
t.Fatalf("expected 13 dependencies, got %d", len(deps))
22+
if len(res.Dependencies) != 13 {
23+
t.Fatalf("expected 13 dependencies, got %d", len(res.Dependencies))
2424
}
2525

2626
depMap := make(map[string]core.Dependency)
27-
for _, d := range deps {
27+
for _, d := range res.Dependencies {
2828
depMap[d.Name] = d
2929
}
3030

@@ -75,17 +75,17 @@ func TestAPKBUILDWithVersions(t *testing.T) {
7575
}
7676

7777
parser := &apkbuildParser{}
78-
deps, err := parser.Parse("APKBUILD", content)
78+
res, err := parser.Parse("APKBUILD", content)
7979
if err != nil {
8080
t.Fatalf("Parse failed: %v", err)
8181
}
8282

83-
if len(deps) != 9 {
84-
t.Fatalf("expected 9 dependencies, got %d", len(deps))
83+
if len(res.Dependencies) != 9 {
84+
t.Fatalf("expected 9 dependencies, got %d", len(res.Dependencies))
8585
}
8686

8787
depMap := make(map[string]core.Dependency)
88-
for _, d := range deps {
88+
for _, d := range res.Dependencies {
8989
depMap[d.Name] = d
9090
}
9191

internal/arch/arch.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ type pkgbuildParser struct{}
1616
var (
1717
// Matches array assignments: depends=('foo' 'bar') or depends=("foo" "bar")
1818
pkgbuildArrayRegex = regexp.MustCompile(`^(\w+)=\(([^)]*)\)`)
19+
// Matches scalar assignments: pkgname=foo or pkgver=1.0
20+
pkgbuildScalarRegex = regexp.MustCompile(`^(\w+)=([^\s('"]+)`)
1921
// Matches package with optional version constraint: pkg>=1.0 or pkg
2022
pkgbuildDepRegex = regexp.MustCompile(`^([a-zA-Z0-9_][a-zA-Z0-9_+@.-]*)(>=|<=|>|<|=)?([^'"]*)$`)
2123
)
2224

23-
func (p *pkgbuildParser) Parse(filename string, content []byte) ([]core.Dependency, error) {
25+
func (p *pkgbuildParser) Parse(filename string, content []byte) (*core.Result, error) {
2426
vars := parsePkgbuildVars(string(content))
2527

2628
var deps []core.Dependency
@@ -53,7 +55,7 @@ func (p *pkgbuildParser) Parse(filename string, content []byte) ([]core.Dependen
5355
deps = append(deps, dep)
5456
}
5557

56-
return deps, nil
58+
return &core.Result{Name: vars["pkgname"], Version: vars["pkgver"], Dependencies: deps}, nil
5759
}
5860

5961
func parsePkgbuildVars(content string) map[string]string {
@@ -70,6 +72,11 @@ func parsePkgbuildVars(content string) map[string]string {
7072

7173
if match := pkgbuildArrayRegex.FindStringSubmatch(line); match != nil {
7274
vars[match[1]] = match[2]
75+
continue
76+
}
77+
78+
if match := pkgbuildScalarRegex.FindStringSubmatch(line); match != nil {
79+
vars[match[1]] = match[2]
7380
}
7481
}
7582

internal/arch/arch_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ func TestPKGBUILD(t *testing.T) {
1414
}
1515

1616
parser := &pkgbuildParser{}
17-
deps, err := parser.Parse("PKGBUILD", content)
17+
res, err := parser.Parse("PKGBUILD", content)
1818
if err != nil {
1919
t.Fatalf("Parse failed: %v", err)
2020
}
2121

22-
if len(deps) != 7 {
23-
t.Fatalf("expected 7 dependencies, got %d", len(deps))
22+
if len(res.Dependencies) != 7 {
23+
t.Fatalf("expected 7 dependencies, got %d", len(res.Dependencies))
2424
}
2525

2626
depMap := make(map[string]core.Dependency)
27-
for _, d := range deps {
27+
for _, d := range res.Dependencies {
2828
depMap[d.Name] = d
2929
}
3030

internal/asdf/asdf.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func init() {
1515
// toolVersionsParser parses .tool-versions files.
1616
type toolVersionsParser struct{}
1717

18-
func (p *toolVersionsParser) Parse(filename string, content []byte) ([]core.Dependency, error) {
18+
func (p *toolVersionsParser) Parse(filename string, content []byte) (*core.Result, error) {
1919
var deps []core.Dependency
2020
lines := strings.Split(string(content), "\n")
2121

@@ -41,5 +41,5 @@ func (p *toolVersionsParser) Parse(filename string, content []byte) ([]core.Depe
4141
})
4242
}
4343

44-
return deps, nil
44+
return &core.Result{Dependencies: deps}, nil
4545
}

internal/asdf/asdf_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,27 @@ func TestToolVersions(t *testing.T) {
1212
}
1313

1414
parser := &toolVersionsParser{}
15-
deps, err := parser.Parse(".tool-versions", content)
15+
res, err := parser.Parse(".tool-versions", content)
1616
if err != nil {
1717
t.Fatalf("Parse failed: %v", err)
1818
}
1919

20-
if len(deps) != 6 {
21-
t.Fatalf("expected 6 dependencies, got %d", len(deps))
20+
if len(res.Dependencies) != 6 {
21+
t.Fatalf("expected 6 dependencies, got %d", len(res.Dependencies))
2222
}
2323

2424
depMap := make(map[string]string)
25-
for _, d := range deps {
25+
for _, d := range res.Dependencies {
2626
depMap[d.Name] = d.Version
2727
}
2828

2929
expected := map[string]string{
30-
"nodejs": "18.12.0",
31-
"ruby": "3.2.1",
32-
"python": "3.11.2",
33-
"golang": "1.21.0",
34-
"erlang": "26.0.2",
35-
"rust": "1.72.0",
30+
"nodejs": "18.12.0",
31+
"ruby": "3.2.1",
32+
"python": "3.11.2",
33+
"golang": "1.21.0",
34+
"erlang": "26.0.2",
35+
"rust": "1.72.0",
3636
}
3737

3838
for name, wantVer := range expected {

internal/bazel/bazel.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ func init() {
1616

1717
type bazelModuleManifestParser struct{}
1818

19-
func (p *bazelModuleManifestParser) Parse(filename string, content []byte) ([]core.Dependency, error) {
19+
func (p *bazelModuleManifestParser) Parse(filename string, content []byte) (*core.Result, error) {
2020
var deps []core.Dependency
21+
var selfName, selfVersion string
2122

2223
moduleManifestTree, err := build.ParseModule(filename, content)
2324
if err != nil {
@@ -31,9 +32,19 @@ func (p *bazelModuleManifestParser) Parse(filename string, content []byte) ([]co
3132
continue
3233
}
3334

34-
// Check if statement is a dependency declaration
3535
ident, ok := callExperssion.X.(*build.Ident)
36-
if !ok || ident.Name != "bazel_dep" {
36+
if !ok {
37+
continue
38+
}
39+
40+
// module(name = "...", version = "...")
41+
if ident.Name == "module" {
42+
selfName, selfVersion = parseBazelModule(*callExperssion)
43+
continue
44+
}
45+
46+
// Check if statement is a dependency declaration
47+
if ident.Name != "bazel_dep" {
3748
continue
3849
}
3950

@@ -54,7 +65,31 @@ func (p *bazelModuleManifestParser) Parse(filename string, content []byte) ([]co
5465
})
5566

5667
}
57-
return deps, nil
68+
return &core.Result{Name: selfName, Version: selfVersion, Dependencies: deps}, nil
69+
}
70+
71+
func parseBazelModule(call build.CallExpr) (name, version string) {
72+
for _, arg := range call.List {
73+
assign, ok := arg.(*build.AssignExpr)
74+
if !ok || assign == nil {
75+
continue
76+
}
77+
key, ok := assign.LHS.(*build.Ident)
78+
if !ok {
79+
continue
80+
}
81+
val, ok := assign.RHS.(*build.StringExpr)
82+
if !ok {
83+
continue
84+
}
85+
switch key.Name {
86+
case "name":
87+
name = val.Value
88+
case "version":
89+
version = val.Value
90+
}
91+
}
92+
return name, version
5893
}
5994

6095
type bazelDep struct {

internal/bazel/bazel_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,17 @@ func TestBazelModuleManifest(t *testing.T) {
1414
}
1515

1616
parser := &bazelModuleManifestParser{}
17-
deps, err := parser.Parse("MODULE.bazel", content)
17+
res, err := parser.Parse("MODULE.bazel", content)
1818
if err != nil {
1919
t.Fatalf("Parse failed: %v", err)
2020
}
2121

22-
if len(deps) != 9 {
23-
t.Fatalf("expected 9 dependencies, got %d", len(deps))
22+
if len(res.Dependencies) != 9 {
23+
t.Fatalf("expected 9 dependencies, got %d", len(res.Dependencies))
2424
}
2525

2626
depMap := make(map[string]core.Dependency)
27-
for _, d := range deps {
27+
for _, d := range res.Dependencies {
2828
depMap[d.Name] = d
2929
}
3030

internal/brew/brew.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package brew
22

33
import (
4-
"github.com/git-pkgs/manifests/internal/core"
54
"encoding/json"
5+
"github.com/git-pkgs/manifests/internal/core"
66
"regexp"
77
"strings"
88
)
@@ -24,7 +24,7 @@ var (
2424
brewTapRegex = regexp.MustCompile(`^\s*tap\s+["']([^"']+)["']`)
2525
)
2626

27-
func (p *brewfileParser) Parse(filename string, content []byte) ([]core.Dependency, error) {
27+
func (p *brewfileParser) Parse(filename string, content []byte) (*core.Result, error) {
2828
var deps []core.Dependency
2929
lines := strings.Split(string(content), "\n")
3030

@@ -37,25 +37,25 @@ func (p *brewfileParser) Parse(filename string, content []byte) ([]core.Dependen
3737
if match := brewFormulaRegex.FindStringSubmatch(line); match != nil {
3838
deps = append(deps, core.Dependency{
3939
Name: match[1],
40-
Scope: core.Runtime,
40+
Scope: core.Runtime,
4141
Direct: true,
4242
})
4343
} else if match := brewCaskRegex.FindStringSubmatch(line); match != nil {
4444
deps = append(deps, core.Dependency{
4545
Name: match[1],
46-
Scope: core.Runtime,
46+
Scope: core.Runtime,
4747
Direct: true,
4848
})
4949
} else if match := brewTapRegex.FindStringSubmatch(line); match != nil {
5050
deps = append(deps, core.Dependency{
5151
Name: match[1],
52-
Scope: core.Runtime,
52+
Scope: core.Runtime,
5353
Direct: true,
5454
})
5555
}
5656
}
5757

58-
return deps, nil
58+
return &core.Result{Dependencies: deps}, nil
5959
}
6060

6161
// brewfileLockParser parses Brewfile.lock.json.
@@ -78,7 +78,7 @@ type brewLockEntry struct {
7878
} `json:"bottle"`
7979
}
8080

81-
func (p *brewfileLockParser) Parse(filename string, content []byte) ([]core.Dependency, error) {
81+
func (p *brewfileLockParser) Parse(filename string, content []byte) (*core.Result, error) {
8282
var lock brewfileLock
8383
if err := json.Unmarshal(content, &lock); err != nil {
8484
return nil, &core.ParseError{Filename: filename, Err: err}
@@ -98,7 +98,7 @@ func (p *brewfileLockParser) Parse(filename string, content []byte) ([]core.Depe
9898
deps = append(deps, core.Dependency{
9999
Name: name,
100100
Version: entry.Version,
101-
Scope: core.Runtime,
101+
Scope: core.Runtime,
102102
Integrity: integrity,
103103
Direct: true,
104104
})
@@ -113,5 +113,5 @@ func (p *brewfileLockParser) Parse(filename string, content []byte) ([]core.Depe
113113
})
114114
}
115115

116-
return deps, nil
116+
return &core.Result{Dependencies: deps}, nil
117117
}

0 commit comments

Comments
 (0)