Skip to content

Commit c3e7eab

Browse files
committed
Parse resolve output into normalized JSON with PURLs
Adds github.com/git-pkgs/resolve to parse raw package manager output into a structured dependency graph. The resolve command now outputs JSON with manager, ecosystem, and dependency tree including PURLs. Use --raw for the previous behavior of printing unparsed output.
1 parent 800edd6 commit c3e7eab

File tree

4 files changed

+37
-8
lines changed

4 files changed

+37
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ git pkgs update lodash # update specific package
272272
git pkgs resolve # print dependency graph
273273
```
274274

275-
The `resolve` command prints raw dependency graph output from the package manager. Some managers produce JSON (npm, cargo, pip), others produce text trees (go, maven, poetry). Status lines go to stderr so stdout is clean for piping.
275+
The `resolve` command runs the package manager's dependency graph command, parses the output into a normalized JSON structure with [PURLs](https://github.com/package-url/purl-spec), and prints the result. Use `--raw` to get the unparsed manager output instead.
276276

277277
Supports 35 package managers including npm, pnpm, yarn, bun, deno, bundler, gem, cargo, go, pip, uv, poetry, conda, composer, mix, rebar3, pub, cocoapods, swift, nuget, maven, gradle, sbt, cabal, stack, opam, luarocks, nimble, shards, cpanm, lein, vcpkg, conan, helm, and brew. The package manager is detected from lockfiles in the current directory.
278278

cmd/resolve.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package cmd
22

33
import (
4+
"bytes"
45
"context"
6+
"encoding/json"
57
"fmt"
68
"time"
79

810
"github.com/git-pkgs/managers"
11+
"github.com/git-pkgs/resolve"
12+
_ "github.com/git-pkgs/resolve/parsers"
913
"github.com/spf13/cobra"
1014
)
1115

@@ -14,24 +18,26 @@ const defaultResolveTimeout = 5 * time.Minute
1418
func addResolveCmd(parent *cobra.Command) {
1519
resolveCmd := &cobra.Command{
1620
Use: "resolve",
17-
Short: "Print dependency graph from the local package manager",
18-
Long: `Run the detected package manager's dependency graph command and print
19-
the raw output. The output format depends on the manager: some produce
20-
JSON (npm, cargo, pip), others produce text trees (go, maven, poetry).
21+
Short: "Print parsed dependency graph from the local package manager",
22+
Long: `Run the detected package manager's dependency graph command, parse
23+
the output into a normalized dependency list with PURLs, and print
24+
the result as JSON.
2125
2226
Assumes dependencies are already installed. Run 'git-pkgs install' first
2327
if needed.
2428
2529
Examples:
2630
git-pkgs resolve # resolve dependencies
2731
git-pkgs resolve -e go # only resolve Go ecosystem
28-
git-pkgs resolve -m cargo # force cargo`,
32+
git-pkgs resolve -m cargo # force cargo
33+
git-pkgs resolve --raw # print raw manager output`,
2934
RunE: runResolve,
3035
}
3136

3237
resolveCmd.Flags().StringP("manager", "m", "", "Override detected package manager (takes precedence over -e)")
3338
resolveCmd.Flags().StringP("ecosystem", "e", "", "Filter to specific ecosystem")
3439
resolveCmd.Flags().Bool("dry-run", false, "Show what would be run without executing")
40+
resolveCmd.Flags().Bool("raw", false, "Print raw manager output instead of parsed JSON")
3541
resolveCmd.Flags().StringArrayP("extra", "x", nil, "Extra arguments to pass to package manager")
3642
resolveCmd.Flags().DurationP("timeout", "t", defaultResolveTimeout, "Timeout for resolve operation")
3743
parent.AddCommand(resolveCmd)
@@ -41,6 +47,7 @@ func runResolve(cmd *cobra.Command, args []string) error {
4147
managerOverride, _ := cmd.Flags().GetString("manager")
4248
ecosystem, _ := cmd.Flags().GetString("ecosystem")
4349
dryRun, _ := cmd.Flags().GetBool("dry-run")
50+
raw, _ := cmd.Flags().GetBool("raw")
4451
quiet, _ := cmd.Flags().GetBool("quiet")
4552
extra, _ := cmd.Flags().GetStringArray("extra")
4653
timeout, _ := cmd.Flags().GetDuration("timeout")
@@ -107,9 +114,28 @@ func runResolve(cmd *cobra.Command, args []string) error {
107114
}
108115
}
109116

110-
if err := RunManagerCommands(ctx, dir, mgr.Name, "resolve", input, cmd.OutOrStdout(), cmd.ErrOrStderr()); err != nil {
117+
if raw {
118+
if err := RunManagerCommands(ctx, dir, mgr.Name, "resolve", input, cmd.OutOrStdout(), cmd.ErrOrStderr()); err != nil {
119+
return fmt.Errorf("%s resolve failed: %w", mgr.Name, err)
120+
}
121+
continue
122+
}
123+
124+
var stdout bytes.Buffer
125+
if err := RunManagerCommands(ctx, dir, mgr.Name, "resolve", input, &stdout, cmd.ErrOrStderr()); err != nil {
111126
return fmt.Errorf("%s resolve failed: %w", mgr.Name, err)
112127
}
128+
129+
result, err := resolve.Parse(mgr.Name, stdout.Bytes())
130+
if err != nil {
131+
return fmt.Errorf("%s: %w", mgr.Name, err)
132+
}
133+
134+
enc := json.NewEncoder(cmd.OutOrStdout())
135+
enc.SetIndent("", " ")
136+
if err := enc.Encode(result); err != nil {
137+
return fmt.Errorf("encoding result: %w", err)
138+
}
113139
}
114140

115141
return nil

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/git-pkgs/git-pkgs
22

3-
go 1.25.6
3+
go 1.25.7
44

55
require (
66
github.com/git-pkgs/enrichment v0.1.4
@@ -9,6 +9,7 @@ require (
99
github.com/git-pkgs/manifests v0.3.7
1010
github.com/git-pkgs/purl v0.1.8
1111
github.com/git-pkgs/registries v0.2.6
12+
github.com/git-pkgs/resolve v0.1.0
1213
github.com/git-pkgs/spdx v0.1.0
1314
github.com/git-pkgs/vers v0.2.2
1415
github.com/git-pkgs/vulns v0.1.3

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ github.com/git-pkgs/purl v0.1.8 h1:iyjEHM2WIZUL9A3+q9ylrabqILsN4nOay9X6jfEjmzQ=
4949
github.com/git-pkgs/purl v0.1.8/go.mod h1:ihlHw3bnSLXat+9Nl9MsJZBYiG7s3NkwmvE3L/Es/sI=
5050
github.com/git-pkgs/registries v0.2.6 h1:hXPQ47mOzrgtZleOimydwpQjj/NJkU9P/4sTa0n6wTI=
5151
github.com/git-pkgs/registries v0.2.6/go.mod h1:54jwF9erSjyxE4qT7gmU9HebETrYiNPke7JCgzHbtDc=
52+
github.com/git-pkgs/resolve v0.1.0 h1:3L8YUj2ggpnCqAm2r8aEtt3MOlT40NUjQaQhcwd0ci4=
53+
github.com/git-pkgs/resolve v0.1.0/go.mod h1:So7rkvjSgz3qbFKcgQ8KQ2Tc8z3D8gmVlyvB5fG+UQM=
5254
github.com/git-pkgs/spdx v0.1.0 h1:kBcB2iIc3A8qSAU/MtqywKslEo+FRct2daFLX+pwZdU=
5355
github.com/git-pkgs/spdx v0.1.0/go.mod h1:Cmpseu5vIhDPnpFXhTVBCJhjZUW3ILck/zhycHHKcXA=
5456
github.com/git-pkgs/vers v0.2.2 h1:42QkiIURhGN2wM8AuYYU+FbzS1YV6jmdGd1RiFp7gXs=

0 commit comments

Comments
 (0)