grim/convey

closing closed branch again
multiple-images
2018-01-26, Gary Kramlich
8e45b1f8ccff
closing closed branch again
/*
* Convey
* Copyright 2016-2017 Gary Kramlich <grim@reaperworld.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package runners
import (
"bytes"
"fmt"
"regexp"
"text/template"
"bitbucket.org/rw_grim/convey/color"
"bitbucket.org/rw_grim/convey/config"
"bitbucket.org/rw_grim/convey/logging"
"bitbucket.org/rw_grim/convey/options"
)
var graphvizTemplate = `
digraph {
graph[rankdir="LR"]
node[style="filled,rounded" shape="rect" fillcolor="powderblue"]
{{range .Tasks}} {{.Normalized}}[label="{{.Name}}"]
{{end}}
{{range .Plans}} edge[color="{{.Color}}"]{{$planNormalized := .Normalized }}
{{.Normalized}}_start[label="{{.Name}}" fillcolor="palegreen" shape="rect"]
{{range .Stages}}{{$planNormalized}}_{{.Normalized}} [label="{{.Name}}" shape="octagon" fillcolor="lightpink1"]
{{end}}
{{.Normalized}}_start{{range .Stages}} -> {{$planNormalized}}_{{.Normalized}}{{if .Concurrent}} -> { {{range .Tasks}} {{.}} {{end}} }{{else}}{{range .Tasks}} -> {{.}}{{end}}{{end}}{{end}}
{{/*add the fall throughs */}}
{{- range .Stages}}{{$stage := .}}{{range .FallThroughs}}{{$planNormalized}}_{{$stage.Normalized}} -> {{$planNormalized}}_{{.Normalized}} [style="dotted"]
{{end}}{{end -}}
{{- end}}
}
`
var normalizeRegex *regexp.Regexp
type (
Graphviz struct{}
GraphvizTask struct {
Normalized string
Name string
}
GraphvizStage struct {
Normalized string
Name string
Concurrent bool
Always bool
Tasks []string
FallThroughs []GraphvizStage
}
GraphvizPlan struct {
Normalized string
Name string
Color string
Stages []GraphvizStage
}
)
func normalize(str string) string {
if normalizeRegex == nil {
normalizeRegex = regexp.MustCompile("[^a-zA-Z0-9_]")
}
return normalizeRegex.ReplaceAllString(str, "_")
}
func (g *Graphviz) getTasks(cfg *config.Config) []GraphvizTask {
tasks := []GraphvizTask{}
for name, _ := range cfg.Tasks {
task := GraphvizTask{
Normalized: normalize(name),
Name: name,
}
tasks = append(tasks, task)
}
return tasks
}
func (g *Graphviz) getPlans(cfg *config.Config) []GraphvizPlan {
plans := []GraphvizPlan{}
for name, plan := range cfg.Plans {
graphvizPlan := GraphvizPlan{
Normalized: normalize(name),
Name: name,
Color: color.X11(name),
Stages: []GraphvizStage{},
}
for idx, stage := range plan.Stages {
graphvizStage := GraphvizStage{
Normalized: normalize(stage.Name),
Name: stage.Name,
Concurrent: stage.Concurrent,
Always: stage.Always,
Tasks: []string{},
}
for _, task := range stage.Tasks {
graphvizStage.Tasks = append(graphvizStage.Tasks, normalize(task))
}
graphvizPlan.Stages = append(graphvizPlan.Stages, graphvizStage)
// if this always runs, if it's not the first add it to the previous stage's fallthroughs
if stage.Always && idx > 0 {
graphvizPlan.Stages[idx-1].FallThroughs = append(graphvizPlan.Stages[idx-1].FallThroughs, graphvizStage)
}
}
plans = append(plans, graphvizPlan)
}
return plans
}
func (g *Graphviz) Run(cfg *config.Config, plans []string, env []string, opts *options.Options) int {
logger := logging.NewAdapter("graphviz")
params := map[string]interface{}{
"Tasks": g.getTasks(cfg),
"Plans": g.getPlans(cfg),
}
// Load the template
tmpl, err := template.New("graphviz").Parse(graphvizTemplate)
if err != nil {
logger.Fatalf("error: %s", err)
return 1
}
// Run the template
output := new(bytes.Buffer)
err = tmpl.Execute(output, params)
if err != nil {
logger.Fatalf("error: %s", err)
return 1
}
// Output the template
fmt.Print(output)
return 0
}