Skip to content

Commit

Permalink
dependency graph may be cyclic
Browse files Browse the repository at this point in the history
Signed-off-by: Akash Kumar <meakash7902@gmail.com>
  • Loading branch information
AkashKumar7902 committed Feb 15, 2024
1 parent 5804939 commit 7c0d2d1
Showing 1 changed file with 74 additions and 16 deletions.
90 changes: 74 additions & 16 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1071,26 +1071,26 @@ func (c *KpmClient) ParseOciOptionFromString(oci string, tag string) (*opt.OciOp

// PrintDependencyGraph will print the dependency graph of kcl package dependencies
func (c *KpmClient) PrintDependencyGraph(kclPkg *pkg.KclPkg) error {
_, depGraph, err := c.downloadDeps(kclPkg.Dependencies, kclPkg.ModFile.Dependencies)
_, depGraph, err := c.downloadDeps(kclPkg.ModFile.Dependencies, kclPkg.Dependencies)
if err != nil {
return err
}

// add the root vertex(package name) to the dependency graph.
root := fmt.Sprint(kclPkg.GetPkgName())
err = depGraph.AddVertex(root)
sources, err := FindSource(depGraph)
if err != nil {
return err
}

sources, err := FindSource(depGraph)
// add the root vertex(package name) to the dependency graph.
root := fmt.Sprintf("%s@%s", kclPkg.GetPkgName(), kclPkg.GetPkgVersion())
err = depGraph.AddVertex(root)
if err != nil {
return err
}

// make an edge between the root vertex and all the sources of the dependency graph.
for _, source := range sources {
err = depGraph.AddEdge(source, root)
err = depGraph.AddEdge(root, source)
if err != nil {
return err
}
Expand All @@ -1105,7 +1105,7 @@ func (c *KpmClient) PrintDependencyGraph(kclPkg *pkg.KclPkg) error {
err = graph.BFS(depGraph, root, func(source string) bool {
for target := range adjMap[source] {
reporter.ReportMsgTo(
fmt.Sprint(source, target),
fmt.Sprint(source, " ", target),
c.logWriter,
)
}
Expand Down Expand Up @@ -1194,13 +1194,6 @@ func (c *KpmClient) downloadDeps(deps pkg.Dependencies, lockDeps pkg.Dependencie

depGraph := graph.New(graph.StringHash, graph.Directed())

for _, d := range newDeps.Deps {
err := depGraph.AddVertex(fmt.Sprintf("%s@%s", d.Name, d.Version))
if err != nil {
return nil, nil, err
}
}

// Recursively download the dependencies of the new dependencies.
for _, d := range newDeps.Deps {
// Load kcl.mod file of the new downloaded dependencies.
Expand All @@ -1223,20 +1216,27 @@ func (c *KpmClient) downloadDeps(deps pkg.Dependencies, lockDeps pkg.Dependencie
}

source := fmt.Sprintf("%s@%s", d.Name, d.Version)
err = depGraph.AddVertex(source)
if err != nil {
if err != graph.ErrVertexAlreadyExists {
return nil, nil, err
}
}

sourcesOfNestedDepGraph, err := FindSource(nestedDepGraph)
if err != nil {
return nil, nil, err
}

depGraph, err = graph.Union(depGraph, nestedDepGraph)
depGraph, err = Union(depGraph, nestedDepGraph)
if err != nil {
return nil, nil, err
}

// make an edge between the source of all nested dep graph and main dep graph
for _, sourceOfNestedDepGraph := range sourcesOfNestedDepGraph {
err = depGraph.AddEdge(source, sourceOfNestedDepGraph)
if err != nil {
if err != nil && err != graph.ErrEdgeAlreadyExists {
return nil, nil, err
}
}
Expand Down Expand Up @@ -1341,3 +1341,61 @@ func FindSource[K comparable, T any](g graph.Graph[K, T]) ([]K, error) {
}
return sources, nil
}

// Union combines two given graphs into a new graph. The vertex hashes in both
// graphs are expected to be unique. The two input graphs will remain unchanged.
//
// Both graphs should be either directed or undirected. All traits for the new
// graph will be derived from g.
//
// If the same vertex/edge happens to be in both g and h, then an error will not be
// thrown as happens in original Union function and successful operation takes place.
func Union[K comparable, T any](g, h graph.Graph[K, T]) (graph.Graph[K, T], error) {
union, err := g.Clone()
if err != nil {
return union, fmt.Errorf("failed to clone g: %w", err)
}

adjacencyMap, err := h.AdjacencyMap()
if err != nil {
return union, fmt.Errorf("failed to get adjacency map: %w", err)
}

addedEdges := make(map[K]map[K]struct{})

for currentHash := range adjacencyMap {
vertex, err := h.Vertex(currentHash)
if err != nil {
return union, fmt.Errorf("failed to get vertex %v: %w", currentHash, err)
}

err = union.AddVertex(vertex)
if err != nil && err != graph.ErrVertexAlreadyExists {
return union, fmt.Errorf("failed to add vertex %v: %w", currentHash, err)
}
}

for _, adjacencies := range adjacencyMap {
for _, edge := range adjacencies {
if _, sourceOK := addedEdges[edge.Source]; sourceOK {
if _, targetOK := addedEdges[edge.Source][edge.Target]; targetOK {
// If the edge addedEdges[source][target] exists, the edge
// has already been created and thus can be skipped here.
continue
}
}

err = union.AddEdge(edge.Source, edge.Target)
if err != nil && err != graph.ErrEdgeAlreadyExists {
return union, fmt.Errorf("failed to add edge (%v, %v): %w", edge.Source, edge.Target, err)
}

if _, ok := addedEdges[edge.Source]; !ok {
addedEdges[edge.Source] = make(map[K]struct{})
}
addedEdges[edge.Source][edge.Target] = struct{}{}
}
}

return union, nil
}

0 comments on commit 7c0d2d1

Please sign in to comment.