prettyprinters/prettyprinter.go
// Copyright © 2016 Asteris, LLC
//
// Licensed 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 prettyprinters
import (
"bytes"
"strings"
"github.com/asteris-llc/converge/graph"
"golang.org/x/net/context"
)
// New creates a new prettyprinter instance from the specified
// DigraphPrettyPrinter instance.
func New(p BasePrinter) Printer {
return Printer{pp: p}
}
// Show will take the given graph and return a string representing the text
// output of the graph according to the associated prettyprinter. If an error
// is returned at any stage of the prettyprinting process it is returned
// unmodified to the user.
func (p Printer) Show(ctx context.Context, g *graph.Graph) (string, error) {
outputBuffer := new(bytes.Buffer)
write := func(s Renderable) { outputBuffer.WriteString(s.String()) }
subgraphs := makeSubgraphMap()
p.loadSubgraphs(ctx, g, subgraphs)
rootNodes := subgraphs[nil].Nodes
graphPrinter, gpOK := p.pp.(GraphPrinter)
if gpOK {
if str, err := graphPrinter.StartPP(g); err == nil {
outputBuffer.WriteString(str.String())
} else {
return "", err
}
}
nodePrinter, npOK := p.pp.(NodePrinter)
if npOK {
for _, node := range rootNodes {
if str, err := nodePrinter.DrawNode(g, node); err == nil {
if !strings.Contains(str.String(), "error in dependency") {
write(str)
}
} else {
return "", err
}
}
}
for graphID, graph := range subgraphs {
if graphID == SubgraphBottomID {
continue
}
if str, err := p.drawSubgraph(g, graphID, graph); err == nil {
write(str)
} else {
return "", err
}
}
if str, err := p.drawEdges(g); err == nil {
write(str)
} else {
return "", err
}
if gpOK {
if str, err := graphPrinter.FinishPP(g); err == nil {
write(str)
} else {
return "", err
}
}
return outputBuffer.String(), nil
}
func (p Printer) drawEdges(g *graph.Graph) (Renderable, error) {
edgePrinter, epOK := p.pp.(EdgePrinter)
edgeSectionPrinter, espOK := p.pp.(EdgeSectionPrinter)
if !epOK && !espOK {
return HiddenString(), nil
}
outputBuffer := new(bytes.Buffer)
write := func(s Renderable) { outputBuffer.WriteString(s.String()) }
edges := g.Edges()
if espOK {
if str, err := edgeSectionPrinter.StartEdgeSection(g); err == nil {
write(str)
} else {
return nil, err
}
}
if epOK {
for _, edge := range edges {
if str, err := edgePrinter.DrawEdge(g, edge.Source, edge.Dest); err == nil {
write(str)
} else {
return nil, err
}
}
}
if espOK {
if str, err := edgeSectionPrinter.FinishEdgeSection(g); err == nil {
write(str)
} else {
return nil, err
}
}
return outputBuffer, nil
}
// Printer is the top-level structure for a pretty printer.
type Printer struct {
pp BasePrinter
}