Commit 93639f28 authored by unknown's avatar unknown

refactor

parent 3d80e0e2
Pipeline #3307 failed with stage
in 35 seconds
......@@ -15,7 +15,7 @@ class File:
Wrapper over IO operations
"""
supported_extension = ('.c', 'py', 'java', 'cpp', '.h')
source_extension = re.compile('\w+.(\w+)')
source_extension = re.compile(r'\w+.(\w+)')
def __init__(self, folder_id, create_directory=True):
self.id = folder_id
......@@ -37,16 +37,16 @@ class File:
"""
os.mkdir(self.concrete_directory, 0o755)
file_obj = request_files
for f in file_obj:
file = request.files.get(f)
for concrete_file in file_obj:
file = request.files.get(concrete_file)
whole_path = os.path.join(self.concrete_directory, file.filename)
try:
# file.save(fd, secure_filename(file.filename))
fd = open(whole_path, "w+")
file_descriptor = open(whole_path, "w+")
# decode to utf-8 format and convert \r\n to \n
msg = "\n".join(file.read().decode("utf-8").splitlines())
fd.write(msg)
fd.close()
file_descriptor.write(msg)
file_descriptor.close()
except Exception as e:
Logger.error.log(e)
......@@ -61,12 +61,12 @@ class File:
file_dir = os.path.join(self.concrete_directory, file)
if file.endswith('.txt'): # report
with open(file_dir, "r") as f:
report = f.read()
with open(file_dir, "r") as concrete_file:
report = concrete_file.read()
elif file.endswith(self.supported_extension):
with open(file_dir, "r") as f:
source_file.append({file: f.read()})
with open(file_dir, "r") as concrete_file:
source_file.append({file: concrete_file.read()})
extension = self.source_extension.search(file).group(1)
return {
'report': report,
......@@ -106,15 +106,15 @@ class File:
for file in files:
if file.endswith('json'):
with open(os.path.join(file_path, file), 'r') as f:
unified_report = json.load(f)
with open(os.path.join(file_path, file), 'r') as concrete_file:
unified_report = json.load(concrete_file)
elif file.endswith('.txt'):
with open(os.path.join(file_path, file), 'r') as f:
raw_report = f.read()
with open(os.path.join(file_path, file), 'r') as concrete_file:
raw_report = concrete_file.read()
else:
with open(os.path.join(file_path, file), 'r') as f:
with open(os.path.join(file_path, file), 'r') as concrete_file:
source_files.append({
file: f.read()
file: concrete_file.read()
})
else:
arr.append({
......
......@@ -2,10 +2,10 @@
@author Jakub Dolejsi
"""
from core.Core import Core
from flask import Flask
from flask_cors import CORS
from flask_restful import Api
from flask_cors import CORS
from core.Core import Core
from resources.v1.RepViewInterface import RepViewInterface
app = Flask(__name__)
......
......@@ -9,11 +9,11 @@ from os import environ
from pkgutil import iter_modules
from typing import Dict, List
from File import File
from core.Guesser import Guesser
from logger.Logger import Logger
from parse.GenericParser import GenericParser
from werkzeug.datastructures import MultiDict
from core.Guesser import Guesser
from logger.Logger import Logger
from File import File
class Core:
......@@ -27,7 +27,13 @@ class Core:
def __init__(self) -> None:
self.__register_tools()
def randomStr(self, n):
@staticmethod
def generate_random_string(n):
"""
Generates random string
@param n: number of string letter
@return: random string of N symbols
"""
return ''.join(random.choices(string.ascii_lowercase + string.digits + string.ascii_uppercase, k=n))
def process_request(self, uploaded_files: MultiDict, form: MultiDict) -> None:
......@@ -40,24 +46,24 @@ class Core:
folder_id = form.get('url')[1:]
file = ''
if folder_id == '':
folder_id = self.randomStr(20)
folder_id = self.generate_random_string(20)
try:
file = File(folder_id)
file.process(uploaded_files)
self.__bundled_source = file.export_sources()
except Exception as fe:
Logger.error.log('Error occurred while parsing file: {}'.format(fe))
except Exception as f_e:
Logger.error.log('Error occurred while parsing file: {}'.format(f_e))
self.__choose_tool(form)
try:
self.__tool.parse()
except Exception as pe:
Logger.error.log('Error occurred while parsing report: {}'.format(pe))
except Exception as p_e:
Logger.error.log('Error occurred while parsing report: {}'.format(p_e))
try:
file.save_unified_report(self.__tool.internal_structure.get(clear=True))
except Exception as fe:
Logger.error.log('Error while creating json file: {}'.format(fe))
except Exception as f_e:
Logger.error.log('Error while creating json file: {}'.format(f_e))
def __choose_tool(self, form) -> None:
"""
......@@ -88,9 +94,9 @@ class Core:
try:
for _, name, _ in iter_modules(['parse']):
import_module('.' + name, 'parse')
except TypeError as te:
Logger.error.log(message='Problem occurred while importing classes: {}'.format(te), f_exit=True)
print(str(te))
except TypeError as t_e:
Logger.error.log(message='Problem occurred while importing classes: {}'.format(t_e), f_exit=True)
print(str(t_e))
self.__registered_base_classes = {cls.__name__: cls for cls in GenericParser.__subclasses__() if
'register' in cls.__dict__}
......
"""
@author Jakub Dolejsi
"""
class Environment:
"""
Class that contains environment settings
"""
logger_directory = 'log_dir'
......@@ -6,6 +6,9 @@ import re
class Guesser():
"""
Class that try to select parsing tool automatically
"""
tools = None
report = None
extension = None
......@@ -16,6 +19,10 @@ class Guesser():
self.extension = ext
def guess(self):
"""
Process choosing parsing tool
@return: chosen tool if found
"""
# get all tools that have supported extensions same as file extension
valid_tools = []
......
......@@ -8,10 +8,13 @@ from parse.GenericParser import GenericParser
class GccParser(GenericParser):
"""
Class for parsing gcc report
"""
GCC_PARSE_PATTERN = re.compile(
'((?P<function>\'(.*)\'):(?P<file>[^:]+):(?P<line>\d+):)(?P<col>\d+):? (?P<type>warning|[eE]rror|fatal error): (?P<message>.+)')
r'((?P<function>\'(.*)\'):(?P<file>[^:]+):(?P<line>\d+):)(?P<col>\d+):? (?P<type>warning|[eE]rror|fatal error): (?P<message>.+)')
pattern = '((?P<function>\'(.*)\'):(?P<file>[^:]+):(?P<line>\d+):)(?P<col>\d+):? (?P<type>warning|[eE]rror|fatal error): (?P<message>.+)'
pattern = r'((?P<function>\'(.*)\'):(?P<file>[^:]+):(?P<line>\d+):)(?P<col>\d+):? (?P<type>warning|[eE]rror|fatal error): (?P<message>.+)'
@staticmethod
def import_report():
......@@ -25,7 +28,7 @@ class GccParser(GenericParser):
"""
self.tool.name = 'gcc'
self.tool.supported_extensions = ['c', 'h']
self.tool.guess_pattern = '(.*): In function'
self.tool.guess_pattern = r'(.*): In function'
def parse(self):
"""
......
......@@ -2,13 +2,15 @@
@author Jakub Dolejsi
"""
import functools
from typing import Dict
from parse.ReportSet import ReportSet
from parse.Tool import Tool
class GenericParser(object):
class GenericParser:
"""
Base class for parsing reports. All implemented tools for parsing report must inherit from this class
"""
all_tools = list()
internal_structure = ReportSet()
tool = None
......@@ -16,54 +18,84 @@ class GenericParser(object):
def __init__(self, report: str):
self.report = report
def register_tool(f):
def wrapper(self):
self.tool = Tool()
f(self)
self.tool.supported_extensions.append('txt')
self.tool.class_name = self.__name__
def register_tool(self):
"""
Register tool decorator
@return:wrapper method
"""
def wrapper(this):
this.tool = Tool()
this(this)
this.tool.supported_extensions.append('txt')
this.tool.class_name = this.__name__
# self.all_tools.append(self.tool)
GenericParser.all_tools.append(self.tool)
GenericParser.all_tools.append(this.tool)
return wrapper
def parse(self):
pass
"""
Generic parse method, which all parses must implement
@return: None
"""
@classmethod
def get_tools(cls):
"""
Retrieve all registered tools
@return: list of registered tools
"""
return [x.get() for x in cls.all_tools]
@classmethod
def get_tool_by_name(cls, name):
"""
Find parsing tool by registered name
@param name: nam of the parsing tools
@return: tool if found, else None
"""
for tool in cls.all_tools:
if tool.name == name:
return tool.class_name
return None
def set_object_property(self, obj, attr, val):
"""
Wrapper at set attribute dunder method
@param obj: input user object
@param attr: index
@param val: value
@return: None
"""
pre, _, post = attr.rpartition('.')
return setattr(self.__rgetattr(obj, pre) if pre else obj, post, val)
def __rgetattr(self, obj, attr, *args):
"""
Wrapper at get attribute dunder method
@param obj: input user object
@param attr: index
@param args: nested object
@return: Retrieved attribute
"""
def _getattr(obj, attr):
return getattr(obj, attr, *args)
return functools.reduce(_getattr, [obj] + attr.split('.'))
def init_backtrace(self, rep, n):
def init_backtrace(self, rep, number):
"""
Initialize Report object with nested backtrace
@param rep: Report object
@param n: number of nested objects
@param number: number of nested objects
@return: Initialized Report object and array of nested backtrace properties
"""
arr = ['Backtrace']
for i in range(1, n):
for i in range(1, number):
arr.append('Backtrace' + ('.Backtrace' * i))
for r, i in zip(range(n), arr):
for _, i in zip(range(number), arr):
self.set_object_property(rep, i, self.internal_structure.create_new_report())
# set first index to emtpy string because in regex loop we need something and this index
......
......@@ -8,38 +8,41 @@ from parse.GenericParser import GenericParser
class HelgrindParser(GenericParser):
begin_stack_regexp = re.compile('^\s*at')
continue_stack_regexp = re.compile('^\s*by')
function_regexp = re.compile(':\s*(\w*)\s*')
file_regexp = re.compile('\s*\((.*)]*:')
line_number_regexp = re.compile(':(\d+)\)')
"""
Class for parsing helgrind report
"""
begin_stack_regexp = re.compile(r'^\s*at')
continue_stack_regexp = re.compile(r'^\s*by')
function_regexp = re.compile(r':\s*(\w*)\s*')
file_regexp = re.compile(r'\s*\((.*)]*:')
line_number_regexp = re.compile(r':(\d+)\)')
general_info = '((?P<message>.*#(?P<thread>[\d])\n))'
concrete_traceback = '(at|by).*:\s(?P<function>.*)\s\((?P<file>.*):(?P<lino>[\d]*)'
general_info = r'((?P<message>.*#(?P<thread>[\d])\n))'
concrete_traceback = r'(at|by).*:\s(?P<function>.*)\s\((?P<file>.*):(?P<lino>[\d]*)'
function = 'at\s(.*):\s(?P<function>(.*))\s\('
file = '\s\((?P<file>.*:)'
line = '\((.*:)(?P<lino>[\d]*)'
function = r'at\s(.*):\s(?P<function>(.*))\s\('
file = r'\s\((?P<file>.*:)'
line = r'\((.*:)(?P<lino>[\d]*)'
def Import(self):
"""Import report in unified format and transfer it into data structure"""
print("Importing...")
@GenericParser.register_tool
def register(self):
"""
Register tool
@return: None
"""
self.tool.name = 'Helgrind'
self.tool.supported_extensions = ['c', 'h']
self.tool.guess_pattern = 'Possible data race during'
def parse(self):
"""
Export report
Process report parsing
"""
first_trace_index = self.report.find('Possible')
self.report = self.report[first_trace_index:].strip()
second_trace_index = self.report.find('This conflicts')
# TODO expecting only two tracebacks, it maybe should be more...
second_trace = self.report[second_trace_index:]
first_trace = self.report[:second_trace_index]
final_iter = [first_trace, second_trace]
......@@ -61,5 +64,3 @@ class HelgrindParser(GenericParser):
self.set_object_property(new_report, traceback + '.Thread', thread)
self.internal_structure.add_report_to_set(new_report)
pass # debug breakpoint
......@@ -10,17 +10,28 @@ from parse.GenericParser import GenericParser
class JavaParser(GenericParser):
TRACEBACK_PATTERN = 'at (?P<function>.*)\((?P<file>.*):(?P<lino>.*)\)'
"""
Class for parsing java traceback
"""
TRACEBACK_PATTERN = r'at (?P<function>.*)\((?P<file>.*):(?P<lino>.*)\)'
COMPILE_PATTERN = ''
CONTEXT_PATTERN = 'thread \"(?P<thread>.*)(?P<exception>java.((.*):))(?P<message>.*)'
CONTEXT_PATTERN = r'thread \"(?P<thread>.*)(?P<exception>java.((.*):))(?P<message>.*)'
@GenericParser.register_tool
def register(self):
"""
Register this tool
@return:
"""
self.tool.name = 'java'
self.tool.supported_extensions = ['java']
self.tool.guess_pattern = 'Exception in'
def parse(self):
"""
Process parsing of traceback
@return:
"""
e = re.search(self.CONTEXT_PATTERN, self.report).group('exception')
m = re.search(self.CONTEXT_PATTERN, self.report).group('message')
......
......@@ -8,7 +8,10 @@ from parse.GenericParser import GenericParser
class PythonParser(GenericParser):
pattern = 'File(\s\"(.+/(?P<file>.+))\"),\sline\s(?P<line>.*),\sin\s(?P<function>.*)'
"""
Class for parsing python traceback
"""
pattern = r'File(\s\"(.+/(?P<file>.+))\"),\sline\s(?P<line>.*),\sin\s(?P<function>.*)'
@GenericParser.register_tool
def register(self):
......@@ -20,6 +23,10 @@ class PythonParser(GenericParser):
self.tool.guess_pattern = 'Traceback' # unique for all reports
def parse(self):
"""
Process traceback parsing
@return: None
"""
if self.report.startswith('Traceback'):
message = self.report.splitlines()[-1]
found_expressions = re.finditer(self.pattern, self.report)
......
......@@ -48,7 +48,11 @@ class ReportSet:
return Report()
def clear(f):
"""
Clears report set
@return: empty report set
"""
def clean_set(self):
ex = f(self)
f(self)
return clean_set
......@@ -8,7 +8,10 @@ from parse.GenericParser import GenericParser
class ValgrindParser(GenericParser):
STACK_TRACE_PATTERN = '(at|by).*:\s(?P<function>.*)\s\(in (?P<file>.*):(?P<lino>[\d]*)'
"""
Class for parsing valgrind report
"""
STACK_TRACE_PATTERN = r'(at|by).*:\s(?P<function>.*)\s\(in (?P<file>.*):(?P<lino>[\d]*)'
ERROR_TYPES = ['Invalid read of size', 'Invalid write of size', 'Conditional jump',
'Syscall param write', 'Invalid free', 'Mismatched free',
......@@ -16,15 +19,23 @@ class ValgrindParser(GenericParser):
@GenericParser.register_tool
def register(self):
"""
Register valgrind parsing tool
@return:
"""
self.tool.supported_extensions = ['c', 'h']
self.tool.name = 'valgrind'
self.tool.guess_pattern = '(HEAP SUMMARY|LEAK SUMMARY|ERROR SUMMARY)'
def parse(self):
"""
Process parsing
@return: None
"""
first_trace_index = ''
for type in self.ERROR_TYPES:
for error_type in self.ERROR_TYPES:
try:
first_trace_index = self.report.find(type)
first_trace_index = self.report.find(error_type)
except Exception:
pass
if first_trace_index != -1:
......@@ -36,10 +47,8 @@ class ValgrindParser(GenericParser):
self.report = self.report[first_trace_index:]
second_trace_index = self.report.find('Address ')
last_trace_index = self.report.find('HEAP SUMMARY')
first_trace = self.report[:second_trace_index]
second_trace = self.report[last_trace_index:]
general_message = self.report.split('\n', 1)[0]
......@@ -56,4 +65,3 @@ class ValgrindParser(GenericParser):
self.set_object_property(new_report, traceback + '.Message', general_message)
self.internal_structure.add_report_to_set(new_report)
pass
......@@ -55,9 +55,8 @@ class RepViewInterface:
@raise Exception if url is not valid
"""
import re
validate_pattern = 'v(\d)'
validate_pattern = r'v(\d)'
is_valid = re.search(validate_pattern, base)
if not is_valid:
raise Exception('Route :', base , ' is not valid')
raise Exception('Route :', base, ' is not valid')
......@@ -19,9 +19,9 @@ class BaseEndpoint(Resource):
Method for accepting options HTTP method
@param kwargs: variable num of params
"""
pass
def dispatch_error(self, message, code):
@staticmethod
def dispatch_error(message, code):
"""
Error dispatch
@param message: message to be showed
......
......@@ -50,7 +50,8 @@ class Files(BaseEndpoint):
return jsonify(return_bundle)
def delete(self, id=None, folder=None):
@staticmethod
def delete(id=None, folder=None):
"""
Delete all content in folder specified by id param
or
......@@ -76,7 +77,8 @@ class Files(BaseEndpoint):
for folder in folders:
shutil.rmtree(os.path.join(folder_to_delete, folder), ignore_errors=True)
def put(self, id, folder):
@staticmethod
def put( id, folder):
"""
Rename folder name
@param id: string specifying concrete user
......
......@@ -634,4 +634,10 @@ export default {
.history
font-family: "Yu Gothic UI Light", sans-serif
.cursor-move
:cursor move
:user-select none
:padding-bottom 8px
:padding-top 8px
</style>
......@@ -16,7 +16,7 @@ def step_impl(context):
@then("source code is displayed")
def step_impl(context):
el = context.driver.find_element_by_xpath('//*[@id="rep"]/div[2]/span/span').text
el = context.driver.find_element_by_xpath('//*[@id="withoutScroll"]').text
assert el
......
......@@ -18,6 +18,7 @@ def step_impl(context):
select_files).send_keys(
os.getcwd() + '/examples/python/two/other.py')
@step("user has selected parsing tool")
def step_impl(context):
context.driver.find_element_by_xpath('//*[@id="dem"]/div/div[1]/div[2]/div/div[1]/div/div[2]/div/label').click()
......@@ -67,7 +68,7 @@ def step_impl(context):
@then("different file is opened")
def step_impl(context):
index = context.driver.find_element_by_xpath('//*[@id="source"]/div/div/div[1]/div/div[1]').\
index = context.driver.find_element_by_xpath('//*[@id="source"]/div/div/div[1]/div/div[1]'). \
get_attribute('aria-selected')
assert index == "true"
......@@ -93,7 +94,6 @@ def step_impl(context):
message = context.driver.find_element_by_xpath('/html/body/div[2]/div[6]/div/div/div/div').text
@when("user clicks on Load button")
def step_impl(context):
context.driver.find_element_by_xpath('//*[@id="history"]/div[1]/div[2]/div[2]/button[2]').click()
......@@ -116,7 +116,6 @@ def step_impl(context):
message = context.driver.find_element_by_xpath('/html/body/div[2]/div[6]/div/div/div/div').text
@then("folders are successfully deleted")
def step_impl(context):
message = context.driver.find_element_by_xpath('/html/body/div[2]/div[6]/div/div/div/div').text
......
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