Skip to content

Commit 43ef4ed

Browse files
author
Martin Kruliš
authored
Custom compilation box (#250)
* Adding custom compilation box. * Redesigned way of assembling custom compilation args (using special conversion boxes). * Fixing bugs in class hierarchy design and static variables initialization. * Adding custom box for Bison compilation. * Fixing some bugs. * Fixing an issue with exercise config checker. * Fixing bug in Bison Box. * Cleanup.
1 parent b57a705 commit 43ef4ed

File tree

11 files changed

+521
-118
lines changed

11 files changed

+521
-118
lines changed

app/helpers/ExerciseConfig/ExerciseConfigChecker.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ public function __construct(ExerciseConfig\Compiler $compiler, ExerciseConfig\V
5050
* @throws ApiException
5151
*/
5252
private function conjureSubmittedFiles(RuntimeEnvironment $environment): array {
53-
$extension = current($environment->getExtensionsList());
54-
$random = Random::generate(20);
55-
return ["recodex.{$random}.{$extension}"];
53+
return array_map(function($extension) {
54+
$random = Random::generate(20);
55+
return "recodex.{$random}.{$extension}";
56+
}, $environment->getExtensionsList());
5657
}
5758

5859
/**
@@ -75,7 +76,7 @@ private function conjureSubmitVariables(Exercise $exercise,
7576
if (strpos($variable["type"], "string") === 0) {
7677
$result->addVariable(new SubmitVariable(["name" => $variable["name"], "value" => Random::generate()]));
7778
} else if (strpos($variable["type"], "file") === 0) {
78-
$result->addVariable(new SubmitVariable(["name" => $variable["name"], "value" => current($submitFiles)]));
79+
$result->addVariable(new SubmitVariable(["name" => $variable["name"], "value" => reset($submitFiles)]));
7980
} else {
8081
// Uh-oh
8182
throw new ExerciseConfigException("I should not generate this error. I really should not. Uh-oh... here we go");

app/helpers/ExerciseConfig/Pipeline/Box/BoxService.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public function __construct() {
3434
JudgeBox::$JUDGE_TYPE => JudgeBox::class,
3535
GccCompilationBox::$GCC_TYPE => GccCompilationBox::class,
3636
GppCompilationBox::$GPP_TYPE => GppCompilationBox::class,
37+
BisonCompilationBox::$BOX_TYPE => BisonCompilationBox::class,
3738
ElfExecutionBox::$ELF_EXEC_TYPE => ElfExecutionBox::class,
3839
FpcCompilationBox::$FPC_TYPE => FpcCompilationBox::class,
3940
MonoCompilationBox::$MCS_TYPE => MonoCompilationBox::class,
@@ -46,9 +47,12 @@ public function __construct() {
4647
Python3CompilationBox::$PYTHON3_COMPILATION_TYPE => Python3CompilationBox::class,
4748
PhpRunBox::$PHP_RUN_TYPE => PhpRunBox::class,
4849
NodeRunBox::$NODE_RUN_TYPE => NodeRunBox::class,
49-
MergeFilesBox::$MERGE_FILES_TYPE => MergeFilesBox::class,
50-
MergeTwoFilesBox::$MERGE_TWO_FILES_TYPE => MergeTwoFilesBox::class,
51-
MergeFileAndFilesBox::$MERGE_FILE_AND_FILES_TYPE => MergeFileAndFilesBox::class,
50+
MergeFilesBox::$BOX_TYPE => MergeFilesBox::class,
51+
MergeStringsBox::$BOX_TYPE => MergeStringsBox::class,
52+
FileToArrayBox::$BOX_TYPE => FileToArrayBox::class,
53+
StringToArrayBox::$BOX_TYPE => StringToArrayBox::class,
54+
FilesNamesBox::$BOX_TYPE => FilesNamesBox::class,
55+
CustomCompilationBox::$CUSTOM_COMPILATION_TYPE => CustomCompilationBox::class,
5256
];
5357
}
5458

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
namespace App\Helpers\ExerciseConfig\Pipeline\Box;
4+
5+
use App\Helpers\ExerciseConfig\Compilation\CompilationParams;
6+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\ConfigParams;
7+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\LinuxSandbox;
8+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\Priorities;
9+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\TaskType;
10+
use App\Helpers\ExerciseConfig\Pipeline\Ports\Port;
11+
use App\Helpers\ExerciseConfig\Pipeline\Ports\PortMeta;
12+
use App\Helpers\ExerciseConfig\VariableTypes;
13+
use App\Helpers\JobConfig\SandboxConfig;
14+
use App\Helpers\JobConfig\Tasks\Task;
15+
16+
17+
/**
18+
* Box that compile Bison format into C/C++ sources.
19+
*/
20+
class BisonCompilationBox extends CompilationBox
21+
{
22+
/** Type key */
23+
public static $BOX_TYPE = "bison";
24+
public static $BISON_BINARY = "/usr/bin/bison";
25+
public static $BISON_EXT = ".y";
26+
public static $DEFAULT_NAME = "Bison Compilation";
27+
public static $OUTPUT_FILES_PORT_KEY = "output";
28+
29+
private static $initialized = false;
30+
private static $defaultOutputPorts;
31+
private static $defaultInputPorts;
32+
33+
/**
34+
* Static initializer.
35+
*/
36+
public static function init() {
37+
if (!self::$initialized) {
38+
self::$initialized = true;
39+
self::$defaultInputPorts = [
40+
new Port((new PortMeta())->setName(self::$ARGS_PORT_KEY)->setType(VariableTypes::$STRING_ARRAY_TYPE)),
41+
new Port((new PortMeta())->setName(self::$SOURCE_FILE_PORT_KEY)->setType(VariableTypes::$FILE_ARRAY_TYPE)),
42+
];
43+
self::$defaultOutputPorts = [
44+
new Port((new PortMeta())->setName(self::$OUTPUT_FILES_PORT_KEY)->setType(VariableTypes::$FILE_ARRAY_TYPE))
45+
];
46+
}
47+
}
48+
49+
/**
50+
* @param BoxMeta $meta
51+
*/
52+
public function __construct(BoxMeta $meta) {
53+
parent::__construct($meta);
54+
}
55+
56+
57+
/**
58+
* Get type of this box.
59+
* @return string
60+
*/
61+
public function getType(): string {
62+
return self::$BOX_TYPE;
63+
}
64+
65+
/**
66+
* Get default input ports for this box.
67+
* @return array
68+
*/
69+
public function getDefaultInputPorts(): array {
70+
self::init();
71+
return self::$defaultInputPorts;
72+
}
73+
74+
/**
75+
* Get default output ports for this box.
76+
* @return array
77+
*/
78+
public function getDefaultOutputPorts(): array {
79+
self::init();
80+
return self::$defaultOutputPorts;
81+
}
82+
83+
/**
84+
* Get default name of this box.
85+
* @return string
86+
*/
87+
public function getDefaultName(): string {
88+
return self::$DEFAULT_NAME;
89+
}
90+
91+
92+
/**
93+
* Compile box into set of low-level tasks.
94+
* @param CompilationParams $params
95+
* @return array
96+
*/
97+
public function compile(CompilationParams $params): array {
98+
$task = $this->compileBaseTask($params);
99+
$task->setCommandBinary(self::$BISON_BINARY);
100+
101+
$inputFile = $this->getInputPortValue(self::$SOURCE_FILE_PORT_KEY)->getValue(ConfigParams::$EVAL_DIR);
102+
$inputBaseName = basename($inputFile, self::$BISON_EXT);
103+
104+
// Prepare cmdline args
105+
$args = [];
106+
if ($this->hasInputPortValue(self::$ARGS_PORT_KEY)) {
107+
$args = $this->getInputPortValue(self::$ARGS_PORT_KEY)->getValue();
108+
}
109+
$args[] = "-o${inputBaseName}.cpp";
110+
$args[] = $inputFile;
111+
$task->setCommandArguments($args);
112+
113+
// Set output names correctly and create task that will check their existence
114+
$output = $this->getOutputPortValue(self::$OUTPUT_FILES_PORT_KEY);
115+
$output->setValue([ "${inputBaseName}.cpp", "${inputBaseName}.hpp", "stack.hh" ]);
116+
$exists = $this->compileExistsTask($output->getTestPrefixedValue(ConfigParams::$SOURCE_DIR));
117+
118+
return [$task, $exists];
119+
}
120+
121+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
namespace App\Helpers\ExerciseConfig\Pipeline\Box;
4+
5+
use App\Helpers\ExerciseConfig\Compilation\CompilationParams;
6+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\ConfigParams;
7+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\LinuxSandbox;
8+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\Priorities;
9+
use App\Helpers\ExerciseConfig\Pipeline\Box\Params\TaskType;
10+
use App\Helpers\ExerciseConfig\Pipeline\Ports\Port;
11+
use App\Helpers\ExerciseConfig\Pipeline\Ports\PortMeta;
12+
use App\Helpers\ExerciseConfig\VariableTypes;
13+
use App\Helpers\JobConfig\SandboxConfig;
14+
use App\Helpers\JobConfig\Tasks\Task;
15+
16+
17+
/**
18+
* Box which represents custom compilation unit.
19+
* It can be used for any compilation preprocessing or postprocessing,
20+
* like custom macro processing, bison&flex compilation, or additional executable bundling.
21+
*/
22+
class CustomCompilationBox extends CompilationBox
23+
{
24+
/** Type key */
25+
public static $CUSTOM_COMPILATION_TYPE = "custom-compilation";
26+
public static $DEFAULT_NAME = "Custom Compilation";
27+
public static $COMPILER_EXEC_PORT_KEY = "compiler-exec";
28+
29+
private static $initialized = false;
30+
private static $defaultInputPorts;
31+
private static $defaultOutputPorts;
32+
33+
/**
34+
* Static initializer.
35+
*/
36+
public static function init() {
37+
if (!self::$initialized) {
38+
self::$initialized = true;
39+
self::$defaultInputPorts = array(
40+
new Port((new PortMeta())->setName(self::$COMPILER_EXEC_PORT_KEY)->setType(VariableTypes::$STRING_TYPE)),
41+
new Port((new PortMeta())->setName(self::$ARGS_PORT_KEY)->setType(VariableTypes::$STRING_ARRAY_TYPE)),
42+
new Port((new PortMeta())->setName(self::$SOURCE_FILES_PORT_KEY)->setType(VariableTypes::$FILE_ARRAY_TYPE)),
43+
new Port((new PortMeta())->setName(self::$EXTRA_FILES_PORT_KEY)->setType(VariableTypes::$FILE_ARRAY_TYPE))
44+
);
45+
self::$defaultOutputPorts = array(
46+
new Port((new PortMeta())->setName(self::$BINARY_FILE_PORT_KEY)->setType(VariableTypes::$FILE_TYPE))
47+
);
48+
}
49+
}
50+
51+
/**
52+
* JudgeNormalBox constructor.
53+
* @param BoxMeta $meta
54+
*/
55+
public function __construct(BoxMeta $meta) {
56+
parent::__construct($meta);
57+
}
58+
59+
60+
/**
61+
* Get type of this box.
62+
* @return string
63+
*/
64+
public function getType(): string {
65+
return self::$CUSTOM_COMPILATION_TYPE;
66+
}
67+
68+
/**
69+
* Get default input ports for this box.
70+
* @return array
71+
*/
72+
public function getDefaultInputPorts(): array {
73+
self::init();
74+
return self::$defaultInputPorts;
75+
}
76+
77+
/**
78+
* Get default output ports for this box.
79+
* @return array
80+
*/
81+
public function getDefaultOutputPorts(): array {
82+
self::init();
83+
return self::$defaultOutputPorts;
84+
}
85+
86+
/**
87+
* Get default name of this box.
88+
* @return string
89+
*/
90+
public function getDefaultName(): string {
91+
return self::$DEFAULT_NAME;
92+
}
93+
94+
95+
/**
96+
* Compile box into set of low-level tasks.
97+
* @param CompilationParams $params
98+
* @return array
99+
*/
100+
public function compile(CompilationParams $params): array {
101+
$task = $this->compileBaseTask($params);
102+
$task->setCommandBinary($this->getInputPortValue(self::$COMPILER_EXEC_PORT_KEY)->getValue());
103+
104+
// Process args
105+
$args = [];
106+
if ($this->hasInputPortValue(self::$ARGS_PORT_KEY)) {
107+
$args = $this->getInputPortValue(self::$ARGS_PORT_KEY)->getValue();
108+
}
109+
$task->setCommandArguments($args);
110+
111+
// check if file produced by compilation was successfully created
112+
$binary = $this->getOutputPortValue(self::$BINARY_FILE_PORT_KEY)->getTestPrefixedValue(ConfigParams::$SOURCE_DIR);
113+
$exists = $this->compileExistsTask([$binary]);
114+
115+
return [$task, $exists];
116+
}
117+
118+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace App\Helpers\ExerciseConfig\Pipeline\Box;
4+
5+
use App\Exceptions\ExerciseConfigException;
6+
use App\Helpers\ExerciseConfig\Compilation\CompilationParams;
7+
use App\Helpers\ExerciseConfig\Pipeline\Ports\Port;
8+
use App\Helpers\ExerciseConfig\Pipeline\Ports\PortMeta;
9+
use App\Helpers\ExerciseConfig\VariableTypes;
10+
11+
12+
/**
13+
* Box which converts a file into a single-item array of files.
14+
*/
15+
class FileToArrayBox extends ScalarToArrayBox
16+
{
17+
public static $BOX_TYPE = "file-to-array";
18+
public static $DEFAULT_NAME = "File to array";
19+
20+
/**
21+
* Static initializer.
22+
* @throws ExerciseConfigException
23+
*/
24+
public static function init() {
25+
static::initScalarToArray(VariableTypes::$FILE_TYPE, VariableTypes::$FILE_ARRAY_TYPE);
26+
}
27+
28+
/**
29+
* Get type of this box.
30+
* @return string
31+
*/
32+
public function getType(): string {
33+
return self::$BOX_TYPE;
34+
}
35+
36+
/**
37+
* Get default name of this box.
38+
* @return string
39+
*/
40+
public function getDefaultName(): string {
41+
return self::$DEFAULT_NAME;
42+
}
43+
44+
}

0 commit comments

Comments
 (0)