Skip to content

Commit

Permalink
check for multiple roots
Browse files Browse the repository at this point in the history
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
  • Loading branch information
nikpivkin committed Dec 17, 2024
1 parent e67015d commit b4f3191
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 11 deletions.
30 changes: 19 additions & 11 deletions pkg/dependency/parser/python/uv/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ func (l Lock) directDeps(root Package) map[string]struct{} {
return deps
}

func (l Lock) prodDeps(root Package) map[string]struct{} {
packages := l.packages()
func prodDeps(root Package, packages map[string]Package) map[string]struct{} {
visited := make(map[string]struct{})
walkPackageDeps(root, packages, visited)
return visited
Expand All @@ -51,14 +50,25 @@ func walkPackageDeps(pkg Package, packages map[string]Package, visited map[strin
}
}

func (l Lock) root() Package {
func (l Lock) root() (Package, error) {
var pkgs []Package
for _, pkg := range l.Packages {
if pkg.isRoot() {
return pkg
pkgs = append(pkgs, pkg)
}
}

return Package{}
if len(pkgs) > 1 {
return Package{}, xerrors.New("uv lockfile contains multiple root projects")
}

// lock file must include root package
// cf. https://github.com/astral-sh/uv/blob/f80ddf10b63c3e7b421ca4658e63f97db1e0378c/crates/uv/src/commands/project/lock.rs#L933-L936
if len(pkgs) != 1 {
return Package{}, xerrors.New("uv lockfile does not contain a root package.")
}

return pkgs[0], nil
}

type Package struct {
Expand Down Expand Up @@ -94,16 +104,14 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc
return nil, nil, xerrors.Errorf("failed to decode uv lock file: %w", err)
}

rootPackage := lock.root()
// lock file must include root package
// cf. https://github.com/astral-sh/uv/blob/f80ddf10b63c3e7b421ca4658e63f97db1e0378c/crates/uv/src/commands/project/lock.rs#L933-L936
if rootPackage.Name == "" {
return nil, nil, xerrors.New("uv lockfile does not contain a root package.")
rootPackage, err := lock.root()
if err != nil {
return nil, nil, err
}

packages := lock.packages()
directDeps := lock.directDeps(rootPackage)
prodDeps := lock.prodDeps(rootPackage)
prodDeps := prodDeps(rootPackage, packages)

var (
pkgs ftypes.Packages
Expand Down
5 changes: 5 additions & 0 deletions pkg/dependency/parser/python/uv/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ func TestParser_Parse(t *testing.T) {
file: "testdata/uv_without_root.lock",
wantErr: "uv lockfile does not contain a root package",
},
{
name: "multiple roots",
file: "testdata/uv_multiple_roots.lock",
wantErr: "uv lockfile contains multiple root projects",
},
}

for _, tt := range tests {
Expand Down
30 changes: 30 additions & 0 deletions pkg/dependency/parser/python/uv/testdata/uv_multiple_roots.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
version = 1
requires-python = ">=3.11"

[[package]]
name = "asyncio"
version = "3.4.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/da/54/054bafaf2c0fb8473d423743e191fcdf49b2c1fd5e9af3524efbe097bafd/asyncio-3.4.3.tar.gz", hash = "sha256:83360ff8bc97980e4ff25c964c7bd3923d333d177aa4f7fb736b019f26c7cb41", size = 204411 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/22/74/07679c5b9f98a7cb0fc147b1ef1cc1853bc07a4eb9cb5731e24732c5f773/asyncio-3.4.3-py3-none-any.whl", hash = "sha256:c4d18b22701821de07bd6aea8b53d21449ec0ec5680645e5317062ea21817d2d", size = 101767 },
]

[[package]]
name = "foo"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "asyncio" },
]

[package.metadata]
requires-dist = [{ name = "asyncio", specifier = "==3.4.3" }]

[[package]]
name = "bar"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "asyncio" },
]

0 comments on commit b4f3191

Please sign in to comment.