blob: ba12d3ce4d79639fe9b8bc76deb958a20dcc451c [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package builder
import (
"bytes"
"fmt"
"strings"
"mynewt.apache.org/newt/newt/resolve"
)
// Records presence of each dependency.
type rmap map[*resolve.ResolveDep]struct{}
// Type used internally while building a proper dependency graph.
type graphMap map[*resolve.ResolvePackage]rmap
// Key=parent, Value=slice of children
// For normal dependency graph: parent=depender, children=dependees.
// For reverse dependency graph: parent=dependee, children=dependers.
type DepGraph map[*resolve.ResolvePackage][]*resolve.ResolveDep
func graphMapEnsure(gm graphMap, p *resolve.ResolvePackage) rmap {
if gm[p] == nil {
gm[p] = rmap{}
}
return gm[p]
}
func graphMapAdd(gm graphMap, p *resolve.ResolvePackage, c *resolve.ResolveDep) {
dstGraph := graphMapEnsure(gm, p)
if dstGraph == nil {
dstGraph = map[*resolve.ResolveDep]struct{}{}
}
dstGraph[c] = struct{}{}
gm[p] = dstGraph
}
func graphMapToDepGraph(gm graphMap) DepGraph {
dg := DepGraph{}
for parent, childMap := range gm {
dg[parent] = []*resolve.ResolveDep{}
for child, _ := range childMap {
dg[parent] = append(dg[parent], child)
}
resolve.SortResolveDeps(dg[parent])
}
return dg
}
func depGraph(rs *resolve.ResolveSet) (DepGraph, error) {
graph := DepGraph{}
for _, parent := range rs.Rpkgs {
graph[parent] = []*resolve.ResolveDep{}
for _, dep := range parent.Deps {
graph[parent] = append(graph[parent], dep)
}
resolve.SortResolveDeps(graph[parent])
}
return graph, nil
}
func revdepGraph(rs *resolve.ResolveSet) (DepGraph, error) {
graph, err := depGraph(rs)
if err != nil {
return nil, err
}
revGm := graphMap{}
for parent, children := range graph {
// Make sure each node exists in the reverse graph. This step is
// necessary for packages that have no dependers.
graphMapEnsure(revGm, parent)
// Add nodes for packages with with dependers.
for _, child := range children {
rParent := child.Rpkg
rChild := *child
rChild.Rpkg = parent
graphMapAdd(revGm, rParent, &rChild)
}
}
return graphMapToDepGraph(revGm), nil
}
func depString(dep *resolve.ResolveDep) string {
s := fmt.Sprintf("%s", dep.Rpkg.Lpkg.FullName())
var reasons []string
if dep.Api != "" {
reasons = append(reasons, fmt.Sprintf("api:%s", dep.Api))
}
if dep.Expr != "" {
reasons = append(reasons, fmt.Sprintf("syscfg:%s", dep.Expr))
}
if len(reasons) > 0 {
s += fmt.Sprintf("(%s)", strings.Join(reasons, " "))
}
return s
}
func DepGraphText(graph DepGraph) string {
parents := make([]*resolve.ResolvePackage, 0, len(graph))
for lpkg, _ := range graph {
parents = append(parents, lpkg)
}
parents = resolve.SortResolvePkgs(parents)
buffer := bytes.NewBufferString("")
fmt.Fprintf(buffer, "Dependency graph (depender --> [dependees]):")
for _, parent := range parents {
children := resolve.SortResolveDeps(graph[parent])
fmt.Fprintf(buffer, "\n * %s --> [", parent.Lpkg.FullName())
for i, child := range children {
if i != 0 {
fmt.Fprintf(buffer, " ")
}
fmt.Fprintf(buffer, "%s", depString(child))
}
fmt.Fprintf(buffer, "]")
}
return buffer.String()
}
func RevdepGraphText(graph DepGraph) string {
parents := make([]*resolve.ResolvePackage, 0, len(graph))
for lpkg, _ := range graph {
parents = append(parents, lpkg)
}
parents = resolve.SortResolvePkgs(parents)
buffer := bytes.NewBufferString("")
fmt.Fprintf(buffer, "Reverse dependency graph (dependee <-- [dependers]):")
for _, parent := range parents {
children := resolve.SortResolveDeps(graph[parent])
fmt.Fprintf(buffer, "\n * %s <-- [", parent.Lpkg.FullName())
for i, child := range children {
if i != 0 {
fmt.Fprintf(buffer, " ")
}
fmt.Fprintf(buffer, "%s", depString(child))
}
fmt.Fprintf(buffer, "]")
}
return buffer.String()
}
// Extracts a new dependency graph containing only the specified parents.
//
// @param dg The source graph to filter.
// @param parents The parent nodes to keep.
//
// @return DepGraph Filtered dependency graph.
// []*ResolvePackage Specified packages that were not parents in
// original graph.
func FilterDepGraph(dg DepGraph, parents []*resolve.ResolvePackage) (
DepGraph, []*resolve.ResolvePackage) {
newDg := DepGraph{}
var missing []*resolve.ResolvePackage
for _, p := range parents {
if dg[p] == nil {
missing = append(missing, p)
} else {
newDg[p] = dg[p]
}
}
return newDg, missing
}