diff --git a/misc/acrn-config/config_app/app.py b/misc/acrn-config/config_app/app.py new file mode 100644 index 000000000..dabc7038c --- /dev/null +++ b/misc/acrn-config/config_app/app.py @@ -0,0 +1,43 @@ +# Copyright (C) 2019 Intel Corporation. +# SPDX-License-Identifier: BSD-3-Clause + +"""Entry for config app. + +""" + +import os +import sys +import threading +import webbrowser + +# flask: Copyright 2010 Pallets +# SPDX-License-Identifier: BSD-3-Clause +# Refer to https://github.com/pallets/flask/blob/master/LICENSE.rst for the permission notice. +from flask import Flask + +# flask: Copyright (c) 2013, Marc Brinkmann +# SPDX-License-Identifier: BSD-3-Clause +# Refer to https://pypi.org/project/Flask-Bootstrap/ for the permission notice. +from flask_bootstrap import Bootstrap + +import configs +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')) +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'library')) +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', + 'board_config')) +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', + 'scenario_config')) +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', + 'launch_config')) +from views import CONFIG_APP + +APP = Flask(__name__) +APP.config.from_object(configs) +APP.register_blueprint(CONFIG_APP) +APP.jinja_env.add_extension('jinja2.ext.do') +Bootstrap(app=APP) + +if __name__ == '__main__': + URL = "http://127.0.0.1:5001/scenario" + threading.Timer(1, lambda: webbrowser.open(URL)).start() + APP.run(port=5001, debug=False) diff --git a/misc/acrn-config/config_app/configs.py b/misc/acrn-config/config_app/configs.py new file mode 100644 index 000000000..24d72608b --- /dev/null +++ b/misc/acrn-config/config_app/configs.py @@ -0,0 +1,13 @@ +# Copyright (C) 2019 Intel Corporation. +# SPDX-License-Identifier: BSD-3-Clause + +"""Configurations for config app. + +""" + +import os + +BOARD_INFO = None +BOARD_TYPE = None +SCENARIO = None +CONFIG_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'xmls', 'config-xmls') diff --git a/misc/acrn-config/config_app/controller.py b/misc/acrn-config/config_app/controller.py new file mode 100644 index 000000000..47570217f --- /dev/null +++ b/misc/acrn-config/config_app/controller.py @@ -0,0 +1,288 @@ +# Copyright (C) 2019 Intel Corporation. +# SPDX-License-Identifier: BSD-3-Clause + +"""Controller for config app. + +""" + +import os +import xml.etree.ElementTree as ElementTree + + +class XmlConfig: + """The core class to analyze and modify acrn config xml files""" + def __init__(self, path=None, default=True): + self._xml_path = path + self._default = default + self._curr_xml = None + self._curr_xml_tree = None + + @staticmethod + def _get_xml_type(xml_file): + """ + get the config type by file. + :param xml_file: the file path of xml file. + :return: the xml type. + :raises: ValueError, OSError, SyntaxError. + """ + xml_type = '' + if os.path.splitext(xml_file)[1] != '.xml': + return xml_type + try: + tree = ElementTree.parse(xml_file) + root = tree.getroot() + if 'uos_launcher' in root.attrib: + xml_type = 'uos_launcher' + elif 'scenario' in root.attrib: + xml_type = 'scenario' + elif 'board' in root.attrib: + xml_type = 'board' + elif 'board_setting' in root.attrib: + xml_type = 'board_setting' + except ValueError: + print('xml parse error: {}'.format(xml_file)) + xml_type = '' + except OSError: + print('xml open error: {}'.format(xml_file)) + xml_type = '' + except SyntaxError: + print('xml syntax error: {}'.format(xml_file)) + xml_type = '' + + return xml_type + + def list_all(self, xml_type=None): + """ + list all xml config files by type. + :param xml_type: the xml type. + :return: he list of xml config files. + """ + xmls = [] + user_xmls = [] + + if self._xml_path is None or not os.path.exists(self._xml_path): + return xmls, user_xmls + for test_file in os.listdir(self._xml_path): + test_file_path = os.path.join(self._xml_path, test_file) + if os.path.isfile(test_file_path): + if XmlConfig._get_xml_type(test_file_path) == xml_type: + xmls.append(os.path.splitext(test_file)[0]) + user_path = os.path.join(self._xml_path, 'user_defined') + if os.path.isdir(user_path): + for test_file in os.listdir(user_path): + test_file_path = os.path.join(user_path, test_file) + if os.path.isfile(test_file_path): + if XmlConfig._get_xml_type(test_file_path) == xml_type: + user_xmls.append(os.path.splitext(test_file)[0]) + + return xmls, user_xmls + + def set_curr(self, xml): + """ + set current xml file to analyze. + :param xml: the xml file. + :return: None. + :raises: ValueError, OSError, SyntaxError. + """ + if self._xml_path is None: + return + try: + self._curr_xml = xml + + xml_path = os.path.join(self._xml_path, self._curr_xml + '.xml') \ + if self._default \ + else os.path.join(self._xml_path, 'user_defined', self._curr_xml + '.xml') + + tree = ElementTree.parse(xml_path) + self._curr_xml_tree = tree + except ValueError: + print('xml parse error: {}'.format(xml)) + self._curr_xml = None + self._curr_xml_tree = None + except OSError: + print('xml open error: {}'.format(xml)) + self._curr_xml = None + self._curr_xml_tree = None + except SyntaxError: + print('xml syntax error: {}'.format(xml)) + self._curr_xml = None + self._curr_xml_tree = None + + def get_curr(self): + """ + get current xml config file. + :return: current xml config file name. + """ + return self._curr_xml + + def get_curr_root(self): + """ + get the xml root of current xml config file. + :return: the xml root of current xml config file. + """ + if self._curr_xml_tree is None: + return None + return self._curr_xml_tree.getroot() + + def get_curr_value(self, *args): + """ + get the value of the element by its path. + :param args: the path of the element. + :return: the value of the element. + """ + if self._curr_xml_tree is None: + return None + dest_node = self._get_dest_node(*args) + if dest_node is None: + return None + if dest_node.text is None or dest_node.text.strip() == '': + return '' + return dest_node.text + + def set_curr_value(self, value, *args): + """ + set the value of the element by its path. + :param value: the value of the element. + :param args: the path of the element. + :return: None. + """ + if self._curr_xml_tree is None: + return + dest_node = self._get_dest_node(*args) + dest_node.text = value + + def set_curr_list(self, values, *args): + """ + set a list of sub element for the element by its path. + :param values: the list of values of the element. + :param args: the path of the element. + :return: None. + """ + if self._curr_xml_tree is None: + return + tag = args[-1] + args = args[:-1] + dest_node = self._get_dest_node(*args) + for node in dest_node.getchildren(): + dest_node.remove(node) + for value in values: + new_node = ElementTree.SubElement(dest_node, tag) + new_node.text = value + + def set_curr_attr(self, attr_name, attr_value, *args): + """ + set the attribute of the element by its path. + :param attr_name: the attribute name of the element. + :param attr_value: the attribute value of the element. + :param args: the path of the element. + :return: None. + """ + if self._curr_xml_tree is None: + return + dest_node = self._get_dest_node(*args) + dest_node.attrib[attr_name] = attr_value + + def add_curr_value(self, key, desc, value, *args): + """ + add a sub element for the element by its path. + :param key: the tag of the sub element. + :param desc: the attribute desc of the sub element. + :param value: the value of the sub element. + :param args: the path of the element. + :return: None. + """ + if self._curr_xml_tree is None: + return + + dest_node = self._get_dest_node(*args) + + if key in ['vm']: + ElementTree.SubElement(dest_node, key, attrib={'id': value, 'desc': desc}) + else: + new_node = ElementTree.SubElement(dest_node, key, attrib={'desc': desc}) + new_node.text = value + + def delete_curr_key(self, *args): + """ + delete the element by its path. + :param args: the path of the element. + :return: None. + """ + if self._curr_xml_tree is None: + return + dest_node = self._get_dest_node(*args) + self._curr_xml_tree.getroot().remove(dest_node) + + def _get_dest_node(self, *args): + """ + get the destination element by its path. + :param args: the path of the element. + :return: the destination element. + """ + if self._curr_xml_tree is None: + return None + dest_node = self._curr_xml_tree.getroot() + path = '.' + for arg in args: + # tag:attr=xxx + # tag:attr + # tag + tag = None + attr_name = None + attr_value = None + if ':' not in arg: + tag = arg + elif '=' not in arg: + # tag = arg.split(':')[0] + # attr_name = arg.split(':')[1] + raise Exception('unsupported xml path: tag:attr') + else: + tag = arg.split(':')[0] + attr = arg.split(':')[1] + attr_name = attr.split('=')[0] + attr_value = attr.split('=')[1] + + if attr_value is None: + path += ("/" + tag) + else: + path += ("/" + tag + "[@" + attr_name + "='" + attr_value + "']") + + dest_node = dest_node.findall(path) + if dest_node is not None and dest_node != []: + return dest_node[0] + + raise Exception('can not find node by {} from xml'.format(args)) + + def save(self, xml=None): + """ + save current xml to file. + :param xml: the file name to save; if not specified, save current xml to default names. + :return: None. + """ + if self._curr_xml_tree is None: + return + if xml is None: + xml = self._curr_xml + + xml_path = os.path.join(self._xml_path, 'user_defined') + if not os.path.isdir(xml_path): + os.makedirs(xml_path) + + self._format_xml(self._curr_xml_tree.getroot()) + self._curr_xml_tree.write(os.path.join(xml_path, xml+'.xml'), encoding='utf-8', + xml_declaration=True, method='xml') + + def _format_xml(self, element, depth=0): + i = "\n" + depth * " " + if element: + if not element.text or not element.text.strip(): + element.text = i + " " + if not element.tail or not element.tail.strip(): + element.tail = i + for element in element: + self._format_xml(element, depth + 1) + if not element.tail or not element.tail.strip(): + element.tail = i + else: + if depth and (not element.tail or not element.tail.strip()): + element.tail = i diff --git a/misc/acrn-config/config_app/requirements b/misc/acrn-config/config_app/requirements new file mode 100644 index 000000000..49ee1a839 --- /dev/null +++ b/misc/acrn-config/config_app/requirements @@ -0,0 +1,3 @@ +Flask==1.1.1 +flask_bootstrap==3.3.7.1 + diff --git a/misc/acrn-config/config_app/static/main.js b/misc/acrn-config/config_app/static/main.js new file mode 100644 index 000000000..deb3098a5 --- /dev/null +++ b/misc/acrn-config/config_app/static/main.js @@ -0,0 +1,560 @@ +$().ready(function(){ + $("#board_info_file").change(function () { + var fileObj = $(this)[0].files[0]; + if (typeof (fileObj) == "undefined" || fileObj.size <= 0) { + alert("Upload error."); + return; + } + var file_name = $(this).val(); + var formFile = new FormData(); + formFile.append("name", file_name); + formFile.append("file", fileObj); + + + $.ajax({ + url: "../upload_board_info", + data: formFile, + type: "Post", + dataType: "json", + cache: false, + processData: false, + contentType: false, + success: function (result) { + console.log(result); + if (result.status == 'success') { + if (result.info != 'updated') { + alert('Upload successfully.\nA new board type: '+result.info+' created.'); + } else { + alert('Upload successfully.'); + } + } else { + alert(result.status); + } + + window.location.reload(); + }, + error: function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }) + }); + + $("#scenario_file").change(function () { + var fileObj = $(this)[0].files[0]; + if (typeof (fileObj) == "undefined" || fileObj.size <= 0) { + alert("Upload error."); + return; + } + var file_name = $(this).val(); + + var formFile = new FormData(); + formFile.append("name", file_name); + formFile.append("file", fileObj); + + $.ajax({ + url: "../upload_scenario", + data: formFile, + type: "Post", + dataType: "json", + cache: false, + processData: false, + contentType: false, + success: function (result) { + console.log(result); + status = result.status; + if (status!='success') { + alert(status); + return; + } + error_list = result.error_list; + file_name = result.file_name; + rename = result.rename + if(result.rename==true) { + alert('Scenario setting existed, import successfully with a new name: '+file_name); + } else { + alert('Scenario setting import successfully with name: '+file_name); + } + window.location = 'http://' + + window.location.host+"/scenario/user_defined_" + file_name; + }, + error: function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }) + }); + + $("#launch_file").change(function () { + var fileObj = $(this)[0].files[0]; + if (typeof (fileObj) == "undefined" || fileObj.size <= 0) { + alert("Upload error."); + return; + } + var file_name = $(this).val(); + + var formFile = new FormData(); + formFile.append("name", file_name); + formFile.append("file", fileObj); + + $.ajax({ + url: "../upload_launch", + data: formFile, + type: "Post", + dataType: "json", + cache: false, + processData: false, + contentType: false, + success: function (result) { + console.log(result); + status = result.status; + if (status!='success') { + alert(status); + return; + } + error_list = result.error_list; + file_name = result.file_name; + rename = result.rename + if(result.rename==true) { + alert('Launch setting existed, import successfully with a new name: '+file_name); + } else { + alert('Launch setting import successfully with name: '+file_name); + } + window.location = 'http://' + + window.location.host+"/launch/user_defined_" + file_name; + }, + error: function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }) + }); + + $("select#board_info").change(function(){ + data = {board_info: $(this).val()}; + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../select_board", + data : JSON.stringify(data), + success : function(result) { + console.log(result); + window.location.reload(true); + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + } + }); + }); + + $("input").on('blur',function(){ + $(this).parents(".form-group").removeClass("has-error"); + $(this).parents(".form-group").children("p").text(""); + }); + + $("select").on('changed.bs.select',function(){ + $(this).parents(".form-group").removeClass("has-error"); + $(this).parents(".form-group").children("p").text(""); + }) + + $('#save_board').on('click', function() { + save_board(); + }); + + $('#save_scenario').on('click', function() { + var name = $(this).data('id'); + if(name=="generate_board_src" || name=="generate_scenario_src") { + save_scenario(name); + } + else { + save_scenario(); + } + }); + + $('#remove_scenario').on('click', function() { + old_scenario_name = $("#old_scenario_name").text(); + if(old_scenario_name.indexOf('user_defined')<0) { + alert("Default scenario setting could not be deleted."); + return; + } + + var board_info = $("select#board_info").val(); + if (board_info==null || board_info=='') { + alert("Please select one board info before this operation."); + return; + } + + scenario_config = { + old_setting_name: $("#old_scenario_name").text(), + new_setting_name: $("#new_scenario_name").val() + } + + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../remove_setting", + data : JSON.stringify(scenario_config), + success : function(result) { + console.log(result); + status = result.status + info = result.info + if (status == 'success') { + alert('Remove current scenario setting from acrn-config app successfully.'); + window.location = window.location = 'http://' + + window.location.host+"/scenario"; + } else { + alert('Remove current scenario setting from acrn-config app failed:\n'+info); + } + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }); + }); + + $('#save_launch').on('click', function() { + var name = $(this).data('id'); + if(name=="generate_launch_script") { + save_launch(name); + } + else { + save_launch(); + } + }); + + $('#remove_launch').on('click', function() { + old_launch_name = $("#old_launch_name").text(); + if(old_launch_name.indexOf('user_defined')<0) { + alert("Default launch setting could not be deleted."); + return; + } + + var board_info = $("select#board_info").val(); + if (board_info==null || board_info=='') { + alert("Please select one board before this operation."); + return; + } + + launch_config = { + old_setting_name: $("#old_launch_name").text(), + new_setting_name: $("#new_launch_name").val(), + } + + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../remove_setting", + data : JSON.stringify(launch_config), + success : function(result) { + console.log(result); + status = result.status + info = result.info + if (status == 'success') { + alert('Remove current launch setting from acrn-config app successfully.'); + window.location = window.location = 'http://' + + window.location.host+"/launch"; + } else { + alert('Remove current launch setting from acrn-config app failed:\n'+info); + } + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }); + }); + + $('#generate_board_src').on('click', function() { + var dataId = $(this).data('id'); + $("#save_scenario").data('id', dataId); + }); + + $('#generate_scenario_src').on('click', function() { + var dataId = $(this).data('id'); + $("#save_scenario").data('id', dataId); + }); + + $('#generate_launch_script').on('click', function() { + var dataId = $(this).data('id'); + $("#save_launch").data('id', dataId); + }); + + $("select[ID$='vuart:id=1,base']").change(function(){ + + var id = $(this).attr('id'); + var value = $(this).val(); + show_com_target(id, value); + }); + + $("select[ID$='vuart:id=1,base']").each(function(index, item) { + var id = $(item).attr('id'); + var value = $(item).val(); + show_com_target(id, value); + }) + +}) + + +function show_com_target(id, value) { + + if(id==null || id=='undefined') { + return + } + var id2 = id.replace('base', 'target_vm_id'); + var jquerySpecialChars = ["~", "`", "@", "#", "%", "&", "=", "'", "\"", + ":", ";", "<", ">", ",", "/"]; + for (var i = 0; i < jquerySpecialChars.length; i++) { + id2 = id2.replace(new RegExp(jquerySpecialChars[i], + "g"), "\\" + jquerySpecialChars[i]); + } + if (value == 'INVALID_COM_BASE') { + $('#'+id2+'_label1').hide(); + $('#'+id2+'_label2').hide(); + $('#'+id2+'_config').hide(); + $('#'+id2+'_err').hide(); + } + else { + $('#'+id2+'_label1').show(); + $('#'+id2+'_label2').show(); + $('#'+id2+'_config').show(); + $('#'+id2+'_err').show(); + } +} + + +function save_scenario(generator=null){ + var board_info = $("select#board_info").val(); + if (board_info==null || board_info=='') { + alert("Please select one board info before this operation."); + return; + } + + scenario_config = { + old_scenario_name: $("#old_scenario_name").text(), + new_scenario_name: $("#new_scenario_name").val() + } + + $("input").each(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + if(id!='new_scenario_name' && id!='board_info_file' + && id!='board_info_upload' && id!="scenario_file") { + scenario_config[id] = $(this).val(); + } + }) + + $("textarea").each(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + if(id!='new_scenario_name' && id!='board_info_file' + && id!='board_info_upload' && id!="scenario_file") { + scenario_config[id] = $(this).val(); + } + }) + + $("select").each(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + if(id!='board_info') { + scenario_config[$(this).attr('id')] = $(this).val(); + } + }) + + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../save_scenario", + data : JSON.stringify(scenario_config), + success : function(result) { + error_list = result.error_list; + status = result.status; + var no_err = true; + $.each(error_list, function(index,item){ + no_err = false; + var jquerySpecialChars = ["~", "`", "@", "#", "%", "&", "=", "'", "\"", + ":", ";", "<", ">", ",", "/"]; + for (var i = 0; i < jquerySpecialChars.length; i++) { + index = index.replace(new RegExp(jquerySpecialChars[i], + "g"), "\\" + jquerySpecialChars[i]); + } + $("#"+index).parents(".form-group").addClass("has-error"); + $("#"+index+"_err").text(item); + }) + if(no_err == true && status == 'success') { + file_name = result.file_name; + if(result.rename==true) { + alert('Scenario setting existed, saved successfully with a new name: ' + +file_name+'\nto acrn-hypervisor/misc/acrn-config/xmls/config-xmls/'+board_info+'/user_defined/'); + } else { + alert('Scenario setting saved successfully with name: ' + +file_name+'\nto acrn-hypervisor/misc/acrn-config/xmls/config-xmls/'+board_info+'/user_defined/'); + } + if(generator != null) { + generator_config = { + type: generator, + board_info: $("select#board_info").val(), + board_setting: "board_setting", + scenario_setting: file_name + } + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../generate_src", + data : JSON.stringify(generator_config), + success : function(result) { + console.log(result); + status = result.status + error_list = result.error_list + if (status == 'success' && JSON.stringify(error_list)=='{}') { + alert(generator+' successfully.'); + } else { + alert(generator+' failed. \nError list:\n'+JSON.stringify(error_list)); + } + window.location = "./user_defined_" + file_name; + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }); + } else { + window.location = "./user_defined_" + file_name; + } + } + else if(status != 'success') { + alert(JSON.stringify(error_list)); + } + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }); +} + +function save_launch(generator=null) { + var board_info = $("select#board_info").val(); + var scenario_name = $("select#scenario_name").val(); + if (board_info==null || board_info=='' || scenario_name==null || scenario_name=='') { + alert("Please select one board and scenario before this operation."); + return; + } + + launch_config = { + old_launch_name: $("#old_launch_name").text(), + new_launch_name: $("#new_launch_name").val(), + scenario_name: scenario_name + } + + $("input").each(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + if(id!='new_launch_name' && id!='board_info_file' + && id!='board_info_upload' && id!='scenario_name' + && id!="launch_file") { + launch_config[id] = $(this).val(); + } + }) + + $("select").each(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + if(id!='board_info') { + launch_config[$(this).attr('id')] = $(this).val(); + } + }) + + $("textarea").each(function(){ + var id = $(this).attr('id'); + var value = $(this).val(); + if(id!='new_scenario_name' && id!='board_info_file' + && id!='board_info_upload' && id!="scenario_file") { + launch_config[id] = $(this).val(); + } + }) + + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../save_launch", + data : JSON.stringify(launch_config), + success : function(result) { + console.log(result); + error_list = result.error_list; + status = result.status; + + var no_err = true; + $.each(error_list, function(index,item){ + no_err = false; + var jquerySpecialChars = ["~", "`", "@", "#", "%", "&", "=", "'", "\"", + ":", ";", "<", ">", ",", "/"]; + for (var i = 0; i < jquerySpecialChars.length; i++) { + index = index.replace(new RegExp(jquerySpecialChars[i], + "g"), "\\" + jquerySpecialChars[i]); + } + $("#"+index).parents(".form-group").addClass("has-error"); + $("#"+index+"_err").text(item); + }) + if(no_err == true && status == 'success') { + file_name = result.file_name; + if(result.rename==true) { + alert('Launch setting existed, saved successfully with a new name: ' + +file_name+'\nto acrn-hypervisor/misc/acrn-config/xmls/config-xmls/'+board_info+'/user_defined/'); + } else { + alert('Launch setting saved successfully with name: ' + +file_name+'\nto acrn-hypervisor/misc/acrn-config/xmls/config-xmls/'+board_info+'/user_defined/'); + } + if(generator != null) { + generator_config = { + type: generator, + board_info: $("select#board_info").val(), + board_setting: "board_setting", + scenario_setting: $("select#scenario_name").val(), + launch_setting: file_name + } + $.ajax({ + type : "POST", + contentType: "application/json;charset=UTF-8", + url : "../generate_src", + data : JSON.stringify(generator_config), + success : function(result) { + console.log(result); + status = result.status + error_list = result.error_list + if (status == 'success' && JSON.stringify(error_list)=='{}') { + alert(generator+' successfully.'); + } else { + alert(generator+' failed. \nError list:\n'+JSON.stringify(error_list)); + } + window.location = "./user_defined_" + file_name; + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }); + } else { + window.location = "./user_defined_" + file_name; + } + } + else if(status != 'success') { + alert(JSON.stringify(error_list)); + } + }, + error : function(e){ + console.log(e.status); + console.log(e.responseText); + alert(e.status+'\n'+e.responseText); + } + }); +} diff --git a/misc/acrn-config/config_app/static/styles.css b/misc/acrn-config/config_app/static/styles.css new file mode 100644 index 000000000..f5776e7d9 --- /dev/null +++ b/misc/acrn-config/config_app/static/styles.css @@ -0,0 +1,3 @@ +ul.nav li.dropdown:hover ul.dropdown-menu { + display: block; +} diff --git a/misc/acrn-config/config_app/templates/base.html b/misc/acrn-config/config_app/templates/base.html new file mode 100644 index 000000000..2cb6531b5 --- /dev/null +++ b/misc/acrn-config/config_app/templates/base.html @@ -0,0 +1,105 @@ + + + +
+ +
+
+
+
+
+ |
+
+ {% for elem in vm.getchildren() %}
+ {% if elem.getchildren() == [] and ('configurable' not in elem.attrib or elem.attrib['configurable'] !=
+ '0') %}
+
+
+
+ {% set elem_text = '' if elem.text == None else elem.text %}
+ {% if ','.join(['uos', elem.tag]) not in launch_item_values %}
+
+ {% elif elem.getchildren() != [] %}
+ {% if 'multiselect' not in elem.attrib or elem.attrib['multiselect'] != 'true' %}
+ {% set first_child = [] %}
+ {% for sub_elem in elem.getchildren() %}
+ {% set sub_elem_text = '' if sub_elem.text == None else sub_elem.text %}
+ {% if 'configurable' not in sub_elem.attrib or sub_elem.attrib['configurable'] != '0' %}
+
+ {% if 'readonly' in elem.attrib and elem.attrib['readonly'] == 'true' %}
+ {% if elem.tag == 'kernel_cmdline' %}
+
+ {% else %}
+
+ {% endif %}
+ {% else %}
+ {% if elem.tag == 'kernel_cmdline' %}
+
+ {% else %}
+
+ {% endif %}
+ {% endif %}
+
+ {% else %}
+
+ {% if 'readonly' in elem.attrib and elem.attrib['readonly'] == 'true' %}
+
+ {% endif %}
+
+ {% if 'id' not in elem.attrib %}
+ {% if not first_child %}
+ {% do first_child.append(1) %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {% if ','.join(['uos', elem.tag, sub_elem.tag]) not in launch_item_values %}
+
+ {% endif %}
+ {% endfor %}
+ {% elif 'configurable' not in elem.attrib or elem.attrib['configurable'] != '0' %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% else %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% endif %}
+ {% else %}
+ {% if not first_child %}
+ {% do first_child.append(1) %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {% if ','.join(['uos', elem.tag, sub_elem.tag]) not in launch_item_values %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% else %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% endif %}
+ {% endif %}
+
+
+
+
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+
+ {% if 'readonly' in elem.attrib and elem.attrib['readonly'] == 'true' %}
+
+ |
+
+
+
+
+
+ |
+
+ {% for elem in vm.getchildren() %}
+ {% set elem_text = elem.text if elem.text != None else '' %}
+ {% if elem.getchildren() == [] and ('configurable' not in elem.attrib or elem.attrib['configurable']
+ != '0')%}
+
+
+
+
+ {% if ','.join(['vm', elem.tag]) not in scenario_item_values %}
+
+ {% elif elem.getchildren() != [] and ('configurable' not in elem.attrib or elem.attrib['configurable']
+ != '0')%}
+ {% if 'multiselect' not in elem.attrib or elem.attrib['multiselect'] != 'true' %}
+ {% set first_child = [] %}
+ {% for sub_elem in elem.getchildren() %}
+ {% set sub_elem_text = sub_elem.text if sub_elem.text != None else '' %}
+ {% if 'configurable' not in sub_elem.attrib or sub_elem.attrib['configurable'] != '0' %}
+
+ {% if 'readonly' in elem.attrib and elem.attrib['readonly'] == 'true' %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% else %}
+
+ {% if 'readonly' in elem.attrib and elem.attrib['readonly'] == 'true' %}
+
+ {% endif %}
+
+
+ {% if 'id' not in elem.attrib %}
+ {% if not first_child %}
+ {% do first_child.append(1) %}
+
+ {% else %}
+
+ {% endif %}
+
+
+ {% if ','.join(['vm', elem.tag, sub_elem.tag]) not in scenario_item_values %}
+ {% if sub_elem.tag in ['bootargs', 'kern_args'] %}
+
+ {% endif %}
+ {% endfor %}
+ {% elif 'configurable' not in elem.attrib or elem.attrib['configurable'] != '0' %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% else %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% endif %}
+ {% else %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% endif %}
+
+ {% else %}
+ {% if not first_child %}
+ {% do first_child.append(1) %}
+
+ {% else %}
+
+ {% endif %}
+
+
+ {% if (','.join(['vm', elem.tag, sub_elem.tag]) not in scenario_item_values) and
+ (elem.tag!='vuart' or sub_elem.tag!='base') %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% else %}
+
+ {% if 'readonly' in sub_elem.attrib and sub_elem.attrib['readonly'] == 'true' %}
+
+ {% endif %}
+
+ {% endif %}
+
+
+
+
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+
+ {% if 'readonly' in elem.attrib and elem.attrib['readonly'] == 'true' %}
+
+
+ |
+