diff --git a/local_install.go b/local_install.go index b4a5a3d1..e8bbcfe7 100644 --- a/local_install.go +++ b/local_install.go @@ -132,16 +132,23 @@ func installLocalPKGBUILD( func addNodes(dbExecutor db.Executor, aurClient aur.ClientInterface, pkgName string, pkgBase string, deps []string, graph *topo.Graph[string]) { graph.AddNode(pkgBase) graph.Alias(pkgBase, pkgName) + graph.SetNodeInfo(pkgBase, &topo.NodeInfo{Color: "blue"}) for _, depString := range deps { depName, _, _ := splitDep(depString) - if dbExecutor.LocalSatisfierExists(depString) { - continue - } - graph.DependOn(depName, pkgBase) + warnings := query.AURWarnings{} + + if dbExecutor.LocalSatisfierExists(depString) { + graph.SetNodeInfo(depName, &topo.NodeInfo{Color: "green"}) + continue + } else { + graph.SetNodeInfo(depName, &topo.NodeInfo{Color: "red"}) + } + + // Check ALPM if alpmPkg := dbExecutor.SyncSatisfier(depString); alpmPkg != nil { newDeps := alpmPkg.Depends().Slice() newDepsSlice := make([]string, 0, len(newDeps)) @@ -151,10 +158,8 @@ func addNodes(dbExecutor db.Executor, aurClient aur.ClientInterface, pkgName str } addNodes(dbExecutor, aurClient, alpmPkg.Name(), alpmPkg.Base(), newDepsSlice, graph) - } - - warnings := query.AURWarnings{} - if aurPkgs, _ := query.AURInfo(context.TODO(), aurClient, []string{depName}, &warnings, 1); len(aurPkgs) != 0 { + // Check AUR + } else if aurPkgs, _ := query.AURInfo(context.TODO(), aurClient, []string{depName}, &warnings, 1); len(aurPkgs) != 0 { pkg := aurPkgs[0] newDeps := dep.ComputeCombinedDepList(pkg, false, false) newDepsSlice := make([]string, 0, len(newDeps)) @@ -162,6 +167,4 @@ func addNodes(dbExecutor db.Executor, aurClient aur.ClientInterface, pkgName str addNodes(dbExecutor, aurClient, pkg.PackageBase, pkg.Name, newDepsSlice, graph) } } - - return } diff --git a/pkg/topo/dep.go b/pkg/topo/dep.go index 7e4f9f6b..eca2998e 100644 --- a/pkg/topo/dep.go +++ b/pkg/topo/dep.go @@ -15,10 +15,17 @@ type ( DepMap[T comparable] map[T]NodeSet[T] ) +type NodeInfo struct { + Color string +} + type Graph[T comparable] struct { alias AliasMap[T] nodes NodeSet[T] + // node info map + nodeInfo map[T]NodeInfo + // `dependencies` tracks child -> parents. dependencies DepMap[T] // `dependents` tracks parent -> children. @@ -32,6 +39,7 @@ func New[T comparable]() *Graph[T] { dependencies: make(DepMap[T]), dependents: make(DepMap[T]), alias: make(AliasMap[T]), + nodeInfo: make(map[T]NodeInfo), } } @@ -61,6 +69,15 @@ func (g *Graph[T]) AddNode(node T) { g.nodes[node] = true } +func (g *Graph[T]) SetNodeInfo(node T, nodeInfo *NodeInfo) { + // check aliases + if aliasNode, ok := g.alias[node]; ok { + node = aliasNode + } + + g.nodeInfo[node] = *nodeInfo +} + func (g *Graph[T]) DependOn(child, parent T) error { if child == parent { return ErrSelfReferential @@ -87,11 +104,21 @@ func (g *Graph[T]) DependOn(child, parent T) error { func (g *Graph[T]) String() string { var sb strings.Builder sb.WriteString("digraph {\n") - // sb.WriteString("rankdir=LR;\n") + sb.WriteString("compound=true;\n") + sb.WriteString("concentrate=true;\n") sb.WriteString("node [shape = record, ordering=out];\n") + for node := range g.nodes { - sb.WriteString(fmt.Sprintf("\t\"%v\";\n", node)) + extra := "" + if info, ok := g.nodeInfo[node]; ok { + if info.Color != "" { + extra = fmt.Sprintf("[color = %s]", info.Color) + } + } + + sb.WriteString(fmt.Sprintf("\t\"%v\"%s;\n", node, extra)) } + for parent, children := range g.dependencies { for child := range children { sb.WriteString(fmt.Sprintf("\t\"%v\" -> \"%v\";\n", parent, child))