mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-05 05:20:34 +00:00
Merge pull request #475 from jola5/master
Support a vertical graph layout in addition to the existing horizontal
This commit is contained in:
@@ -24,3 +24,4 @@ List of contributors, in chronological order:
|
||||
* Geoffrey Thomas (https://github.com/geofft)
|
||||
* Oliver Sauder (https://github.com/sliverc)
|
||||
* Harald Sitter (https://github.com/apachelogger)
|
||||
* Johannes Layher (https://github.com/jola5)
|
||||
+3
-2
@@ -11,7 +11,7 @@ import (
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
// GET /api/graph.:ext
|
||||
// GET /api/graph.:ext?layout=[vertical|horizontal(default)]
|
||||
func apiGraph(c *gin.Context) {
|
||||
var (
|
||||
err error
|
||||
@@ -19,6 +19,7 @@ func apiGraph(c *gin.Context) {
|
||||
)
|
||||
|
||||
ext := c.Params.ByName("ext")
|
||||
layout := c.Request.URL.Query().Get("layout")
|
||||
|
||||
factory := context.CollectionFactory()
|
||||
|
||||
@@ -31,7 +32,7 @@ func apiGraph(c *gin.Context) {
|
||||
factory.PublishedRepoCollection().RLock()
|
||||
defer factory.PublishedRepoCollection().RUnlock()
|
||||
|
||||
graph, err := deb.BuildGraph(factory)
|
||||
graph, err := deb.BuildGraph(factory, layout)
|
||||
if err != nil {
|
||||
c.JSON(500, err)
|
||||
return
|
||||
|
||||
+5
-1
@@ -21,8 +21,11 @@ func aptlyGraph(cmd *commander.Command, args []string) error {
|
||||
return commander.ErrCommandError
|
||||
}
|
||||
|
||||
layout := context.Flags().Lookup("layout").Value.String()
|
||||
|
||||
fmt.Printf("Generating graph...\n")
|
||||
graph, err := deb.BuildGraph(context.CollectionFactory())
|
||||
graph, err := deb.BuildGraph(context.CollectionFactory(), layout)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -108,6 +111,7 @@ Example:
|
||||
|
||||
cmd.Flag.String("format", "png", "render graph to specified format (png, svg, pdf, etc.)")
|
||||
cmd.Flag.String("output", "", "specify output filename, default is to open result in viewer")
|
||||
cmd.Flag.String("layout", "horizontal", "create a more 'vertical' or a more 'horizontal' graph layout")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
+26
-9
@@ -7,13 +7,28 @@ import (
|
||||
)
|
||||
|
||||
// BuildGraph generates graph contents from aptly object database
|
||||
func BuildGraph(collectionFactory *CollectionFactory) (gographviz.Interface, error) {
|
||||
func BuildGraph(collectionFactory *CollectionFactory, layout string) (gographviz.Interface, error) {
|
||||
var err error
|
||||
|
||||
graph := gographviz.NewEscape()
|
||||
graph.SetDir(true)
|
||||
graph.SetName("aptly")
|
||||
|
||||
var labelStart string
|
||||
var labelEnd string
|
||||
|
||||
switch layout {
|
||||
case "vertical":
|
||||
graph.AddAttr("aptly", "rankdir", "LR")
|
||||
labelStart = ""
|
||||
labelEnd = ""
|
||||
case "horizontal":
|
||||
fallthrough
|
||||
default:
|
||||
labelStart = "{"
|
||||
labelEnd = "}"
|
||||
}
|
||||
|
||||
existingNodes := map[string]bool{}
|
||||
|
||||
err = collectionFactory.RemoteRepoCollection().ForEach(func(repo *RemoteRepo) error {
|
||||
@@ -26,9 +41,9 @@ func BuildGraph(collectionFactory *CollectionFactory) (gographviz.Interface, err
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "darkgoldenrod1",
|
||||
"label": fmt.Sprintf("{Mirror %s|url: %s|dist: %s|comp: %s|arch: %s|pkgs: %d}",
|
||||
repo.Name, repo.ArchiveRoot, repo.Distribution, strings.Join(repo.Components, ", "),
|
||||
strings.Join(repo.Architectures, ", "), repo.NumPackages()),
|
||||
"label": fmt.Sprintf("%sMirror %s|url: %s|dist: %s|comp: %s|arch: %s|pkgs: %d%s", labelStart, repo.Name, repo.ArchiveRoot,
|
||||
repo.Distribution, strings.Join(repo.Components, ", "),
|
||||
strings.Join(repo.Architectures, ", "), repo.NumPackages(), labelEnd),
|
||||
})
|
||||
existingNodes[repo.UUID] = true
|
||||
return nil
|
||||
@@ -48,8 +63,8 @@ func BuildGraph(collectionFactory *CollectionFactory) (gographviz.Interface, err
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "mediumseagreen",
|
||||
"label": fmt.Sprintf("{Repo %s|comment: %s|pkgs: %d}",
|
||||
repo.Name, repo.Comment, repo.NumPackages()),
|
||||
"label": fmt.Sprintf("%sRepo %s|comment: %s|pkgs: %d%s", labelStart,
|
||||
repo.Name, repo.Comment, repo.NumPackages(), labelEnd),
|
||||
})
|
||||
existingNodes[repo.UUID] = true
|
||||
return nil
|
||||
@@ -79,7 +94,8 @@ func BuildGraph(collectionFactory *CollectionFactory) (gographviz.Interface, err
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "cadetblue1",
|
||||
"label": fmt.Sprintf("{Snapshot %s|%s|pkgs: %d}", snapshot.Name, description, snapshot.NumPackages()),
|
||||
"label": fmt.Sprintf("%sSnapshot %s|%s|pkgs: %d%s", labelStart,
|
||||
snapshot.Name, description, snapshot.NumPackages(), labelEnd),
|
||||
})
|
||||
|
||||
if snapshot.SourceKind == "repo" || snapshot.SourceKind == "local" || snapshot.SourceKind == "snapshot" {
|
||||
@@ -102,8 +118,9 @@ func BuildGraph(collectionFactory *CollectionFactory) (gographviz.Interface, err
|
||||
"shape": "Mrecord",
|
||||
"style": "filled",
|
||||
"fillcolor": "darkolivegreen1",
|
||||
"label": fmt.Sprintf("{Published %s/%s|comp: %s|arch: %s}", repo.Prefix, repo.Distribution,
|
||||
strings.Join(repo.Components(), " "), strings.Join(repo.Architectures, ", ")),
|
||||
"label": fmt.Sprintf("%sPublished %s/%s|comp: %s|arch: %s%s", labelStart,
|
||||
repo.Prefix, repo.Distribution, strings.Join(repo.Components(), " "),
|
||||
strings.Join(repo.Architectures, ", "), labelEnd),
|
||||
})
|
||||
|
||||
for _, uuid := range repo.Sources {
|
||||
|
||||
@@ -270,6 +270,14 @@ class BaseTest(object):
|
||||
if a != b:
|
||||
self.verify_match(a, b, match_prepare=pprint.pformat)
|
||||
|
||||
def check_ge(self, a, b):
|
||||
if not a >= b:
|
||||
raise Exception("%s is not greater or equal to %s" % (a, b))
|
||||
|
||||
def check_gt(self, a, b):
|
||||
if not a > b:
|
||||
raise Exception("%s is not greater to %s" % (a, b))
|
||||
|
||||
def check_in(self, item, l):
|
||||
if not item in l:
|
||||
raise Exception("item %r not in %r", item, l)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from api_lib import APITest
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
class GraphAPITest(APITest):
|
||||
@@ -19,3 +20,28 @@ class GraphAPITest(APITest):
|
||||
resp = self.get("/api/graph.dot")
|
||||
self.check_equal(resp.headers["Content-Type"], "text/plain; charset=utf-8")
|
||||
self.check_equal(resp.content[:13], 'digraph aptly')
|
||||
|
||||
# basic test of layout:
|
||||
# horizontal should be wider than vertical
|
||||
# vertical should be higher than horizontal
|
||||
# for this to work we need at couple of repos
|
||||
tempRepos = [self.random_name() for r in range(3)]
|
||||
for repo in tempRepos:
|
||||
self.check_equal(self.post("/api/repos", json={"Name": repo, "Comment": "graph test repo"}).status_code, 201)
|
||||
|
||||
horizontal = self.get("/api/graph.svg?layout=horizontal").content
|
||||
vertical = self.get("/api/graph.svg?layout=vertical").content
|
||||
horizontalWidth = int(ET.fromstring(horizontal).get('width').replace("pt",""))
|
||||
horizontalHeight = int(ET.fromstring(horizontal).get('height').replace("pt",""))
|
||||
verticalWidth = int(ET.fromstring(vertical).get('width').replace("pt",""))
|
||||
verticalHeight = int(ET.fromstring(vertical).get('height').replace("pt",""))
|
||||
|
||||
self.check_gt(horizontalWidth, verticalWidth)
|
||||
self.check_gt(verticalHeight, horizontalHeight)
|
||||
|
||||
# make sure our default layout is horizontal
|
||||
self.check_equal(horizontal, self.get("/api/graph.svg").content)
|
||||
|
||||
# remove the repos again
|
||||
for repo in tempRepos:
|
||||
self.check_equal(self.delete("/api/repos/" + repo, params={"force": "1"}).status_code, 200)
|
||||
|
||||
Reference in New Issue
Block a user