grim/convey
Clone
Summary
Browse
Changes
Graph
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
}