Пример #1
0
    def new_var(var, appname):
        """Outputs a new definition when VarManager makes a new variable."""

        app = module.apps[appname]
        has_category = syslx.patterns(
            app.attrs) & {'human', 'cron', 'db', 'external', 'ui'}
        assert len(has_category) <= 1
        (order, agent) = {
            'human': (0, 'actor'),
            'ui': (1, 'boundary'),
            'cron': (2, 'control'),
            'db': (4, 'database'),
            'external': (5, 'control'),
        }.get(''.join(has_category), (3, 'control'))

        isoctrl = []

        for ctrl in app.attrs.keys():
            if 'iso_ctrl' in ctrl:
                isoctrl.append(re.sub(r'iso_ctrl_(.*)_txt', r'\1', ctrl))

        label = params.appfmt(appname=appname,
                              controls=', '.join(i for i in sorted(isoctrl)),
                              **diagutil.attr_fmt_vars(app.attrs)).replace(
                                  u'\n', ur'\n')
        var_names.append(
            ((order, int(var[1:])), u'{} "{}" as {}'.format(agent, label,
                                                            var)))
Пример #2
0
    def new_var(var, appname):
        """Outputs a new definition when VarManager makes a new variable."""

        app = module.apps[appname]
        has_category = syslx.patterns(app.attrs) & {
            'human', 'cron', 'db', 'external', 'ui'}
        assert len(has_category) <= 1
        (order, agent) = {
            'human': (0, 'actor'),
            'ui': (1, 'boundary'),
            'cron': (2, 'control'),
            'db': (4, 'database'),
            'external': (5, 'control'),
        }.get(
            ''.join(has_category),
            (3, 'control'))

        isoctrl = []

        for ctrl in app.attrs.keys():
            if 'iso_ctrl' in ctrl:
                isoctrl.append(re.sub(r'iso_ctrl_(.*)_txt', r'\1', ctrl))

        label = params.appfmt(
            appname=appname,
            controls=', '.join(i for i in sorted(isoctrl)),
            **diagutil.attr_fmt_vars(app.attrs)
        ).replace(u'\n', ur'\n')
        var_names.append(
            ((order, int(var[1:])), u'{} "{}" as {}'.format(agent, label, var)))
Пример #3
0
            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 '')
Пример #4
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 not app:
        raise Exception('Invalid project "{}"'.format(args.project))
    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
            if not module.apps.get(appname):
                continue
            for (name, typespec) in module.apps.get(appname).types.iteritems():
                if typespec.WhichOneof(
                        'type') == 'relation' or 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))

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

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

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

    return out
Пример #5
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 not app:
        raise Exception('Invalid project "{}"'.format(args.project))
    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
            if not module.apps.get(appname):
                continue
            for (name, typespec) in module.apps.get(appname).types.iteritems():
                if typespec.WhichOneof('type') == 'relation' or 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))

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

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

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

    return out
Пример #6
0
            def new_var(var, name):
                """Outputs a new definition when VarManager makes a new variable."""

                # TODO dodgy, should be using context (look at syslseqs)
                attrs = {}
                state_name = ''

                if istoplevel:
                    template = 'state "{}" as X{}{} {{'
                    attrs = module.apps[name].attrs
                    state_name = name
                else:
                    template = '  state "{}" as {}{}'
                    (app_name, _, ep_name) = name.partition(' : ')
                    attrs = module.apps[app_name].endpoints[ep_name].attrs
                    state_name = ep_name

                write(template,
                      appfmt(appname=state_name,
                             **diagutil.attr_fmt_vars(attrs)).replace('\n', r'\n'),
                      var,
                      ' <<highlight>>' if name in highlights else '')
Пример #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."""
            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:
            if not args.endpoint:
                raise Exception(
                    'sysl sd requires either one specific endpoint, ' +
                    'e.g. --endpoint "ATM <- GetBalance", or an output ' +
                    'pattern with %(epname), e.g. -o "out/%(epname).svg".')
            out = sequence_diag(module, SequenceDiagParams(
                # -s builds list of lists (idkw).
                endpoints=args.endpoint,
                epfmt=diagutil.parse_fmt(args.endpoint_format),
                appfmt=diagutil.parse_fmt(args.app_format),
                activations=args.activations,
                title=args.title,
                blackboxes=args.blackbox))
            diagutil.output_plantuml(args, out)
Пример #8
0
    def visit_endpoint(
            from_app,
            appname,
            epname,
            uptos,
            sender_patterns,
            sender_endpt_patterns=None,
            stmt=None,
            deactivate=None):
        """Recursively visit an endpoint."""
        if from_app:
            sender = var_name(syslx.fmt_app_name(from_app.name))
        else:
            sender = '['
        agent = var_name(appname)
        app = module.apps.get(appname)
        endpt = app.endpoints.get(epname)
        assert endpt

        def visit_stmts(stmts, deactivate, last_parent_stmt):
            """Recursively visit a stmt list."""
            def block(last_stmt, block_stmts, fmt, *args):
                """Output a compound block."""
                write(fmt, *args)
                with write.indent():
                    return visit_stmts(block_stmts, deactivate, last_stmt)

            def block_with_end(last_stmt, block_stmts, fmt, *args):
                """Output a compound block, including the 'end' clause."""
                payload = block(last_stmt, block_stmts, fmt, *args)
                write('end')
                return payload

            payload = None

            for (i, stmt) in enumerate(stmts):
                last_stmt = last_parent_stmt and i == len(stmts) - 1
                if stmt.HasField('call'):
                    with write.indent():
                        payload = visit_endpoint(
                            app,
                            syslx.fmt_app_name(stmt.call.target),
                            stmt.call.endpoint,
                            uptos,
                            app_patterns,
                            syslx.patterns(stmt.attrs) | syslx.patterns(
                                endpt.attrs),
                            stmt,
                            last_stmt and deactivate)
                elif stmt.HasField('action'):
                    #write('{0} -> {0} : {1}', agent, r'\n'.join(textwrap.wrap(stmt.action.action, 40)))
                    write('{0} -> {0} : {1}', agent, stmt.action.action)
                elif stmt.HasField('cond'):
                    payload = block_with_end(last_stmt, stmt.cond.stmt,
                                             'opt {}',
                                             stmt.cond.test)
                elif stmt.HasField('loop'):
                    payload = block_with_end(last_stmt, stmt.loop.stmt,
                                             'loop {} {}',
                                             stmt.loop.Mode.Name(
                                                 stmt.loop.mode),
                                             stmt.loop.criterion)
                elif stmt.HasField('loop_n'):
                    payload = block_with_end(last_stmt, stmt.loop_n.stmt,
                                             'loop {} times',
                                             stmt.loop_n.count)
                elif stmt.HasField('foreach'):
                    payload = block_with_end(last_stmt, stmt.foreach.stmt,
                                             'loop for each {}',
                                             stmt.foreach.collection)
                elif stmt.HasField('group'):
                    payload = block_with_end(last_stmt, stmt.group.stmt,
                                             'group {}',
                                             stmt.group.title)
                elif stmt.HasField('alt'):
                    prefix = 'alt'
                    for (j, choice) in enumerate(stmt.alt.choice):
                        last_alt_stmt = last_stmt and j == len(
                            stmt.alt.choice) - 1
                        payload = block(last_alt_stmt, choice.stmt,
                                        '{} {}', prefix, choice.cond)
                        prefix = 'else'
                    write('end')
                elif stmt.HasField('ret'):
                    rargs = []

                    for param in syslalgo.yield_ret_params(stmt.ret.payload):
                        if param != '...' and '.' in param:
                            (an, pn) = rex.split(r'\.', param)

                            rarg = format_args(an, pn)

                            if rarg:
                                rargs.append(rarg)
                        else:
                            rargs.append(param)

                    write('{}<--{} : {}', sender, agent,
                          ' | '.join(p for p in rargs))
                else:
                    raise Exception('No statement!')

            return payload

        app_patterns = syslx.patterns(app.attrs)
        target_patterns = syslx.patterns(endpt.attrs)

        patterns = target_patterns

        human = 'human' in app_patterns
        human_sender = 'human' in sender_patterns
        cron = 'cron' in sender_patterns
        needs_int = not (human or human_sender or cron) and sender != agent
        label = re.sub(ur'^.*? -> ', u' ⬄ ', unicode(epname))

        cron = 'cron' in app_patterns

        if stmt:
            assert stmt.HasField('call')

            ptrns = ''
            if bool(sender_endpt_patterns) or bool(patterns):
                ptrns = u', '.join(sorted(sender_endpt_patterns)) + \
                    u' → ' + u', '.join(sorted(patterns))

            isoctrl = []

            for ctrl in endpt.attrs.keys():
                if 'iso_ctrl' in ctrl:
                    isoctrl.append(re.sub(r'iso_ctrl_(.*)_txt', r'\1', ctrl))

            epargs = []

            def format_args(an, pn):
                arg = '.'.join((an, pn))

                if arg:
                    conf = module.apps[an].types[pn].attrs['iso_conf'].s[:1].upper(
                    )
                    integ = module.apps[an].types[pn].attrs['iso_integ'].s[:1].upper(
                    )
                    isocolor = 'red' if 'R' in conf else 'green'
                    arg = '<color blue>' + arg + '</color>' + ' <<color ' + isocolor + '>' + \
                        (conf if conf else '?') + ', ' + \
                        (integ if integ else '?') + '</color>>'

                return arg

            for p in endpt.param:
                an = ' :: '.join(p.type.type_ref.ref.appname.part)
                pn = '.'.join(p.type.type_ref.ref.path)

                eparg = format_args(an, pn)

                if eparg:
                    epargs.append(eparg)

            label = params.epfmt(
                epname=label,
                human='human' if human else '',
                human_sender='human sender' if human_sender else '',
                needs_int='needs_int' if needs_int else '',
                args=' | '.join(e for e in epargs),
                #args=', '.join(p.name for p in stmt.call.arg),
                patterns=ptrns,
                controls=', '.join(i for i in sorted(isoctrl)),
                **diagutil.attr_fmt_vars(stmt.attrs)
            ).replace('\n', r'\n')

        if not ((human and sender == '[') or cron):
            ep_patterns = syslx.patterns(endpt.attrs)

            icon = '<&timer> ' if 'cron' in ep_patterns else ''
            write('{}->{} : {}{}', sender, agent, icon, label)
            if log_integration and stmt:
                log_integration(app=from_app, stmt=stmt, patterns=patterns)

        rargs = []

        for param in syslalgo.yield_ret_params(
                syslalgo.return_payload(endpt.stmt)):
            if param != '...' and '.' in param:
                (an, pn) = rex.split(r'\.', param)

                rarg = format_args(an, pn)

                if rarg:
                    rargs.append(rarg)
            else:
                rargs.append(param)

        payload = ' | '.join(p for p in rargs)

        calling_self = from_app and syslx.fmt_app_name(
            from_app.name) == appname
        if not calling_self and not payload and deactivate:
            deactivate()

        if len(endpt.stmt):
            hit_blackbox = False
            for (upto, comment) in itertools.chain(
                    uptos.iteritems(), already_visited.keys()):
                # Compare the common prefix of the current endpt and upto.
                upto_parts = upto.split(' <- ')
                if [appname, epname][:len(upto_parts)] == upto_parts:
                    hit_blackbox = True
                    if payload:
                        write.activate(agent)
                        if comment is not None:
                            write('note over {}: {}', agent,
                                  comment or 'see below')
                    else:
                        if comment is not None:
                            write('note {}: {}',
                                  'left' if sender > agent else 'right',
                                  comment or 'see below')
                    if payload:
                        write('{}<--{} : {}', sender, agent, payload)
                        write.deactivate(agent)
                    break

            if not hit_blackbox:
                with write.activated(agent, human or cron) as deactivate:
                    # 'see above')
                    visiting = (appname + ' <- ' + epname, None)
                    already_visited[visiting] += 1
                    try:
                        return visit_stmts(endpt.stmt, deactivate, True)
                    finally:
                        already_visited[visiting] -= 1
                        if not already_visited[visiting]:
                            del already_visited[visiting]
Пример #9
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."""
            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:
            if not args.endpoint:
                raise Exception(
                    'sysl sd requires either one specific endpoint, ' +
                    'e.g. --endpoint "ATM <- GetBalance", or an output ' +
                    'pattern with %(epname), e.g. -o "out/%(epname).svg".')
            out = sequence_diag(
                module,
                SequenceDiagParams(
                    # -s builds list of lists (idkw).
                    endpoints=args.endpoint,
                    epfmt=diagutil.parse_fmt(args.endpoint_format),
                    appfmt=diagutil.parse_fmt(args.app_format),
                    activations=args.activations,
                    title=args.title,
                    blackboxes=args.blackbox))
            diagutil.output_plantuml(args, out)
Пример #10
0
    def visit_endpoint(from_app,
                       appname,
                       epname,
                       uptos,
                       sender_patterns,
                       sender_endpt_patterns=None,
                       stmt=None,
                       deactivate=None):
        """Recursively visit an endpoint."""
        if from_app:
            sender = var_name(syslx.fmt_app_name(from_app.name))
        else:
            sender = '['
        agent = var_name(appname)
        app = module.apps.get(appname)
        endpt = app.endpoints.get(epname)
        assert endpt

        def visit_stmts(stmts, deactivate, last_parent_stmt):
            """Recursively visit a stmt list."""
            def block(last_stmt, block_stmts, fmt, *args):
                """Output a compound block."""
                write(fmt, *args)
                with write.indent():
                    return visit_stmts(block_stmts, deactivate, last_stmt)

            def block_with_end(last_stmt, block_stmts, fmt, *args):
                """Output a compound block, including the 'end' clause."""
                payload = block(last_stmt, block_stmts, fmt, *args)
                write('end')
                return payload

            payload = None

            for (i, stmt) in enumerate(stmts):
                last_stmt = last_parent_stmt and i == len(stmts) - 1
                if stmt.HasField('call'):
                    with write.indent():
                        payload = visit_endpoint(
                            app, syslx.fmt_app_name(stmt.call.target),
                            stmt.call.endpoint, uptos, app_patterns,
                            syslx.patterns(stmt.attrs)
                            | syslx.patterns(endpt.attrs), stmt, last_stmt
                            and deactivate)
                elif stmt.HasField('action'):
                    #write('{0} -> {0} : {1}', agent, r'\n'.join(textwrap.wrap(stmt.action.action, 40)))
                    write('{0} -> {0} : {1}', agent, stmt.action.action)
                elif stmt.HasField('cond'):
                    payload = block_with_end(last_stmt, stmt.cond.stmt,
                                             'opt {}', stmt.cond.test)
                elif stmt.HasField('loop'):
                    payload = block_with_end(
                        last_stmt, stmt.loop.stmt, 'loop {} {}',
                        stmt.loop.Mode.Name(stmt.loop.mode),
                        stmt.loop.criterion)
                elif stmt.HasField('loop_n'):
                    payload = block_with_end(last_stmt, stmt.loop_n.stmt,
                                             'loop {} times',
                                             stmt.loop_n.count)
                elif stmt.HasField('foreach'):
                    payload = block_with_end(last_stmt, stmt.foreach.stmt,
                                             'loop for each {}',
                                             stmt.foreach.collection)
                elif stmt.HasField('group'):
                    payload = block_with_end(last_stmt, stmt.group.stmt,
                                             'group {}', stmt.group.title)
                elif stmt.HasField('alt'):
                    prefix = 'alt'
                    for (j, choice) in enumerate(stmt.alt.choice):
                        last_alt_stmt = last_stmt and j == len(
                            stmt.alt.choice) - 1
                        payload = block(last_alt_stmt, choice.stmt, '{} {}',
                                        prefix, choice.cond)
                        prefix = 'else'
                    write('end')
                elif stmt.HasField('ret'):
                    rargs = []

                    for param in syslalgo.yield_ret_params(stmt.ret.payload):
                        if param != '...' and '.' in param:
                            (an, pn) = rex.split(r'\.', param)

                            rarg = format_args(an, pn)

                            if rarg:
                                rargs.append(rarg)
                        else:
                            rargs.append(param)

                    write('{}<--{} : {}', sender, agent,
                          ' | '.join(p for p in rargs))
                else:
                    raise Exception('No statement!')

            return payload

        app_patterns = syslx.patterns(app.attrs)
        target_patterns = syslx.patterns(endpt.attrs)

        patterns = target_patterns

        human = 'human' in app_patterns
        human_sender = 'human' in sender_patterns
        cron = 'cron' in sender_patterns
        needs_int = not (human or human_sender or cron) and sender != agent
        label = re.sub(ur'^.*? -> ', u' ⬄ ', unicode(epname))

        cron = 'cron' in app_patterns

        if stmt:
            assert stmt.HasField('call')

            ptrns = ''
            if bool(sender_endpt_patterns) or bool(patterns):
                ptrns = u', '.join(sorted(sender_endpt_patterns)) + \
                    u' → ' + u', '.join(sorted(patterns))

            isoctrl = []

            for ctrl in endpt.attrs.keys():
                if 'iso_ctrl' in ctrl:
                    isoctrl.append(re.sub(r'iso_ctrl_(.*)_txt', r'\1', ctrl))

            epargs = []

            def format_args(an, pn):
                arg = '.'.join((an, pn))

                if arg:
                    conf = module.apps[an].types[pn].attrs[
                        'iso_conf'].s[:1].upper()
                    integ = module.apps[an].types[pn].attrs[
                        'iso_integ'].s[:1].upper()
                    isocolor = 'red' if 'R' in conf else 'green'
                    arg = '<color blue>' + arg + '</color>' + ' <<color ' + isocolor + '>' + \
                        (conf if conf else '?') + ', ' + \
                        (integ if integ else '?') + '</color>>'

                return arg

            for p in endpt.param:
                an = ' :: '.join(p.type.type_ref.ref.appname.part)
                pn = '.'.join(p.type.type_ref.ref.path)

                eparg = format_args(an, pn)

                if eparg:
                    epargs.append(eparg)

            label = params.epfmt(
                epname=label,
                human='human' if human else '',
                human_sender='human sender' if human_sender else '',
                needs_int='needs_int' if needs_int else '',
                args=' | '.join(e for e in epargs),
                #args=', '.join(p.name for p in stmt.call.arg),
                patterns=ptrns,
                controls=', '.join(i for i in sorted(isoctrl)),
                **diagutil.attr_fmt_vars(stmt.attrs)).replace('\n', r'\n')

        if not ((human and sender == '[') or cron):
            ep_patterns = syslx.patterns(endpt.attrs)

            icon = '<&timer> ' if 'cron' in ep_patterns else ''
            write('{}->{} : {}{}', sender, agent, icon, label)
            if log_integration and stmt:
                log_integration(app=from_app, stmt=stmt, patterns=patterns)

        rargs = []

        for param in syslalgo.yield_ret_params(
                syslalgo.return_payload(endpt.stmt)):
            if param != '...' and '.' in param:
                (an, pn) = rex.split(r'\.', param)

                rarg = format_args(an, pn)

                if rarg:
                    rargs.append(rarg)
            else:
                rargs.append(param)

        payload = ' | '.join(p for p in rargs)

        calling_self = from_app and syslx.fmt_app_name(
            from_app.name) == appname
        if not calling_self and not payload and deactivate:
            deactivate()

        if len(endpt.stmt):
            hit_blackbox = False
            for (upto, comment) in itertools.chain(uptos.iteritems(),
                                                   already_visited.keys()):
                # Compare the common prefix of the current endpt and upto.
                upto_parts = upto.split(' <- ')
                if [appname, epname][:len(upto_parts)] == upto_parts:
                    hit_blackbox = True
                    if payload:
                        write.activate(agent)
                        if comment is not None:
                            write('note over {}: {}', agent, comment
                                  or 'see below')
                    else:
                        if comment is not None:
                            write('note {}: {}',
                                  'left' if sender > agent else 'right',
                                  comment or 'see below')
                    if payload:
                        write('{}<--{} : {}', sender, agent, payload)
                        write.deactivate(agent)
                    break

            if not hit_blackbox:
                with write.activated(agent, human or cron) as deactivate:
                    # 'see above')
                    visiting = (appname + ' <- ' + epname, None)
                    already_visited[visiting] += 1
                    try:
                        return visit_stmts(endpt.stmt, deactivate, True)
                    finally:
                        already_visited[visiting] -= 1
                        if not already_visited[visiting]:
                            del already_visited[visiting]
Пример #11
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()

        passthrough_apps_attr = endpt.attrs.get('passthrough')
        passthrough_apps = set(
            e.s for e in passthrough_apps_attr.a.elt) if passthrough_apps_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 - passthrough_apps

        def find_integrations():
            """Return all integrations between relevant apps."""

            integration_set = {((app1, ep1), (app2, ep2))
                               for ((app1, ep1), (app2, ep2)) in deps
                               if ({app1, app2} <= apps and not ({app1, app2} & exclude)) and not {ep1, ep2} & {'.. * <- *', '*'}}

            if passthrough_apps:

                def passthrough_walk(dep, integration_set):
                    """ visit passthrough + 1: dep tuple, integration_set tuples """

                    # add to integration set
                    if (not ({dep[1][0]} & exclude) and not (
                            {dep[1][1]} & {'.. * <- *', '*'})):
                        integration_set.add(dep)

                    # find the next outbond dep
                    if dep[1][0] in passthrough_apps:
                        # call visit_endpoints for all calls
                        for stmt in yield_call_statements(
                                module.apps[dep[1][0]].endpoints[dep[1][1]].stmt):
                            app_2_name = ' :: '.join(
                                part for part in stmt.call.target.part)
                            ep_2_name = stmt.call.endpoint
                            passthrough_walk(
                                ((dep[1]), (app_2_name, ep_2_name)), integration_set)

                    return

                # collect outbound dependencies
                outbound_deps = {((app1, ep1), (app2, ep2))
                                 for ((app1, ep1), (app2, ep2)) in deps
                                 if (({app1, app2} <= apps) or ({app1} <= apps and {app2} <= passthrough_apps)) and not
                                    ({app1, app2} & exclude) and not ({ep1, ep2} & {'.. * <- *', '*'})}

                # collect outbound pubsub dependencies
                # inbound_deps

                # add passthroughs
                for dep in outbound_deps:
                    passthrough_walk(dep, integration_set)

            return integration_set

        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
Пример #12
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)
                attrs = {}
                state_name = ''

                if istoplevel:
                    template = 'state "{}" as X{}{} {{'
                    attrs = module.apps[name].attrs
                    state_name = name
                else:
                    template = '  state "{}" as {}{}'
                    (app_name, _, ep_name) = name.partition(' : ')
                    attrs = module.apps[app_name].endpoints[ep_name].attrs
                    state_name = ep_name

                write(template,
                      appfmt(appname=state_name,
                             **diagutil.attr_fmt_vars(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('left to right direction')
            write('scale max 16384 height')
            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 restrict_by and restrict_by not in module.apps[app_a].attrs.keys(
                ) + module.apps[app_b].attrs.keys():
                    continue

                if restrict_by and restrict_by not in module.apps[app_a].endpoints[ep_a].attrs.keys(
                ) + module.apps[app_b].endpoints[ep_b].attrs.keys():
                    continue

                if app_a not in clusters:
                    clusters[app_a] = set()
                if app_b not in clusters:
                    clusters[app_b] = set()

                client_ep = ep_b
                # 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(client_ep + " 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:

                if restrict_by and restrict_by not in module.apps[app_a].attrs.keys(
                ) + module.apps[app_b].attrs.keys():
                    continue

                if restrict_by and restrict_by not in module.apps[app_a].endpoints[ep_a].attrs.keys(
                ) + module.apps[app_b].endpoints[ep_b].attrs.keys():
                    continue

                direct = {app_a, app_b} & highlights

                (match_app, match_ep) = (app_b, ep_b)

                # build the label
                label = ''
                needs_int = app_a != match_app

                pub_sub_src_ptrns = syslx.patterns(
                    module.apps[app_a].endpoints[ep_a].attrs)

                tgt_ptrns = syslx.patterns(module.apps[match_app].endpoints[match_ep].attrs) or \
                    syslx.patterns(module.apps[match_app].attrs)

                for stmt in yield_call_statements(
                        module.apps[app_a].endpoints[ep_a].stmt):

                    # if restrict_by not in stmt.attrs.keys():
                    #  continue

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

                    if match_app == app_b_name and match_ep == stmt.call.endpoint:
                        fmt_vars = diagutil.attr_fmt_vars(stmt.attrs)

                        src_ptrns = syslx.patterns(
                            stmt.attrs) or pub_sub_src_ptrns

                        ptrns = u', '.join(sorted(src_ptrns)) + u' → ' + u', '.join(sorted(tgt_ptrns)) \
                            if (bool(src_ptrns) or bool(tgt_ptrns)) else ''

                        label = diagutil.parse_fmt(app.attrs["epfmt"].s)(
                            needs_int=needs_int, patterns=ptrns, **fmt_vars)

                # if not label and middle:
                #  fmt_vars = diagutil.attr_fmt_vars(module.apps[app_b].endpoints[ep_b].attrs)
                #  label = diagutil.parse_fmt(app.attrs["epfmt"].s)(needs_int=needs_int, patterns=u'→' + middle + u'→', **fmt_vars)

                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),
                              '[#blue]',
                              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 '')