Commit 40a2fb37 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Fix robustness issues in Asn1Scc API

parent e6632bff
......@@ -21,7 +21,8 @@ import distutils.spawn as spawn
import sys
import importlib
import logging
import PySide.QtCore as Qt
from PySide.QtCore import QProcess
LOG = logging.getLogger(__name__)
......@@ -49,42 +50,48 @@ class ASN1(Enum):
def parse_asn1(*files, **options):
''' Call the ASN.1 parser on a number of files, and return the module
containing the AST '''
containing the AST
This function uses QProcess to launch the ASN.1 compiler because
the subprocess module from Python has issues on the Windows platform
'''
global AST
ast_version = options.get('ast_version', ASN1.UniqueEnumeratedNames)
flags = options.get('flags', [ASN1.AstOnly])
assert isinstance(ast_version, ASN1)
assert isinstance(flags, list)
asn1scc_root = os.path.dirname(spawn.find_executable('asn1.exe'))
path_to_asn1scc = spawn.find_executable('asn1.exe')
if not path_to_asn1scc:
raise TypeError('ASN.1 Compiler not found in path')
asn1scc_root = os.path.abspath(os.path.dirname(path_to_asn1scc))
# Create a temporary directory to store dataview.py and import it
tempdir = tempfile.mkdtemp()
if hasattr(sys, 'frozen'):
sys.path.append(tempdir)
if hasattr(sys, 'frozen') or os.name == 'nt':
# On windows, remove the drive letter, workaround to ASN1SCC bug
tempdir = tempdir[2:]
asn1scc_root = '.' if not asn1scc_root else asn1scc_root[2:]
asn1scc_root = asn1scc_root[2:]
filename = str(uuid.uuid4()).replace('-', '_')
filepath = tempdir + os.sep + filename + '.py'
# dump python.stg in the temp directory
#stg = Qt.QFile(':misc/python.stg')
#stg_data = stg.readData(stg.size())
stg = asn1scc_root + os.sep + 'python.stg'
#with open(tmp_stg, 'w') as fd:
# fd.write(stg_data)
args = ['asn1.exe',
'-customStgAstVerion', str(ast_version.value),
args = ['-customStgAstVerion', str(ast_version.value),
'-customStg', stg + ':' + filepath] + list(*files)
LOG.debug('Calling: ' + ' '.join(args))
try:
ret = subprocess.check_call(args)
except subprocess.CalledProcessError as err:
LOG.debug(str(err))
raise TypeError('asn1.exe execution failed')
sys.path.append(tempdir)
if ret == 0:
asn1scc = QProcess()
LOG.debug(os.getcwd())
LOG.debug(path_to_asn1scc + ' ' + ' '.join(args))
asn1scc.start(path_to_asn1scc, args)
if not asn1scc.waitForStarted():
raise TypeError('Could not start ASN.1 Compiler')
if not asn1scc.waitForFinished():
raise TypeError('Execution of ASN.1 Compiler timed out')
exitcode = asn1scc.exitCode()
result = asn1scc.readAllStandardError()
if exitcode != 0:
raise TypeError('ASN.1 Compiler Error (exit code = {}) - {}'
.format(exitcode, str(result)))
else:
if filename in AST.viewkeys():
# Re-import module if it was already loaded
ast = AST[filename]
......@@ -93,8 +100,6 @@ def parse_asn1(*files, **options):
ast = importlib.import_module(filename)
AST[filename] = ast
return ast
else:
raise TypeError('Error calling ASN.1 compiler')
if __name__ == '__main__':
......
......@@ -95,7 +95,8 @@ LIST = type('ListType', (object,), {'kind': 'ListType'})
ANY_TYPE = type('AnyType', (object,), {'kind': 'AnyType'})
CHOICE = type('ChoiceType', (object,), {'kind': 'ChoiceType'})
BOOLEAN = type('BooleanType', (object,), {'kind': 'BooleanType'})
RAWSTRING = type('RawString', (object,), {'kind': 'StandardStringType'})
RAWSTRING = type('RawString', (object,), {'kind': 'StandardStringType',
'Min': '0', 'Max': '255'})
OCTETSTRING = type('OctetString', (object,), {'kind': 'OctetStringType'})
ENUMERATED = type('EnumeratedType', (object,), {'kind': 'EnumeratedType'})
......@@ -3835,8 +3836,8 @@ def pr_file(root):
LOG.info('USE Clause did not contain ASN.1 filename')
LOG.debug(str(err))
except TypeError as err:
errors.append('ASN.1 compiler execution failed')
LOG.debug(str(err))
LOG.debug(traceback.format_exc())
errors.append('ASN.1 compiler failed - {}'.format(str(err)))
for child in systems:
LOG.debug('found SYSTEM')
......@@ -3882,7 +3883,7 @@ def add_to_ast(ast, filename=None, string=None):
try:
parser = parser_init(filename=filename, string=string)
except IOError as err:
LOG.error('parser_init failed: ' + str(err))
LOG.error('Parser error: ' + str(err))
raise
# Use Sam & Max output capturer to get errors from ANTLR parser
with samnmax.capture_ouput() as (stdout, stderr):
......@@ -4001,13 +4002,17 @@ def parseSingleElement(elem='', string=''):
def parser_init(filename=None, string=None):
''' Initialize the parser (to be called first) '''
try:
char_stream = antlr3.ANTLRFileStream(filename, encoding='utf-8')
except (IOError, TypeError) as err:
if filename is not None:
try:
char_stream = antlr3.ANTLRFileStream(filename, encoding='utf-8')
except (IOError, TypeError) as err:
LOG.debug(str(traceback.format_exc()))
raise
if string is not None:
try:
char_stream = antlr3.ANTLRStringStream(string)
except TypeError as err:
raise IOError('Could not parse input: ' + str(err))
raise IOError('String parsing error: ' + str(err))
lex = lexer.sdl92Lexer(char_stream)
tokens = antlr3.CommonTokenStream(lex)
parser = sdl92Parser(tokens)
......
......@@ -1952,8 +1952,12 @@ def init_logging(options):
def parse(files):
''' Parse files '''
LOG.info('Checking ' + str(files))
# move to the directory of the .pr files (needed for ASN.1 parsing)
LOG.info(files[0])
path = os.path.dirname(files[0])
files = [os.path.abspath(each) for each in files]
os.chdir(path or '.')
ast, warnings, errors = ogParser.parse_pr(files=files)
LOG.info('Parsing complete. '
'Summary, found {} warnings and {} errors'
.format(len(warnings), len(errors)))
......@@ -2127,6 +2131,12 @@ def opengeode():
if __name__ == '__main__':
''' Run main application '''
cwd = os.getcwd()
# Windows only: argv[0] may not contain anything if binary is called
# from the current directory (no "./" prefix on Windows, even if the
# current folder is not in the PATH). In that case add it to the PATH
if os.name == 'nt':
os.environ['PATH'] += os.pathsep + os.path.abspath(
os.path.dirname(sys.argv[0]) or cwd)
ret = opengeode()
os.chdir(cwd)
sys.exit(ret)
......@@ -13,6 +13,8 @@ SeqBoolFix ::= SEQUENCE (SIZE(2)) OF BOOLEAN
SeqEnum ::= SEQUENCE (SIZE(1..5)) OF ENUMERATED { hello, world }
SeqEnumFix ::= SEQUENCE (SIZE(2)) OF ENUMERATED { hello, world }
Enum ::= ENUMERATED {a, b, c, d}
END
......
......@@ -2,7 +2,7 @@
PROCESS orchestrator
/* CIF COMMENT (405, 192), (71, 35) */
COMMENT 'Hello';
/* CIF TEXT (39, 94), (293, 203) */
/* CIF TEXT (39, 94), (293, 233) */
dcl seq tastE_Peek_id_list;
dcl fixed FixedString := 'Hello';
......@@ -14,6 +14,10 @@ dcl seqbool2 SeqBoolFix := { true, false };
dcl seqen SeqEnum := { hello, world };
dcl seqen2 SeqEnumFix := { hello, world };
dcl myenum Enum := a;
dcl check tasTE_Peek_id;
/* CIF ENDTEXT */
/* CIF START (428, 223), (100, 45) */
START;
......@@ -61,4 +65,4 @@ endfor;
/* CIF STATE (423, 163), (118, 50) */
STATE Wait_for_GUI;
ENDSTATE;
ENDPROCESS orchestrator;
ENDPROCESS orchestrator;
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment