Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Рефакторинг опций сборки и запуска #111

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions kks/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

import click

from kks.util.config import find_target


GPP_ARGS = [
'g++',
Expand Down Expand Up @@ -35,17 +33,35 @@
]


def compile_solution(directory, target_name, verbose, options):
target = find_target(target_name)
if target is None:
click.secho(f'No target {target_name} found', fg='red', err=True)
return None
class BuildOptions:
def __init__(self, asan=False, verbose=False):
self.asan = asan
self.verbose = verbose


class RunOptions:
def __init__(self, asan=False, valgrind=False):
self.asan = asan
self.valgrind = valgrind


class TestRunOptions(RunOptions):
def __init__(self,
continue_on_error=False,
ignore_exit_code=False,
asan=False,
valgrind=False,
is_sample=False):
super().__init__(asan=asan, valgrind=valgrind)
self.continue_on_error = continue_on_error
self.ignore_exit_code = ignore_exit_code
self.is_sample = is_sample
Comment on lines +36 to +58
Copy link
Owner

Choose a reason for hiding this comment

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

Можешь напомнить зачем это разделение?
Пока-что некрасиво получается с TestSource, в который почему-то передаются опции запуска
Хотя он еще и собирает скрипты

Copy link
Collaborator Author

@vvd170501 vvd170501 Apr 4, 2021

Choose a reason for hiding this comment

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

  • все эти опции, кроме asan, не нужны в команде build (и во всех вызовах compile_solution)
  • при запуске решения из команды run нужны только опции asan и valgrind

В TestSource сейчас нужен только ignore_exit_code для эталонного решения (возможно, стоит явно передавать его вместо всего объекта TestRunOptions). Опции / таргеты не влияют на сборку скрипта (раньше использовалась только опция для asan)



if verbose:
def compile_solution(directory, target, options):
if options.verbose:
click.secho(f'Selected target: {target}')

if options.asan is None:
options.asan = target.default_asan # will be used in run_solution
# gcc (clang) can compile c and asm files together, so everything should be ok
source_files = list(chain(*[directory.glob(f) for f in target.files]))

Expand All @@ -55,7 +71,7 @@ def compile_solution(directory, target_name, verbose, options):

click.secho('Compiling... ', fg='green', err=True, nl=False)

binary = compile_c(directory, source_files, target, verbose, options)
binary = compile_c_or_asm(directory, source_files, target, options)

if binary is None:
click.secho('Compilation failed!', fg='red', err=True)
Expand All @@ -67,7 +83,7 @@ def compile_solution(directory, target_name, verbose, options):
return binary


def compile_c(workdir, files, target, verbose, options):
def compile_c_or_asm(workdir, files, target, options):
compiler_args = [target.compiler] + target.flags
if not target.asm64bit and any(f.suffix.lower() == '.s' for f in files):
compiler_args.append('-m32')
Expand All @@ -78,15 +94,14 @@ def compile_c(workdir, files, target, verbose, options):
compiler_args,
linker_args=[f'-l{lib}' for lib in target.libs],
out_file=target.out,
verbose=verbose
)


def compile_cpp(workdir, files, options):
return compile_gnu(workdir, files, options, GPP_ARGS)


def compile_gnu(workdir, files, options, compiler_args, linker_args=[], out_file='', verbose=False):
def compile_gnu(workdir, files, options, compiler_args, linker_args=[], out_file=''):
filenames = [path.absolute() for path in files]

command = compiler_args
Expand All @@ -97,7 +112,7 @@ def compile_gnu(workdir, files, options, compiler_args, linker_args=[], out_file
command += filenames
command += linker_args

if verbose:
if options.verbose:
click.secho('\nExecuting "{}"'.format(' '.join(map(str, command))))

p = subprocess.run(command, cwd=workdir)
Expand Down
7 changes: 4 additions & 3 deletions kks/cmd/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from kks.binary import compile_solution
from kks.util.common import get_solution_directory
from kks.util.testing import RunOptions
from kks.binary import BuildOptions


@click.command(short_help='Build solution')
Expand All @@ -15,8 +15,9 @@
def build(target, verbose, asan):
directory = get_solution_directory()

options = RunOptions(
options = BuildOptions(
asan=asan,
verbose=verbose
)

compile_solution(directory, target, verbose, options)
compile_solution(directory, target, options)
5 changes: 3 additions & 2 deletions kks/cmd/gen.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import click
from tqdm import tqdm

from kks.util.testing import TestSource, RunOptions
from kks.binary import TestRunOptions
from kks.util.testing import TestSource
from kks.util.common import get_solution_directory, test_number_to_name, find_test_pairs, get_matching_suffix, \
format_file
from kks.util.script import find_script
Expand Down Expand Up @@ -37,7 +38,7 @@ def gen(output_only, generator, solution, tests, test_range, force, ignore_exit_

directory = get_solution_directory()

options = RunOptions(
options = TestRunOptions(
ignore_exit_code=ignore_exit_code
)

Expand Down
2 changes: 1 addition & 1 deletion kks/cmd/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from kks.util.click import OptFlagCommand, FlagOption, OptFlagOption, Choice2
from kks.util.common import find_workspace, get_hidden_dir, format_file
from kks.util.config import target_file, global_comment
from kks.util.targets import target_file, global_comment


@click.command(cls=OptFlagCommand)
Expand Down
26 changes: 20 additions & 6 deletions kks/cmd/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

import click

from kks.binary import compile_solution, run_solution
from kks.util.testing import RunOptions, Test
from kks.binary import BuildOptions, RunOptions, compile_solution, run_solution
from kks.util.common import get_solution_directory, find_test_pairs, format_file, test_number_to_name
from kks.util.targets import find_target
from kks.util.testing import Test


@click.command(short_help='Run solution')
Expand Down Expand Up @@ -39,12 +40,25 @@ def run(asan, valgrind, sample, test, file, target, verbose, run_args):

directory = get_solution_directory()

options = RunOptions(
asan=asan and not valgrind,
vvd170501 marked this conversation as resolved.
Show resolved Hide resolved
target = find_target(target)
if target is None:
return

if valgrind:
asan = False
elif asan is None:
asan = target.default_asan

build_options = BuildOptions(
asan=asan,
verbose=verbose,
)
run_options = RunOptions(
asan=asan,
valgrind=valgrind,
)

binary = compile_solution(directory, target, verbose, options)
binary = compile_solution(directory, target, build_options)
if binary is None:
return

Expand All @@ -56,7 +70,7 @@ def run(asan, valgrind, sample, test, file, target, verbose, run_args):
output = f'Running binary with arguments ' + click.style(' '.join(run_args), fg='red', bold=True)
click.secho(output, fg='green', err=True)

exit(run_solution(binary, list(run_args), options, test_data, capture_output=False).returncode)
exit(run_solution(binary, list(run_args), run_options, test_data, capture_output=False).returncode)


def find_test_to_run(directory, test, file, sample):
Expand Down
32 changes: 23 additions & 9 deletions kks/cmd/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import click
from tqdm import tqdm

from kks.binary import compile_solution, run_solution
from kks.util.script import find_script
from kks.util.testing import TestSource, VirtualTestSequence, RunOptions, Test
from kks.binary import BuildOptions, TestRunOptions, compile_solution, run_solution
from kks.util.common import get_solution_directory, format_file, find_test_output, test_number_to_name, \
find_test_pairs, print_diff
from kks.util.script import find_script
from kks.util.targets import find_target
from kks.util.testing import TestSource, VirtualTestSequence, Test


@click.command(name='test', short_help='Test solutions')
Expand Down Expand Up @@ -52,15 +53,28 @@ def test_(target, verbose, tests, test_range, files, sample,

directory = get_solution_directory()

options = RunOptions(
target = find_target(target)
if target is None:
return

if valgrind:
asan = False
elif asan is None:
asan = target.default_asan

build_options = BuildOptions(
asan=asan,
verbose=verbose,
)
run_options = TestRunOptions(
continue_on_error=continue_on_error,
ignore_exit_code=ignore_exit_code,
asan=asan and not valgrind,
asan=asan,
valgrind=valgrind,
is_sample=sample,
)

binary = compile_solution(directory, target, verbose, options)
binary = compile_solution(directory, target, build_options)
if binary is None:
return

Expand All @@ -75,11 +89,11 @@ def test_(target, verbose, tests, test_range, files, sample,
click.secho('No tests to run!', fg='red')
return

run_tests(binary, tests, options)
run_tests(binary, tests, run_options)
else:
generator = find_script(directory, 'gen', default=generator)
solution = find_script(directory, 'solve', default=solution)
with TestSource(generator, solution, options) as test_source:
with TestSource(generator, solution, run_options) as test_source:
if test_range:
l, r = sorted(test_range)
test_range = range(l, r + 1)
Expand All @@ -91,7 +105,7 @@ def test_(target, verbose, tests, test_range, files, sample,

tests = VirtualTestSequence(test_source, all_tests)

run_tests(binary, tests, options)
run_tests(binary, tests, run_options)


def find_tests_to_run(directory, files, tests, test_range, sample):
Expand Down
6 changes: 3 additions & 3 deletions kks/util/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import click

from kks.binary import compile_cpp
from kks.binary import BuildOptions, compile_cpp
from kks.util.common import format_file


Expand Down Expand Up @@ -41,9 +41,9 @@ def needs_compilation(script):
return script is not None and script.suffix in CPP_EXTENSIONS


def compile_script(workdir, script, options):
def compile_script(workdir, script):
vvd170501 marked this conversation as resolved.
Show resolved Hide resolved
if script.suffix in CPP_EXTENSIONS:
return compile_cpp(workdir, [script], options)
return compile_cpp(workdir, [script], BuildOptions())
else:
raise Exception(f'Cant compile script with extension {script.suffix}')

Expand Down
2 changes: 1 addition & 1 deletion kks/util/config.py → kks/util/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def get_target(config, target_name):

package_target = get_target(package_cfg, name)
if package_target is None:
# not found
click.secho(f'No target {target_name} found', fg='red', err=True)
return None

package_target.replace_macros_add_missing(problem, package_default)
Expand Down
33 changes: 12 additions & 21 deletions kks/util/testing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import subprocess
import tempfile
from pathlib import Path
from sys import exit

import click

Expand All @@ -23,8 +24,7 @@ def __init__(self, generator, solution, options):
self.solution_directory = tempfile.TemporaryDirectory(prefix='kks-')

def generate_input(self, test, stdout=subprocess.PIPE):
return run_script(self.generator, [test], stdout=stdout,
ignore_exit_code=self.options.ignore_exit_code)
vvd170501 marked this conversation as resolved.
Show resolved Hide resolved
return run_script(self.generator, [test], stdout=stdout)

def generate_output(self, test, stdin=None, stdout=subprocess.PIPE, input=None):
return run_script(self.solution, [test], stdin=stdin, stdout=stdout, input=input,
Expand All @@ -36,7 +36,7 @@ def __enter__(self):
path = Path(self.generator_directory.name)

click.secho('Compiling generator... ', fg='green', err=True)
self.generator = compile_script(path, self.generator, self.options)
vvd170501 marked this conversation as resolved.
Show resolved Hide resolved
self.generator = compile_script(path, self.generator)
if self.generator is None:
click.secho('Compilation failed!', fg='red', err=True)
raise click.Abort()
Expand All @@ -47,7 +47,7 @@ def __enter__(self):
path = Path(self.solution_directory.name)

click.secho('Compiling solution... ', fg='green', err=True)
self.solution = compile_script(path, self.solution, self.options)
self.solution = compile_script(path, self.solution)
if self.solution is None:
click.secho('Compilation failed!', fg='red', err=True)
raise click.Abort()
Expand All @@ -70,9 +70,14 @@ def __init__(self, generator, tests):
def __iter__(self):
for test in self.tests:
name = test_number_to_name(test)
input_data = self.test_source.generate_input(name).stdout
output_data = self.test_source.generate_output(name, input=input_data).stdout
yield Test.from_data(name, input_data, output_data)
input_process = self.test_source.generate_input(name)
if input_process is None:
exit(1)
input_data = input_process.stdout
output_process = self.test_source.generate_output(name, input=input_data)
if output_process is None:
exit(1)
yield Test.from_data(name, input_data, output_process.stdout)

def __len__(self):
return len(self.tests)
Expand Down Expand Up @@ -129,17 +134,3 @@ def read_output(self):
return self.output_data
else:
return None


class RunOptions:
def __init__(self,
continue_on_error=False,
ignore_exit_code=False,
asan=True,
valgrind=False,
is_sample=False):
self.continue_on_error = continue_on_error
self.ignore_exit_code = ignore_exit_code
self.asan = asan
self.valgrind = valgrind
self.is_sample = is_sample