@@ -0,0 +1,2814 @@
+#!/usr/bin/env python3%0A%0A# Copyright 2021 ETH Zurich%0A#%0A# Licensed under the Apache License, Version 2.0 (the %22License%22);%0A# you may not use this file except in compliance with the License.%0A# You may obtain a copy of the License at%0A#%0A#   http://www.apache.org/licenses/LICENSE-2.0%0A#%0A# Unless required by applicable law or agreed to in writing, software%0A# distributed under the License is distributed on an %22AS IS%22 BASIS,%0A# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A# See the License for the specific language governing permissions and%0A# limitations under the License.%0A%0Aimport pathlib%0Aimport sys%0Aimport tempfile%0Aimport yaml%0A%0Afrom plumbum import cli, local%0Afrom typing import Dict, List, NamedTuple%0A%0Afrom python.lib.types import LinkType%0Afrom python.topology.topo import LinkEP%0A%0A%0Aclass TopoDot(cli.Application):%0A    show = cli.Flag(%5B%22-s%22, %22--show%22%5D,%0A                    help=%22Run dot and show the graph, instead of only outputting the dot file.%22)%0A%0A    def main(self, topofile):%0A        if self.show:%0A            prefix = pathlib.PurePath(topofile).stem + '-'%0A            with tempfile.NamedTemporaryFile(prefix=prefix, suffix='.png') as tmp:%0A                dot = local%5B'dot'%5D%0A                xdg_open = local%5B'xdg-open'%5D%0A                p = dot.popen(('-Tpng', '-o', tmp.name), encoding='utf-8')%0A                p.stdin.write(topodot(topofile))%0A                p.communicate()%0A                xdg_open(tmp.name)%0A        else:%0A            sys.stdout.write(topodot(topofile))%0A%0A%0Aclass Link(NamedTuple):%0A    a: LinkEP%0A    b: LinkEP%0A    type: str%0A%0A%0Adef topodot(topofile) -%3E str:%0A    with open(topofile, 'r') as f:%0A        topo_config = yaml.safe_load(f)%0A    links = topo_links(topo_config)%0A    return 'digraph topo %7B%5Cn%25s%5Cn%7D%5Cn' %25 %5C%0A           '%5Cn'.join('%5Ct%22%25s%22 -%3E %22%25s%22%25s' %25%0A                     (link.a, link.b, fmt_attrs(link_attrs(link)))%0A                     for link in links)%0A%0A%0Adef fmt_attrs(attrs: Dict%5Bstr, str%5D) -%3E str:%0A    if attrs:%0A        return '%5B' + ';'.join('%25s=%25s' %25 (k, v) for k, v in attrs.items()) + '%5D'%0A    else:%0A        return ''%0A%0A%0Adef link_attrs(link: Link) -%3E Dict%5Bstr, str%5D:%0A    attrs = %7B%0A        'taillabel': link.a.ifid,%0A        'headlabel': link.b.ifid,%0A        'labelfontcolor': 'gray50',%0A        'labelfontsize': '10.0',%0A    %7D%0A    if link.type in %5BLinkType.CORE, LinkType.PEER%5D:%0A        attrs%5B'constraint'%5D = 'false'%0A        attrs%5B'dir'%5D = 'none'%0A    if link.type == LinkType.PEER:%0A        attrs%5B'constraint'%5D = 'false'%0A        attrs%5B'dir'%5D = 'none'%0A        attrs%5B'style'%5D = 'dotted'%0A    return attrs%0A%0A%0Adef topo_links(topo_config) -%3E List%5BLink%5D:%0A    return %5B%0A        Link(a=LinkEP(link%5B'a'%5D),%0A             b=LinkEP(link%5B'b'%5D),%0A             type=link%5B'linkAtoB'%5D.lower())%0A        for link in topo_config%5B'links'%5D%0A    %5D%0A%0A%0Aif __name__ == %22__main__%22:%0A    TopoDot.run()%0A

add topodot