Skip to content

Commit

Permalink
Merge branch 'master' into u-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
YaRiabtsev committed Aug 30, 2022
2 parents 3cb68c8 + 57b602c commit e812a2a
Show file tree
Hide file tree
Showing 313 changed files with 3,889 additions and 5,478 deletions.
2 changes: 1 addition & 1 deletion project/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${BUILD_DIR}/../bin")

include_directories(${CMAKE_SOURCE_DIR})
add_subdirectory(src/transpiler)
add_subdirectory(tests/unit_tests)
add_subdirectory(tests/unit_tests)
26 changes: 13 additions & 13 deletions project/scripts/build_c2eo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,37 @@
SOFTWARE.
"""

import os
import sys
import argparse
import subprocess
from os import chdir
from pathlib import Path

# Our scripts
import tools
import settings


def main(path_to_c2eo_build, cmake_cmd='cmake ..'):
def main(path_to_c2eo_build: Path, cmake_cmd: str = 'cmake ..') -> None:
tools.pprint()
original_path = os.getcwd()
if not os.path.exists(path_to_c2eo_build):
os.mkdir(path_to_c2eo_build)
os.chdir(path_to_c2eo_build)
original_path = Path.cwd()
path_to_c2eo_build.mkdir(exist_ok=True)
chdir(path_to_c2eo_build)
result = subprocess.run(cmake_cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
if result.returncode:
tools.pprint_status_result(cmake_cmd, tools.EXCEPTION, result.stderr)
os.chdir(original_path)
chdir(original_path)
exit('Failed during cmake execution')

tools.pprint(result.stdout, slowly=True)
result = subprocess.run(f'make -j {tools.cpu_count()}', shell=True)
os.chdir(original_path)
if result.returncode != 0:
chdir(original_path)
if result.returncode:
exit('Failed during make execution')
tools.pprint()


def create_parser():
def create_parser() -> argparse.ArgumentParser:
_parser = argparse.ArgumentParser(description='the script for building c2eo in the specified directory')

_parser.add_argument('-p', '--path_to_c2eo_build', default=settings.get_setting('path_to_c2eo_build'),
Expand All @@ -63,7 +63,7 @@ def create_parser():


if __name__ == '__main__':
tools.move_to_script_dir(sys.argv[0])
tools.move_to_script_dir(Path(sys.argv[0]))
parser = create_parser()
namespace = parser.parse_args()
main(namespace.path_to_c2eo_build)
main(Path(namespace.path_to_c2eo_build))
59 changes: 36 additions & 23 deletions project/scripts/build_eo.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
SOFTWARE.
"""

import os
import sys
import csv
import json
import subprocess
from os import chdir
from os import sep as os_sep
from pathlib import Path

# Our scripts
import tools
Expand All @@ -35,7 +39,7 @@

class EOBuilder(object):

def __init__(self, transpilation_units):
def __init__(self, transpilation_units: list[dict]):
self.path_to_eo_project = settings.get_setting('path_to_eo_project')
self.current_version = settings.get_setting('current_eo_version')
self.path_to_foreign_objects = settings.get_setting('path_to_foreign_objects')
Expand All @@ -45,14 +49,16 @@ def __init__(self, transpilation_units):
self.errors = set()
self.error_result = {}

def build(self):
def build(self) -> (set[dict], dict):
tools.pprint('Compilation start\n')
original_path = os.getcwd()
os.chdir(self.path_to_eo_project)
result = self.is_recompilation()
tools.pprint(f'\n{"Recompilation eo project starts" if result else "Full eo project compilation starts"}\n')
cmd = ['mvn'] if result else ['mvn', 'clean']
cmd.extend(['compile', '-Djansi.force=true', '-Dstyle.color=always'])
original_path = Path.cwd()
chdir(self.path_to_eo_project)
can_recompile = self.is_recompilation()
if can_recompile:
cmd, _ = ['mvn'], tools.pprint('\nRecompilation eo project starts')
else:
cmd, _ = ['mvn', 'clean'], tools.pprint('Full eo project compilation starts\n')
cmd.extend(['compile', '-D', 'jansi.force=true', '-D' 'style.color=always'])
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, text=True)
for line in process.stdout:
if line:
Expand All @@ -61,13 +67,13 @@ def build(self):
self.handle_eo_error(line)
elif process.poll() is not None:
break
os.chdir(original_path)
chdir(original_path)
if process.poll():
exit('compilation failed')
return self.errors, self.error_result

def is_recompilation(self):
if not os.path.exists(self.path_to_foreign_objects):
def is_recompilation(self) -> bool:
if not self.path_to_foreign_objects.exists():
tools.pprint('Compile dir not found', status=tools.WARNING)
return False

Expand All @@ -77,12 +83,12 @@ def is_recompilation(self):
return False

tools.pprint('Latest version detected', status=tools.PASS)
eo_src_files = tools.search_files_by_patterns(self.path_to_eo, ['*.eo'], recursive=True)
eo_src_files = set(map(lambda x: x.replace(self.path_to_eo, '', 1).replace('.eo', '', 1), eo_src_files))
project_eo_files = tools.search_files_by_patterns(self.path_to_eo_parse, ['*.xmir'],
recursive=True, filters=['!org/eolang'])
project_eo_files = set(map(lambda x: x.replace(self.path_to_eo_parse, '', 1).replace('.xmir', '', 1),
project_eo_files))
eo_src_files = tools.search_files_by_patterns(self.path_to_eo, {'*.eo'}, recursive=True)
eo_src_files = {Path(str(x).replace(self.path_to_eo, '', 1).replace('.eo', '', 1)) for x in eo_src_files}
project_eo_files = tools.search_files_by_patterns(self.path_to_eo_parse, {'*.xmir'},
recursive=True, filters={'!org/eolang'})
project_eo_files = {Path(str(x).replace(self.path_to_eo_parse, '', 1).replace('.xmir', '', 1)) for x in
project_eo_files}
difference = project_eo_files - eo_src_files
tools.pprint()
if difference:
Expand All @@ -93,18 +99,25 @@ def is_recompilation(self):
tools.pprint('EO project files are compatible', status=tools.PASS)
return True

def is_actual_object_version(self):
def is_actual_object_version(self) -> bool:
tools.pprint('\nCheck version of compiled eo objects\n')
data = tools.read_file_as_dictionary(self.path_to_foreign_objects)
data = []
if not self.path_to_foreign_objects.exists():
return False

with open(self.path_to_foreign_objects) as f:
reader = csv.DictReader(f)
for row in reader:
data.append(row)
for package in data:
if package['version'] not in ['*.*.*', '0.0.0']:
compare = tools.version_compare(self.current_version, package['version'])
if compare <= 0:
return True
return False

def handle_eo_error(self, message):
file, error = message.split('/', maxsplit=1)[1].split('with error:', maxsplit=1)
def handle_eo_error(self, message) -> None:
file, error = message.split(os_sep, maxsplit=1)[1].split('with error:', maxsplit=1)
file, error = file.strip(), error.strip()
for unit in self.transpilation_units:
if unit['unique_name'] in file:
Expand All @@ -116,5 +129,5 @@ def handle_eo_error(self, message):


if __name__ == '__main__':
tools.move_to_script_dir(sys.argv[0])
tools.move_to_script_dir(Path(sys.argv[0]))
EOBuilder([]).build()
1 change: 0 additions & 1 deletion project/scripts/c2eo-all.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
if __name__ == '__main__':
path_to_c_files = os.path.abspath(sys.argv[1])
if not os.path.exists(path_to_c_files):
print('This path does not exist')
exit('This path does not exist')

clean_before_transpilation.main(path_to_c_files)
Expand Down
50 changes: 24 additions & 26 deletions project/scripts/clang_tidy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@
SOFTWARE.
"""

import os
import sys
import time
import argparse
import subprocess
from os import chdir
from pathlib import Path

# Our scripts
import settings
Expand All @@ -37,28 +38,25 @@

class ClangTidy(object):

def __init__(self, path_to_code_files):
def __init__(self, path_to_code_files: Path):
self.filters = None
if os.path.isfile(path_to_code_files):
self.filters = [os.path.split(path_to_code_files)[1]]
path_to_code_files = os.path.dirname(path_to_code_files)
if path_to_code_files.is_file():
self.filters = {path_to_code_files.name}
path_to_code_files = path_to_code_files.parent
self.path_to_code_files = path_to_code_files
self.files_handled_count = 0
self.files_count = 0
self.path_to_c2eo_build = settings.get_setting('path_to_c2eo_build')
if not os.path.exists(self.path_to_c2eo_build):
os.mkdir(self.path_to_c2eo_build)
self.ignored_inspection_warnings = settings.get_setting('ignored_inspection_warnings')
if not self.ignored_inspection_warnings:
self.ignored_inspection_warnings = []
self.path_to_c2eo_build.mkdir(exist_ok=True)
self.ignored_inspection_warnings = settings.get_setting('ignored_inspection_warnings') or []
self.clang_tidy_checks = ','.join(settings.get_setting('clang_tidy_checks'))
self.results = []
self.results: list[dict[str, str | Path | subprocess.CompletedProcess]] = []

def inspect(self):
def inspect(self) -> bool:
start_time = time.time()
tools.pprint('\nInspection start\n')
self.generate_compile_commands()
patterns = settings.get_setting('code_file_patterns')
patterns = set(settings.get_setting('code_file_patterns'))
code_files = tools.search_files_by_patterns(self.path_to_code_files, patterns, filters=self.filters,
recursive=True, print_files=True)
self.files_count = len(code_files)
Expand All @@ -67,30 +65,30 @@ def inspect(self):
with tools.thread_pool() as threads:
self.results = [result for result in threads.map(self.inspect_file, code_files)]
result = self.group_inspection_results()
_is_failed = len(result[tools.WARNING]) + len(result[tools.EXCEPTION])
_is_failed = len(result[tools.WARNING]) + len(result[tools.EXCEPTION]) > 0
tools.pprint_result('INSPECTION', self.files_count, int(time.time() - start_time), result, _is_failed)
return _is_failed

def generate_compile_commands(self):
original_path = os.getcwd()
os.chdir(self.path_to_c2eo_build)
def generate_compile_commands(self) -> None:
original_path = Path.cwd()
chdir(self.path_to_c2eo_build)
cmd = f'cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=ON'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
os.chdir(original_path)
chdir(original_path)
if result.returncode != 0:
tools.pprint_status_result(cmd, tools.EXCEPTION, result.stderr)
exit('Failed during cmake execution')
tools.pprint(result.stdout, slowly=True)

def inspect_file(self, file):
def inspect_file(self, file: Path) -> dict[str, str | Path | subprocess.CompletedProcess]:
transpile_cmd = f'clang-tidy -p {self.path_to_c2eo_build} --checks=\'{self.clang_tidy_checks}\' {file}'
result = subprocess.run(transpile_cmd, shell=True, capture_output=True, text=True)
self.files_handled_count += 1
tools.print_progress_bar(self.files_handled_count, self.files_count)
return {'name': tools.get_file_name(file), 'file': os.path.basename(file), 'inspection_result': result}
return {'name': file.stem, 'file': file.name, 'inspection_result': result}

def group_inspection_results(self):
result = {tools.PASS: set([unit['file'] for unit in self.results]), tools.NOTE: {}, tools.WARNING: {},
def group_inspection_results(self) -> dict[str, set[str] | dict[str, [dict[str, set[str]]]]]:
result = {tools.PASS: {unit['file'] for unit in self.results}, tools.NOTE: {}, tools.WARNING: {},
tools.ERROR: {}, tools.EXCEPTION: {}}
tools.pprint('\nGetting results\n', slowly=True, on_the_next_line=True)
for unit in self.results:
Expand All @@ -116,11 +114,11 @@ def group_inspection_results(self):
if unit['file'] in place:
result[status][message][unit['file']].add(place.split(':', 1)[1][:-2])
for status in [tools.WARNING, tools.ERROR, tools.EXCEPTION]:
result[tools.PASS] -= set(file for value in result[status].values() for file in value.keys())
result[tools.PASS] -= {file for value in result[status].values() for file in value.keys()}
return result


def create_parser():
def create_parser() -> argparse.ArgumentParser:
_parser = argparse.ArgumentParser(description='script for checking code files using Clang-Tidy')

_parser.add_argument('-p', '--path_to_code_files', default=settings.get_setting('path_to_code_files'),
Expand All @@ -129,9 +127,9 @@ def create_parser():


if __name__ == '__main__':
tools.move_to_script_dir(sys.argv[0])
tools.move_to_script_dir(Path(sys.argv[0]))
parser = create_parser()
namespace = parser.parse_args()
is_failed = ClangTidy(namespace.path_to_code_files).inspect()
is_failed = ClangTidy(Path(namespace.path_to_code_files)).inspect()
if is_failed:
exit(f'clang-tidy checks failed')
19 changes: 10 additions & 9 deletions project/scripts/clean_before_transpilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,26 @@
SOFTWARE.
"""

import os

import sys
import argparse
from pathlib import Path

# Our scripts
import tools
import settings


def main(path_to_files):
patterns = settings.get_setting('patterns_for_cleaning')
if os.path.isfile(path_to_files):
path_to_files = os.path.dirname(path_to_files)
def main(path_to_files: Path) -> None:
patterns = set(settings.get_setting('patterns_for_cleaning'))
if path_to_files.is_file():
path_to_files = path_to_files.parent
tools.clear_dir_by_patterns(path_to_files, patterns, recursive=True)
tools.remove_empty_dirs(path_to_files)
tools.clear_dir_by_patterns(settings.get_setting('path_to_c2eo_transpiler'), ['*.eo'])
tools.clear_dir_by_patterns(settings.get_setting('path_to_c2eo_transpiler'), {'*.eo'})


def create_parser():
def create_parser() -> argparse.ArgumentParser:
_parser = argparse.ArgumentParser(description='the script for cleaning the folder from temporary files')

_parser.add_argument('-p', '--path_to_files', metavar='PATH', default=settings.get_setting('path_to_tests'),
Expand All @@ -51,7 +52,7 @@ def create_parser():


if __name__ == '__main__':
tools.move_to_script_dir(sys.argv[0])
tools.move_to_script_dir(Path(sys.argv[0]))
parser = create_parser()
namespace = parser.parse_args()
main(namespace.path_to_files)
main(Path(namespace.path_to_files))
22 changes: 10 additions & 12 deletions project/scripts/code_lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,26 @@
SOFTWARE.
"""

import os
import sys
import glob
import subprocess
from pathlib import Path

if __name__ == '__main__':
path_to_files = os.path.abspath(sys.argv[1])
if not os.path.exists(path_to_files):
print('This path does not exist')
path_to_files = Path(sys.argv[1]).resolve()
if not path_to_files.exists():
exit('This path does not exist')

path_to_files = os.path.join(path_to_files, '**')
code_lines = {'c': 0, 'i': 0, 'eo': 0, 'h': 0}
if len(sys.argv) == 3 and sys.argv[2] in code_lines.keys():
code_lines = {sys.argv[2]: 0}
for extension in code_lines.keys():
files = glob.glob(os.path.join(path_to_files, f'*.{extension}'), recursive=True)
files = path_to_files.rglob(f'*.{extension}')
if extension == 'c':
files = list(filter(lambda f: '-eo.c' not in f, files))
files = {f for f in files if not f.match('-eo.c')}
lines_count = 0
files_count = 0
for file in files:
result = subprocess.run(f'wc -l {file}', shell=True, text=True, capture_output=True)
lines_count += int(result.stdout.split()[0])
lines_count = '{0:7,}'.format(lines_count).replace(',', ' ')
print(f'*.{extension:2} | files: {len(files):3} | lines: {lines_count}')
if result := subprocess.run(f'wc -l {file}', shell=True, text=True, capture_output=True).stdout.split():
lines_count += int(result[0])
files_count += 1
print(f'*.{extension:2} | files: {files_count:5,} | lines: {lines_count:7,}')
Loading

1 comment on commit e812a2a

@0pdd
Copy link
Member

@0pdd 0pdd commented on e812a2a Aug 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to retrieve PDD puzzles from the code base and submit them to github. If you think that it's a bug on our side, please submit it to yegor256/0pdd:

set -x && set -e && set -o pipefail && cd /tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ && pdd -v -f /tmp/20220830-20726-jtvppc [1]: + set -e + set -o pipefail + cd /tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ + pdd -v -f...

Please, copy and paste this stack trace to GitHub:

UserError
set -x && set -e && set -o pipefail && cd /tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ && pdd -v -f /tmp/20220830-20726-jtvppc [1]:
+ set -e
+ set -o pipefail
+ cd /tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ
+ pdd -v -f /tmp/20220830-20726-jtvppc

My version is 0.21.3
Ruby version is 2.7.5 at x86_64-linux
Reading from root dir /tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ
/tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ/project/scripts/data/skips/test.txt is a binary file (0 bytes)
/tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ/project/tests/in_progress/for_main/.gitkeep is a binary file (0 bytes)
/tmp/0pdd20220830-13-3bdnp/Z2l0QGdpdGh1Yi5jb206cG9seXN0YXQvYzJlby5naXQ/result/eo/c2eo/src/.gitkeep is a binary file (0 bytes)
Reading .gitignore ...
Reading .gitattributes ...
Reading Dockerfile ...
Reading .rultor.yml ...
Reading project/CMakeLists.txt ...
Reading project/scripts/build_c2eo.py ...
Reading project/scripts/build_eo.py ...
Reading project/scripts/code_lines.py ...
Reading project/scripts/c2eo-all.py ...
Reading project/scripts/clang_tidy.py ...
Reading project/scripts/compile.py ...
Reading project/scripts/readme.md ...
Reading project/scripts/clean_before_transpilation.py ...
Reading project/scripts/tools.py ...
Reading project/scripts/update-release.py ...
Reading project/scripts/test.py ...
Reading project/scripts/transpile.py ...
Reading project/scripts/codecov.py ...
Reading project/scripts/data/settings.yml ...
Reading project/scripts/data/meta/run.sh.txt ...
Reading project/scripts/data/meta/plug.txt ...
Reading project/scripts/data/skips/gcc.txt ...
Reading project/scripts/data/skips/testcuite.txt ...
ERROR: project/scripts/data/skips/testcuite.txt; PDD::Error at project/scripts/data/skips/testcuite.txt:1: TODO found, but puzzle can't be parsed, most probably because TODO is not followed by a puzzle marker, as this page explains: https://github.com/cqfn/pdd#how-to-format
If you can't understand the cause of this issue or you don't know how to fix it, please submit a GitHub issue, we will try to help you: https://github.com/cqfn/pdd/issues. This tool is still in its beta version and we will appreciate your feedback. Here is where you can find more documentation: https://github.com/cqfn/pdd/blob/master/README.md.
Exit code is 1

/app/objects/git_repo.rb:73:in `rescue in block in xml'
/app/objects/git_repo.rb:70:in `block in xml'
/app/vendor/ruby-2.7.5/lib/ruby/2.7.0/tempfile.rb:291:in `open'
/app/objects/git_repo.rb:69:in `xml'
/app/objects/puzzles.rb:41:in `deploy'
/app/objects/jobs/job.rb:38:in `proceed'
/app/objects/jobs/job_starred.rb:32:in `proceed'
/app/objects/jobs/job_recorded.rb:31:in `proceed'
/app/objects/jobs/job_emailed.rb:33:in `proceed'
/app/objects/jobs/job_commiterrors.rb:33:in `proceed'
/app/objects/jobs/job_detached.rb:48:in `exclusive'
/app/objects/jobs/job_detached.rb:36:in `block in proceed'
/app/objects/jobs/job_detached.rb:36:in `fork'
/app/objects/jobs/job_detached.rb:36:in `proceed'
/app/0pdd.rb:518:in `process_request'
/app/0pdd.rb:355:in `block in <top (required)>'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1686:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1686:in `block in compile!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1023:in `block (3 levels) in route!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1042:in `route_eval'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1023:in `block (2 levels) in route!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1071:in `block in process_route'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1069:in `catch'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1069:in `process_route'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1021:in `block in route!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1018:in `each'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1018:in `route!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1140:in `block in dispatch!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1112:in `block in invoke'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1112:in `catch'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1112:in `invoke'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1135:in `dispatch!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:949:in `block in call!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1112:in `block in invoke'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1112:in `catch'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1112:in `invoke'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:949:in `call!'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:938:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-protection-2.2.2/lib/rack/protection/xss_header.rb:18:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-protection-2.2.2/lib/rack/protection/path_traversal.rb:16:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-protection-2.2.2/lib/rack/protection/json_csrf.rb:26:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-protection-2.2.2/lib/rack/protection/base.rb:50:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-protection-2.2.2/lib/rack/protection/base.rb:50:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-protection-2.2.2/lib/rack/protection/frame_options.rb:31:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-2.2.4/lib/rack/logger.rb:17:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-2.2.4/lib/rack/common_logger.rb:38:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:255:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:248:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-2.2.4/lib/rack/head.rb:12:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-2.2.4/lib/rack/method_override.rb:24:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:218:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1993:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1553:in `block in call'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1769:in `synchronize'
/app/vendor/bundle/ruby/2.7.0/gems/sinatra-2.2.2/lib/sinatra/base.rb:1553:in `call'
/app/vendor/bundle/ruby/2.7.0/gems/rack-2.2.4/lib/rack/handler/webrick.rb:95:in `service'
/app/vendor/ruby-2.7.5/lib/ruby/2.7.0/webrick/httpserver.rb:140:in `service'
/app/vendor/ruby-2.7.5/lib/ruby/2.7.0/webrick/httpserver.rb:96:in `run'
/app/vendor/ruby-2.7.5/lib/ruby/2.7.0/webrick/server.rb:307:in `block in start_thread'

Please sign in to comment.