Example #1
0
        def make_varmgr(istoplevel=False):
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                #TODO dodgy, should be using context (look at syslseqs)
                if istoplevel:
                    template = 'state "{}" as X{}{} {{'
                else:
                    template = '  state "{}" as {}{}'
                    (_, _, name) = name.partition(' : ')

                app = module.apps[name]
                write(
                    template,
                    appfmt(appname=name,
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)
Example #2
0
def dataviews(module, args):
    """Generate a set of data views."""

    out = []

    parts = re.match(ur'^(.*?)(?:\s*<-\s*(.*?))?$', args.project)
    (appname, epname) = parts.groups()

    app = module.apps.get(appname)
    if epname is not None:
        endpts = [app.endpoints.get(epname)]
    else:
        endpts = app.endpoints.itervalues()

    out_fmt = diagutil.parse_fmt(args.output)

    for endpt in endpts:
        types = []

        for stmt in endpt.stmt:
            appname = stmt.action.action
            for (name, typespec) in module.apps.get(appname).types.iteritems():
                if typespec.WhichOneof('type') == 'tuple':
                    types.append((appname, name, typespec))

        args.output = out_fmt(appname=appname,
                              epname=endpt.name,
                              eplongname=endpt.long_name,
                              **diagutil.attr_fmt_vars(app.attrs, endpt.attrs))

        out.append(_generate_view(module, appname, types))

        diagutil.output_plantuml(args, out[-1])

    return out
Example #3
0
        def make_varmgr():
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                app = module.apps[name]
                write(
                    '[{}] as {}{}',
                    appfmt(appname=name_map.get(name, name),
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)
Example #4
0
def integration_views(module, deps, args):
    """Generate an integration view."""
    def find_matching_apps(integrations):
        """Yield all apps that match the integrations."""
        exclude = set(args.exclude)
        app_re = re.compile(r'^(?:{})(?: *::|$)'.format(
            '|'.join(integrations)))
        for ((app1, _), (app2, _)) in deps:
            if not ({app1, app2} & exclude):
                for app in [app1, app2]:
                    if app_re.match(app) and 'human' not in syslx.patterns(
                            module.apps[app].attrs):
                        yield app

    def find_apps(matching_apps):
        """Yield all apps that are relevant to this view."""
        exclude = set(args.exclude)
        for ((app1, _), (app2, _)) in deps:
            if not ({app1, app2} & exclude) and ({app1, app2} & matching_apps):
                for app in [app1, app2]:
                    if 'human' not in syslx.patterns(module.apps[app].attrs):
                        yield app

    out_fmt = diagutil.parse_fmt(args.output)

    # The "project" app that specifies the required view of the integrations
    app = module.apps[args.project]

    out = []

    # Interate over each endpoint within the selected project
    for endpt in app.endpoints.itervalues():

        # build the set of excluded items
        exclude_attr = endpt.attrs.get('exclude')
        exclude = set(e.s
                      for e in exclude_attr.a.elt) if exclude_attr else set()

        integrations = []

        # endpt.stmt's "action" will conatain the "apps" whose integration is to be drawn
        # each one of these will be placed into the "integrations" list
        for s in endpt.stmt:
            assert s.WhichOneof('stmt') == 'action', str(s)
            integrations.append(s.action.action)

        # include the requested "app" and all the apps upon which the requested "app"
        # depends in the app set
        matching_apps = set(find_matching_apps(integrations))
        apps = set(find_apps(matching_apps)) - exclude

        # the meaning of integrations is overloaded in this context: above it means
        # it is the list of apps whose integration is to be drawn, here it means the
        # actual integrations between the apps that are in the "apps" set and are not excluded
        def find_integrations():
            """Return all integrations between relevant apps."""
            return {((app1, ep1), (app2, ep2))
                    for ((app1, ep1), (app2, ep2)) in deps
                    if ({app1, app2} <= apps and not ({app1, app2} & exclude))
                    and not ({ep1, ep2} & {'.. * <- *'})}

        args.output = out_fmt(appname=args.project,
                              epname=endpt.name,
                              eplongname=endpt.long_name,
                              **diagutil.attr_fmt_vars(app.attrs, endpt.attrs))

        if args.filter and not re.match(args.filter, args.output):
            continue

        print args.project, matching_apps
        out.append(
            _generate_view(module, args, find_integrations(), matching_apps,
                           app, apps, endpt))

        diagutil.output_plantuml(args, out[-1])

    return out
Example #5
0
def _generate_view(module, args, integrations, highlights, app, apps, endpt):
    write = writer.Writer('plantuml')
    """Output integration view"""

    app_attrs = syslx.View(app.attrs)
    endpt_attrs = syslx.View(endpt.attrs)
    highlight_color = app_attrs['highlight_color'].s
    arrow_color = app_attrs['arrow_color'].s
    indirect_arrow_color = app_attrs['indirect_arrow_color'].s

    diagram_title = ''
    if (app_attrs['title'].s or args.title):
        fmtfn = diagutil.parse_fmt(app_attrs['title'].s or args.title)
        diagram_title = fmtfn(epname=endpt.name, eplongname=endpt.long_name)

    def generate_component_view():

        name_map = {}

        def make_varmgr():
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                app = module.apps[name]
                write(
                    '[{}] as {}{}',
                    appfmt(appname=name_map.get(name, name),
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)

        with write.uml():

            if diagram_title:
                write('title ' + diagram_title)

            write('hide stereotype')
            write('scale max 16384 height')
            write('skinparam linetype ortho')
            write('skinparam component {{')
            write('  BackgroundColor FloralWhite')
            write('  BorderColor Black')
            write('  ArrowColor Crimson')
            if highlight_color:
                write('  BackgroundColor<<highlight>> ' + highlight_color)
            if arrow_color:
                write('  ArrowColor ' + arrow_color)
            if indirect_arrow_color and indirect_arrow_color != 'none':
                write('  ArrowColor<<indirect>> ' + indirect_arrow_color)
            write('}}')

            var_name = make_varmgr()

            if args.clustered or endpt_attrs['view'].s == 'clustered':
                clusters = diagutil.group_by(
                    apps, key=lambda app: app.partition(' :: ')[0])
                clusters = [(cluster, members) for (cluster, g) in clusters
                            for members in [list(g)] if len(members) > 1]
                name_map = {
                    app: app.partition(' :: ')[-1] or app
                    for (cluster, members) in clusters for app in members
                }
                for (cluster, cluster_apps) in clusters:
                    write('package "{}" {{', cluster)
                    for app in cluster_apps:
                        var_name(app)
                        # write('  {}', var_name(app))
                    write('}}')

            calls_drawn = set()

            if endpt_attrs['view'].s == 'system':
                for ((app_a, _), (app_b, _)) in integrations:
                    direct = {app_a, app_b} & highlights
                    app_a = app_a.partition(' :: ')[0]
                    app_b = app_b.partition(' :: ')[0]
                    if app_a != app_b and (app_a, app_b) not in calls_drawn:
                        if direct or indirect_arrow_color != 'none':
                            write('{} --> {}{}', var_name(app_a),
                                  var_name(app_b),
                                  '' if direct else ' <<indirect>>')
                            calls_drawn.add((app_a, app_b))
            else:
                for ((app_a, _), (app_b, _)) in integrations:
                    if app_a != app_b and (app_a, app_b) not in calls_drawn:
                        direct = {app_a, app_b} & highlights
                        if direct or indirect_arrow_color != 'none':
                            write('{} --> {}{}', var_name(app_a),
                                  var_name(app_b),
                                  '' if direct else ' <<indirect>>')
                            calls_drawn.add((app_a, app_b))

                for appname in apps:
                    for mixin in module.apps[appname].mixin2:
                        mixin_name = syslx.fmt_app_name(mixin.name)
                        mixin_app = module.apps[mixin_name]
                        write('{} <|.. {}', var_name(mixin_name),
                              var_name(appname))

    #TODO Some serious refactoring
    def generate_state_view():
        def make_varmgr(istoplevel=False):
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                #TODO dodgy, should be using context (look at syslseqs)
                if istoplevel:
                    template = 'state "{}" as X{}{} {{'
                else:
                    template = '  state "{}" as {}{}'
                    (_, _, name) = name.partition(' : ')

                app = module.apps[name]
                write(
                    template,
                    appfmt(appname=name,
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)

        def yield_call_statements(statements):
            for (_, stmt) in enumerate(statements):
                field = stmt.WhichOneof('stmt')
                if field == 'call':
                    yield stmt
                elif field == 'alt':
                    for (_, choice) in enumerate(stmt.alt.choice):
                        for next_stmt in yield_call_statements(choice.stmt):
                            yield next_stmt
                elif field in {'cond', 'loop', 'loop_n', 'foreach', 'group'}:
                    for next_stmt in yield_call_statements(
                            getattr(stmt, field).stmt):
                        yield next_stmt

        with write.uml():

            if diagram_title:
                write('title ' + diagram_title)

            write('left to right direction')
            write('scale max 16384 height')
            write('skinparam nodesep 10')
            #TODO[kirkpatg]: this should probably scale up & down based on nodes & connections
            write('skinparam ranksep 300')
            #write('skinparam linetype polyline')
            write('hide empty description')
            write('skinparam state {{')
            write('  BackgroundColor FloralWhite')
            write('  BorderColor Black')
            write('  ArrowColor Crimson')
            if highlight_color:
                write('  BackgroundColor<<highlight>> ' + highlight_color)
            if arrow_color:
                write('  ArrowColor ' + arrow_color)
            if indirect_arrow_color and indirect_arrow_color != 'none':
                write('  ArrowColor<<indirect>> ' + indirect_arrow_color)
                write('  ArrowColor<<internal>> ' + indirect_arrow_color)
            write('}}')

            var_name = make_varmgr()
            tl_var_name = make_varmgr(True)

            clusters = {}

            # group end points and build the declarations
            for (app_a, ep_a), (app_b, ep_b) in integrations:
                if app_a not in clusters: clusters[app_a] = set()
                if app_b not in clusters: clusters[app_b] = set()

                # create clients in the calling app
                clusters[app_a].add(ep_a)
                if app_a != app_b and not module.apps[app_a].endpoints[
                        ep_a].is_pubsub:
                    clusters[app_a].add(ep_b + " client")

                clusters[app_b].add(ep_b)

            for cluster in clusters:
                tl_var_name(cluster)
                for member in clusters[cluster]:
                    var_name(cluster + ' : ' + member)
                write('}}')

            processed = []
            for ((app_a, ep_a), (app_b, ep_b)) in integrations:
                direct = {app_a, app_b} & highlights

                # build the label
                label = ''
                needs_int = app_a != app_b
                # if 'App1 Event' in ep_a: import pdb; pdb.set_trace()

                # import pdb; pdb.set_trace()
                for stmt in yield_call_statements(
                        module.apps[app_a].endpoints[ep_a].stmt):

                    app_b_name = ' :: '.join(part
                                             for part in stmt.call.target.part)

                    if app_b == app_b_name and ep_b == stmt.call.endpoint:
                        fmt_vars = diagutil.attr_fmt_vars(stmt.attrs)
                        ptrns = syslx.patterns(
                            module.apps[app_b].endpoints[ep_b].attrs)
                        label = diagutil.parse_fmt(app.attrs["epfmt"].s)(
                            needs_int=needs_int,
                            patterns=', '.join(sorted(ptrns)),
                            **fmt_vars)
                        break

                flow = ".".join([app_a, ep_b, app_b, ep_b])
                is_pubsub = module.apps[app_a].endpoints[ep_a].is_pubsub
                ep_b_client = ep_b + " client"
                if app_a != app_b:
                    if is_pubsub:
                        write('{} -{}> {}{}', var_name(app_a + ' : ' + ep_a),
                              '[#black]', var_name(app_b + ' : ' + ep_b),
                              ' : ' + label if label else '')
                    else:
                        write(
                            '{} -{}> {}', var_name(app_a + ' : ' + ep_a),
                            '[#' + indirect_arrow_color +
                            ']-' if indirect_arrow_color else '[#silver]-',
                            var_name(app_a + ' : ' + ep_b_client))
                        if flow not in processed:
                            write('{} -{}> {}{}',
                                  var_name(app_a + ' : ' + ep_b_client),
                                  '[#black]', var_name(app_b + ' : ' + ep_b),
                                  ' : ' + label if label else '')
                            processed.append(flow)

                else:
                    write(
                        '{} -{}> {}{}', var_name(app_a + ' : ' + ep_a),
                        '[#' + indirect_arrow_color +
                        ']-' if indirect_arrow_color else '[#silver]-',
                        var_name(app_b + ' : ' + ep_b),
                        ' : ' + label if label else '')

    if (args.epa) or endpt_attrs['view'].s == 'epa':
        generate_state_view()
    else:
        generate_component_view()

    return str(write)
Example #6
0
    def generate_state_view():
        def make_varmgr(istoplevel=False):
            """Return a variable manager instance."""
            appfmt = syslx.View(module.apps.get(
                args.project).attrs)['appfmt'].s
            appfmt = diagutil.parse_fmt(appfmt)

            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                #TODO dodgy, should be using context (look at syslseqs)
                if istoplevel:
                    template = 'state "{}" as X{}{} {{'
                else:
                    template = '  state "{}" as {}{}'
                    (_, _, name) = name.partition(' : ')

                app = module.apps[name]
                write(
                    template,
                    appfmt(appname=name,
                           **diagutil.attr_fmt_vars(app.attrs)).replace(
                               '\n', r'\n'), var,
                    ' <<highlight>>' if name in highlights else '')

            return diagutil.VarManager(new_var)

        def yield_call_statements(statements):
            for (_, stmt) in enumerate(statements):
                field = stmt.WhichOneof('stmt')
                if field == 'call':
                    yield stmt
                elif field == 'alt':
                    for (_, choice) in enumerate(stmt.alt.choice):
                        for next_stmt in yield_call_statements(choice.stmt):
                            yield next_stmt
                elif field in {'cond', 'loop', 'loop_n', 'foreach', 'group'}:
                    for next_stmt in yield_call_statements(
                            getattr(stmt, field).stmt):
                        yield next_stmt

        with write.uml():

            if diagram_title:
                write('title ' + diagram_title)

            write('left to right direction')
            write('scale max 16384 height')
            write('skinparam nodesep 10')
            #TODO[kirkpatg]: this should probably scale up & down based on nodes & connections
            write('skinparam ranksep 300')
            #write('skinparam linetype polyline')
            write('hide empty description')
            write('skinparam state {{')
            write('  BackgroundColor FloralWhite')
            write('  BorderColor Black')
            write('  ArrowColor Crimson')
            if highlight_color:
                write('  BackgroundColor<<highlight>> ' + highlight_color)
            if arrow_color:
                write('  ArrowColor ' + arrow_color)
            if indirect_arrow_color and indirect_arrow_color != 'none':
                write('  ArrowColor<<indirect>> ' + indirect_arrow_color)
                write('  ArrowColor<<internal>> ' + indirect_arrow_color)
            write('}}')

            var_name = make_varmgr()
            tl_var_name = make_varmgr(True)

            clusters = {}

            # group end points and build the declarations
            for (app_a, ep_a), (app_b, ep_b) in integrations:
                if app_a not in clusters: clusters[app_a] = set()
                if app_b not in clusters: clusters[app_b] = set()

                # create clients in the calling app
                clusters[app_a].add(ep_a)
                if app_a != app_b and not module.apps[app_a].endpoints[
                        ep_a].is_pubsub:
                    clusters[app_a].add(ep_b + " client")

                clusters[app_b].add(ep_b)

            for cluster in clusters:
                tl_var_name(cluster)
                for member in clusters[cluster]:
                    var_name(cluster + ' : ' + member)
                write('}}')

            processed = []
            for ((app_a, ep_a), (app_b, ep_b)) in integrations:
                direct = {app_a, app_b} & highlights

                # build the label
                label = ''
                needs_int = app_a != app_b
                # if 'App1 Event' in ep_a: import pdb; pdb.set_trace()

                # import pdb; pdb.set_trace()
                for stmt in yield_call_statements(
                        module.apps[app_a].endpoints[ep_a].stmt):

                    app_b_name = ' :: '.join(part
                                             for part in stmt.call.target.part)

                    if app_b == app_b_name and ep_b == stmt.call.endpoint:
                        fmt_vars = diagutil.attr_fmt_vars(stmt.attrs)
                        ptrns = syslx.patterns(
                            module.apps[app_b].endpoints[ep_b].attrs)
                        label = diagutil.parse_fmt(app.attrs["epfmt"].s)(
                            needs_int=needs_int,
                            patterns=', '.join(sorted(ptrns)),
                            **fmt_vars)
                        break

                flow = ".".join([app_a, ep_b, app_b, ep_b])
                is_pubsub = module.apps[app_a].endpoints[ep_a].is_pubsub
                ep_b_client = ep_b + " client"
                if app_a != app_b:
                    if is_pubsub:
                        write('{} -{}> {}{}', var_name(app_a + ' : ' + ep_a),
                              '[#black]', var_name(app_b + ' : ' + ep_b),
                              ' : ' + label if label else '')
                    else:
                        write(
                            '{} -{}> {}', var_name(app_a + ' : ' + ep_a),
                            '[#' + indirect_arrow_color +
                            ']-' if indirect_arrow_color else '[#silver]-',
                            var_name(app_a + ' : ' + ep_b_client))
                        if flow not in processed:
                            write('{} -{}> {}{}',
                                  var_name(app_a + ' : ' + ep_b_client),
                                  '[#black]', var_name(app_b + ' : ' + ep_b),
                                  ' : ' + label if label else '')
                            processed.append(flow)

                else:
                    write(
                        '{} -{}> {}{}', var_name(app_a + ' : ' + ep_a),
                        '[#' + indirect_arrow_color +
                        ']-' if indirect_arrow_color else '[#silver]-',
                        var_name(app_b + ' : ' + ep_b),
                        ' : ' + label if label else '')
Example #7
0
    def cmd(args):
        """Handle subcommand."""
        (module, _, _) = syslloader.load(args.modules, args.validations,
                                         args.root)

        def output_sd(args, params):
            """Generate and output a sequence diagram."""
            # pdb.set_trace()
            out = sequence_diag(module, params)

            diagutil.output_plantuml(args, out)

        epfilters = os.getenv('SYSL_SD_FILTERS', '*').split(',')

        # TODO: Find a cleaner way to trigger multi-output.
        if '%(epname)' in args.output:
            out_fmt = diagutil.parse_fmt(args.output)
            for appname in args.app:
                app = module.apps[appname]

                bbs = [[e.s for e in bbox.a.elt]
                       for bbox in syslx.View(app.attrs)['blackboxes'].a.elt]

                seqtitle = diagutil.parse_fmt(
                    syslx.View(app.attrs)['seqtitle'].s or args.seqtitle)
                epfmt = diagutil.parse_fmt(
                    syslx.View(app.attrs)['epfmt'].s or args.endpoint_format)
                appfmt = diagutil.parse_fmt(
                    syslx.View(app.attrs)['appfmt'].s or args.app_format)

                for (name, endpt) in sorted(app.endpoints.iteritems(),
                                            key=lambda kv: kv[1].name):
                    if not any(
                            fnmatch.fnmatch(name, filt) for filt in epfilters):
                        continue

                    attrs = {
                        u'@' + name: value.s
                        for (name, value) in endpt.attrs.iteritems()
                    }
                    args.output = out_fmt(appname=appname,
                                          epname=name,
                                          eplongname=endpt.long_name,
                                          **attrs)

                    if args.filter and not re.match(args.filter, args.output):
                        continue

                    bbs2 = [[
                        e.s for e in bbox.a.elt
                    ] for bbox in syslx.View(endpt.attrs)['blackboxes'].a.elt]

                    varrefs = diagutil.attr_fmt_vars(
                        app.attrs,
                        endpt.attrs,
                        epname=endpt.name,
                        eplongname=endpt.long_name)

                    out = sequence_diag(
                        module,
                        SequenceDiagParams(endpoints=[
                            ' :: '.join(s.call.target.part) + ' <- ' +
                            s.call.endpoint for s in endpt.stmt
                            if s.WhichOneof('stmt') == 'call'
                        ],
                                           epfmt=epfmt,
                                           appfmt=appfmt,
                                           activations=args.activations,
                                           title=seqtitle(**varrefs).replace(
                                               '\n', r'\n'),
                                           blackboxes=bbs + bbs2))
                    diagutil.output_plantuml(args, out)

        else:
            out = sequence_diag(
                module,
                SequenceDiagParams(
                    endpoints=[i[0] for i in args.endpoint
                               ],  # -s builds list of lists (idkw).
                    epfmt=diagutil.parse_fmt(args.endpoint_format),
                    appfmt=diagutil.parse_fmt(args.app_format),
                    activations=args.activations,
                    title=args.title,
                    blackboxes=args.blackboxes))
            diagutil.output_plantuml(args, out)