Skip to content

Commit 150a773

Browse files
authored
fix(conda): add support pip deps for environment.yml files (#6675)
1 parent 787b466 commit 150a773

File tree

6 files changed

+111
-12
lines changed

6 files changed

+111
-12
lines changed

pkg/dependency/parser/conda/environment/parse.go

+48-10
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ import (
1515
)
1616

1717
type environment struct {
18-
Dependencies []Dependency `yaml:"dependencies"`
18+
Entries []Entry `yaml:"dependencies"`
19+
}
20+
21+
type Entry struct {
22+
Dependencies []Dependency
1923
}
2024

2125
type Dependency struct {
@@ -42,13 +46,15 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc
4246
}
4347

4448
var pkgs ftypes.Packages
45-
for _, dep := range env.Dependencies {
46-
pkg := p.toPackage(dep)
47-
// Skip empty pkgs
48-
if pkg.Name == "" {
49-
continue
49+
for _, entry := range env.Entries {
50+
for _, dep := range entry.Dependencies {
51+
pkg := p.toPackage(dep)
52+
// Skip empty pkgs
53+
if pkg.Name == "" {
54+
continue
55+
}
56+
pkgs = append(pkgs, pkg)
5057
}
51-
pkgs = append(pkgs, pkg)
5258
}
5359

5460
sort.Sort(pkgs)
@@ -96,8 +102,40 @@ func (*Parser) parseDependency(line string) (string, string) {
96102
return name, parts[1]
97103
}
98104

99-
func (d *Dependency) UnmarshalYAML(node *yaml.Node) error {
100-
d.Value = node.Value
101-
d.Line = node.Line
105+
func (e *Entry) UnmarshalYAML(node *yaml.Node) error {
106+
var dependencies []Dependency
107+
// cf. https://github.com/go-yaml/yaml/blob/f6f7691b1fdeb513f56608cd2c32c51f8194bf51/resolve.go#L70-L81
108+
switch node.Tag {
109+
case "!!str":
110+
dependencies = append(dependencies, Dependency{
111+
Value: node.Value,
112+
Line: node.Line,
113+
})
114+
case "!!map":
115+
if node.Content != nil {
116+
// Map key is package manager (e.g. pip). So we need to store only map values (dependencies).
117+
// e.g. dependencies:
118+
// - pip:
119+
// - pandas==2.1.4
120+
if node.Content[1].Tag != "!!seq" { // Conda supports only map[string][]string format.
121+
return xerrors.Errorf("unsupported dependency type %q on line %d", node.Content[1].Tag, node.Content[1].Line)
122+
}
123+
124+
for _, depContent := range node.Content[1].Content {
125+
if depContent.Tag != "!!str" {
126+
return xerrors.Errorf("unsupported dependency type %q on line %d", depContent.Tag, depContent.Line)
127+
}
128+
129+
dependencies = append(dependencies, Dependency{
130+
Value: depContent.Value,
131+
Line: depContent.Line,
132+
})
133+
}
134+
}
135+
default:
136+
return xerrors.Errorf("unsupported dependency type %q on line %d", node.Tag, node.Line)
137+
}
138+
139+
e.Dependencies = dependencies
102140
return nil
103141
}

pkg/dependency/parser/conda/environment/parse_test.go

+37-2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ func TestParse(t *testing.T) {
3131
},
3232
},
3333
},
34+
{
35+
Name: "asgiref",
36+
Version: "3.8.1",
37+
Locations: ftypes.Locations{
38+
{
39+
StartLine: 21,
40+
EndLine: 21,
41+
},
42+
},
43+
},
3444
{
3545
Name: "blas",
3646
Version: "1.0",
@@ -61,6 +71,16 @@ func TestParse(t *testing.T) {
6171
},
6272
},
6373
},
74+
{
75+
Name: "django",
76+
Version: "5.0.6",
77+
Locations: ftypes.Locations{
78+
{
79+
StartLine: 22,
80+
EndLine: 22,
81+
},
82+
},
83+
},
6484
{
6585
Name: "ld_impl_linux-aarch64",
6686
Locations: ftypes.Locations{
@@ -167,9 +187,24 @@ func TestParse(t *testing.T) {
167187
},
168188
},
169189
{
170-
name: "invalid_json",
190+
name: "invalid yaml file",
171191
input: "testdata/invalid.yaml",
172-
wantErr: "unable to decode conda environment.yml file",
192+
wantErr: "cannot unmarshal !!str `invalid` into environment.environment",
193+
},
194+
{
195+
name: "`dependency` field uses unsupported type",
196+
input: "testdata/wrong-deps-type.yaml",
197+
wantErr: `unsupported dependency type "!!int" on line 5`,
198+
},
199+
{
200+
name: "nested field uses unsupported type",
201+
input: "testdata/wrong-nested-type.yaml",
202+
wantErr: `unsupported dependency type "!!str" on line 5`,
203+
},
204+
{
205+
name: "nested dependency uses unsupported type",
206+
input: "testdata/wrong-nested-dep-type.yaml",
207+
wantErr: `unsupported dependency type "!!map" on line 6`,
173208
},
174209
}
175210
for _, tt := range tests {

pkg/dependency/parser/conda/environment/testdata/happy.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ dependencies:
1717
- liblapack=3.9.*=22_linuxaarch64_openblas
1818
- libnsl=2.0.1=h31becfc_0
1919
- bzip2=1.0.8=h998d150_5
20+
- pip:
21+
- asgiref==3.8.1
22+
- django==5.0.6
2023

2124
prefix: /opt/conda/envs/test-env
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: test-env
2+
channels:
3+
- defaults
4+
dependencies:
5+
- 1
6+
7+
prefix: /opt/conda/envs/test-env
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: test-env
2+
channels:
3+
- defaults
4+
dependencies:
5+
- pip:
6+
- wrongType:
7+
- asgiref==3.8.1
8+
9+
prefix: /opt/conda/envs/test-env
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: test-env
2+
channels:
3+
- defaults
4+
dependencies:
5+
- pip: asgiref==3.8.1
6+
7+
prefix: /opt/conda/envs/test-env

0 commit comments

Comments
 (0)