@@ -170,6 +170,25 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
170170 panic (err )
171171 }
172172
173+ // Helper function to add an edge with a tooltip describing both nodes and dependency type
174+ addEdgeWithTooltip := func (from , to * dot.Node , fromName , toName , depType string ) error {
175+ edge := dot .NewEdge (from , to )
176+
177+ if web {
178+ tooltip := fmt .Sprintf ("%s → %s" , fromName , toName )
179+ if depType != "" {
180+ tooltip += fmt .Sprintf (" (%s)" , depType )
181+ }
182+
183+ if err := edge .Set ("tooltip" , tooltip ); err != nil {
184+ return err
185+ }
186+ }
187+
188+ _ , err := out .AddEdge (edge )
189+ return err
190+ }
191+
173192 file := dot .NewNode (configFile )
174193 if _ , err := out .AddNode (file ); err != nil {
175194 panic (err )
@@ -187,7 +206,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
187206 }
188207 }
189208
190- if _ , err := out . AddEdge ( dot . NewEdge ( file , n ) ); err != nil {
209+ if err := addEdgeWithTooltip ( file , n , configFile , pkg , "required" ); err != nil {
191210 panic (err )
192211 }
193212 if before , _ , ok := strings .Cut (pkg , "=" ); ok {
@@ -201,7 +220,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
201220 panic (err )
202221 }
203222 }
204- if _ , err := out . AddEdge ( dot . NewEdge ( n , p ) ); err != nil {
223+ if err := addEdgeWithTooltip ( n , p , pkg , before , "exact version" ); err != nil {
205224 panic (err )
206225 }
207226
@@ -233,7 +252,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
233252 panic (err )
234253 }
235254 }
236- if _ , err := out . AddEdge ( dot . NewEdge ( n , p ) ); err != nil {
255+ if err := addEdgeWithTooltip ( n , p , pkg , before , "compatible version" ); err != nil {
237256 panic (err )
238257 }
239258
@@ -329,7 +348,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
329348 if _ , ok := edges [dep ]; ! ok || ! span {
330349 // This check is stupid but otherwise cycles render dumb.
331350 if pkg .Name != dep {
332- if _ , err := out . AddEdge ( dot . NewEdge ( n , d ) ); err != nil {
351+ if err := addEdgeWithTooltip ( n , d , pkg . Name , dep , "dependency" ); err != nil {
333352 panic (err )
334353 }
335354 edges [dep ] = struct {}{}
@@ -396,7 +415,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
396415 panic (err )
397416 }
398417
399- if _ , err := out . AddEdge ( dot . NewEdge ( p , n ) ); err != nil {
418+ if err := addEdgeWithTooltip ( p , n , before , pkg . Name , "provides" ); err != nil {
400419 panic (err )
401420 }
402421 }
@@ -417,7 +436,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
417436 panic (err )
418437 }
419438
420- if _ , err := out . AddEdge ( dot . NewEdge ( p , n ) ); err != nil {
439+ if err := addEdgeWithTooltip ( p , n , before , pkg . Name , "provides" ); err != nil {
421440 panic (err )
422441 }
423442 }
@@ -437,7 +456,7 @@ func DotCmd(ctx context.Context, configFile string, archs []types.Architecture,
437456 }
438457 }
439458 if _ , ok := edges [pkg .Name ]; ! ok || ! span {
440- if _ , err := out . AddEdge ( dot . NewEdge ( p , n ) ); err != nil {
459+ if err := addEdgeWithTooltip ( p , n , prov , pkg . Name , "provides" ); err != nil {
441460 panic (err )
442461 }
443462 edges [pkg .Name ] = struct {}{}
0 commit comments