Updates pipeline and FSM design and development tools

* Updates pipeline and FSM design for 3.4 features:
    group and read/write design features.
* Adds tool to copy layout from existing design
* Adds pipeline design
This commit is contained in:
Ben Thomasson
2018-02-06 09:23:13 -05:00
parent 14ee6a8360
commit a222fb5ebd
78 changed files with 666 additions and 34450 deletions

View File

@@ -0,0 +1 @@
/extracted

View File

@@ -0,0 +1,19 @@
.PHONY: check extract
FSMS = animation time test mode buttons button toolbox site rack group stream link details.panel move device.detail view keybindings hotkeys null
extract:
mkdir -p extracted
for fsm in $(FSMS); do \
./extract.js ./$${fsm}.fsm.js > extracted/$${fsm}.yml; \
done
check: extract
for fsm in $(FSMS); do \
./tools/fsm-diff ../../../../network_ui/designs/$$fsm.yml extracted/$$fsm.yml; \
./tools/copy-layout.py ../../../../network_ui/designs/$$fsm.yml extracted/$$fsm.yml; \
done

View File

@@ -0,0 +1,47 @@
#!/usr/bin/env node
var YAML = require('yamljs');
function Iterator(o){
var k=Object.keys(o);
return {
next:function(){
return k.shift();
}
};
}
var myArgs = process.argv.slice(2);
var implementation = require(myArgs[0]);
var states = [];
var transitions = [];
var data = {states: states,
transitions: transitions};
var state_iter = Iterator(implementation);
var transition_iter = null;
var next_state = state_iter.next();
var next_transition = null;
var state = null;
var transition = null;
var i = 0;
while(next_state !== undefined) {
state = implementation[next_state];
transition_iter = Iterator(state.constructor.prototype);
next_transition = transition_iter.next();
while (next_transition !== undefined) {
transition = state.constructor.prototype[next_transition];
if (transition.transitions !== undefined) {
for (i = 0; i < transition.transitions.length; i++) {
transitions.push({from_state: next_state,
to_state:transition.transitions[i],
label:next_transition});
}
}
next_transition = transition_iter.next();
}
states.push({label: state.name});
next_state = state_iter.next();
}
console.log(YAML.stringify(data));

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env node
var YAML = require('yamljs');
function Iterator(o){
var k=Object.keys(o);
return {
next:function(){
return k.shift();
}
};
}
var myArgs = process.argv.slice(2);
var implementation = require(myArgs[0]);
var messages = [];
var data = {messages: messages};
var message_iter = Iterator(implementation);
var field_iter = null;
var next_message = message_iter.next();
var next_field = null;
var message = null;
var message_instance = null;
var fields = null;
// var field = null;
// var i = 0;
while(next_message !== undefined) {
message = implementation[next_message];
try {
message_instance = new message();
} catch(err) {
next_message = message_iter.next();
continue;
}
fields = [];
field_iter = Iterator(message_instance);
next_field = field_iter.next();
while (next_field !== undefined) {
fields.push(next_field);
// field = message.constructor.prototype[next_field];
// if (field.transitions !== undefined) {
// for (i = 0; i < field.transitions.length; i++) {
// transitions.push({from_message: next_message,
// to_message:field.transitions[i],
// label:next_field});
// }
// }
next_field = field_iter.next();
}
if(message_instance.msg_type !== null && message_instance.msg_type !== undefined) {
messages.push({msg_type: message_instance.msg_type,
fields: fields});
}
next_message = message_iter.next();
}
console.log(YAML.stringify(data));

View File

@@ -1,8 +1,8 @@
/* Copyright (c) 2017 Red Hat, Inc. */
var inherits = require('inherits');
var fsm = require('./fsm.js');
var move = require('./move.js');
var group = require('./group.js');
var move = require('./move.fsm.js');
var group = require('./group.fsm.js');
var rack_fsm = require('./rack.fsm.js');
var site_fsm = require('./site.fsm.js');

View File

@@ -1,6 +1,6 @@
/* Copyright (c) 2017-2018 Red Hat, Inc. */
var fsm = require('./fsm.js');
var button = require('./button.js');
var button = require('./button.fsm.js');
var util = require('./util.js');
var inherits = require('inherits');
var animation_fsm = require('./animation.fsm.js');

View File

@@ -8,13 +8,13 @@ var rack_fsm = require('./rack.fsm.js');
var site_fsm = require('./site.fsm.js');
var hotkeys = require('./hotkeys.fsm.js');
var toolbox_fsm = require('./toolbox.fsm.js');
var view = require('./view.js');
var move = require('./move.js');
var link = require('./link.js');
var view = require('./view.fsm.js');
var move = require('./move.fsm.js');
var link = require('./link.fsm.js');
var stream_fsm = require('./stream.fsm.js');
var group = require('./group.js');
var buttons = require('./buttons.js');
var time = require('./time.js');
var group = require('./group.fsm.js');
var buttons = require('./buttons.fsm.js');
var time = require('./time.fsm.js');
var test_fsm = require('./test.fsm.js');
var util = require('./util.js');
var models = require('./models.js');

View File

@@ -0,0 +1,26 @@
var inherits = require('inherits');
var fsm = require('./fsm.js');
function _State () {
}
inherits(_State, fsm._State);
{%for state in states%}
function _{{state.label}} () {
this.name = '{{state.label}}';
}
inherits(_{{state.label}}, _State);
var {{state.label}} = new _{{state.label}}();
exports.{{state.label}} = {{state.label}};
{%endfor%}
{%for state in states%}
{%for fn, transitions in state.functions%}
_{{state.label}}.prototype.{{fn}} = function (controller) {
{%for tn in transitions %}
controller.changeState({{tn.to_state}});
{%endfor%}
};
_{{state.label}}.prototype.{{fn}}.transitions = [{%for t in transitions%}'{{t.to_state}}'{% if not loop.last%}, {%endif%}{%endfor%}];
{%endfor%}
{%endfor%}

View File

@@ -0,0 +1,55 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2018 Benjamin Thomasson
"""
Usage:
copy-layout [options] <from> <to>
Options:
-h, --help Show this page
--debug Show debug logging
--verbose Show verbose logging
"""
from docopt import docopt
import logging
import sys
import yaml
logger = logging.getLogger('copy-layout')
def main(args=None):
if args is None:
args = sys.argv[1:]
parsed_args = docopt(__doc__, args)
if parsed_args['--debug']:
logging.basicConfig(level=logging.DEBUG)
elif parsed_args['--verbose']:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARNING)
with open(parsed_args['<from>']) as f:
from_fsm = yaml.load(f.read())
with open(parsed_args['<to>']) as f:
to_fsm = yaml.load(f.read())
to_states = {x['label']: x for x in to_fsm.get('states', [])}
to_fsm['name'] = from_fsm.get('name', '')
to_fsm['finite_state_machine_id'] = from_fsm.get('finite_state_machine_id', '')
to_fsm['diagram_id'] = from_fsm.get('diagram_id', '')
for state in from_fsm.get('states', []):
to_states.get(state['label'], {})['x'] = state.get('x', 0)
to_states.get(state['label'], {})['y'] = state.get('y', 0)
with open(parsed_args['<to>'], 'w') as f:
f.write(yaml.safe_dump(to_fsm, default_flow_style=False))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from fsm_diff.cli import main
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv[1:]))

View File

@@ -0,0 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__author__ = 'Ben Thomasson'
__email__ = 'benthomasson@gmail.com'
__version__ = '0.1.0'

View File

@@ -0,0 +1,79 @@
"""
Usage:
fsm_diff [options] <a> <b> [<output>]
Options:
-h, --help Show this page
--debug Show debug logging
--verbose Show verbose logging
"""
from docopt import docopt
import logging
import sys
import yaml
logger = logging.getLogger('cli')
def fsm_diff(a_name, b_name, a, b, silent=True):
a_states = {x['label'] for x in a['states']}
b_states = {x['label'] for x in b['states']}
missing_in_a = b_states - a_states
missing_in_b = a_states - b_states
if (missing_in_b) and not silent:
print "Extra states in " + a_name + ":\n ", "\n ".join(list(missing_in_b))
if (missing_in_a) and not silent:
print "Extra states in " + b_name + ":\n ", "\n ".join(list(missing_in_a))
new_states = missing_in_b.union(missing_in_a)
a_transitions = {tuple(sorted(x.items())) for x in a['transitions']}
b_transitions = {tuple(sorted(x.items())) for x in b['transitions']}
missing_in_a = b_transitions - a_transitions
missing_in_b = a_transitions - b_transitions
if (missing_in_b) and not silent:
print "Extra transitions in " + a_name + ":\n ", "\n ".join(map(str, missing_in_b))
if (missing_in_a) and not silent:
print "Extra transitions in " + b_name + ":\n ", "\n ".join(map(str, missing_in_a))
new_transitions = missing_in_b.union(missing_in_a)
data = dict(states=[dict(label=x) for x in list(new_states)],
transitions=[dict(x) for x in list(new_transitions)])
return data
def main(args=None):
if args is None:
args = sys.argv[1:]
parsed_args = docopt(__doc__, args)
if parsed_args['--debug']:
logging.basicConfig(level=logging.DEBUG)
elif parsed_args['--verbose']:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARNING)
with open(parsed_args['<a>']) as f:
a = yaml.load(f.read())
with open(parsed_args['<b>']) as f:
b = yaml.load(f.read())
data = fsm_diff(parsed_args['<a>'], parsed_args['<b>'], a, b, silent=False)
if parsed_args['<output>']:
with open(parsed_args['<output>'], 'w') as f:
f.write(yaml.dump(data, default_flow_style=False))
return 0

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Red Hat, Inc
"""
Usage:
fsm_generate_diffs [options] <design> <implementation>
Options:
-h, --help Show this page
--debug Show debug logging
--verbose Show verbose logging
--append Append the newly generated code to the implementation.
"""
from docopt import docopt
import logging
import sys
import fsm_diff.cli
import transform_fsm
import yaml
from jinja2 import FileSystemLoader, Environment
from subprocess import Popen, PIPE
logger = logging.getLogger('fsm_generate_diffs')
def main(args=None):
if args is None:
args = sys.argv[1:]
parsed_args = docopt(__doc__, args)
if parsed_args['--debug']:
logging.basicConfig(level=logging.DEBUG)
elif parsed_args['--verbose']:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARNING)
implementation = parsed_args['<implementation>']
p = Popen(['./extract.js', implementation], stdout=PIPE)
output = p.communicate()[0]
if p.returncode == 0:
b = yaml.load(output)
else:
return 1
with open(parsed_args['<design>']) as f:
a = yaml.load(f.read())
data = fsm_diff.cli.fsm_diff(a, b)
data = transform_fsm.transform_fsm(data)
env = Environment(loader=FileSystemLoader("templates"))
template = env.get_template('fsm.jst')
if parsed_args['--append']:
with open(implementation, "a") as f:
f.write(template.render(**data))
else:
print (template.render(**data))
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv[1:]))

View File

@@ -0,0 +1,4 @@
jinja2
docopt
pyyaml

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2017 Red Hat, Inc
"""
Usage:
transform_fsm [options] <input> <output>
Options:
-h, --help Show this page
--debug Show debug logging
--verbose Show verbose logging
"""
from docopt import docopt
import logging
import sys
import yaml
logger = logging.getLogger('transform_fsm')
def transform_fsm(data):
state_map = dict()
for state in data['states']:
state_map[state['label']] = state
state['functions'] = dict()
for transition in data['transitions']:
state = state_map.get(transition['from_state'], dict(label=transition['from_state'], functions=dict()))
state_map[transition['from_state']] = state
if state not in data['states']:
data['states'].append(state)
function_transitions = state['functions'].get(transition['label'], list())
function_transitions.append(dict(to_state=transition['to_state']))
state['functions'][transition['label']] = function_transitions
for state in data['states']:
state['functions'] = sorted(state['functions'].items())
return data
def main(args=None):
if args is None:
args = sys.argv[1:]
parsed_args = docopt(__doc__, args)
if parsed_args['--debug']:
logging.basicConfig(level=logging.DEBUG)
elif parsed_args['--verbose']:
logging.basicConfig(level=logging.INFO)
else:
logging.basicConfig(level=logging.WARNING)
with open(parsed_args['<input>']) as f:
data = yaml.load(f.read())
data = transform_fsm(data)
with open(parsed_args['<output>'], 'w') as f:
f.write(yaml.safe_dump(data, default_flow_style=False))
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))