Skip to content

Commit b5faaf7

Browse files
committed
feat: compile c/cpp
1 parent 1c5050d commit b5faaf7

File tree

9 files changed

+158
-49
lines changed

9 files changed

+158
-49
lines changed

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ lazy_static = "1.4.0"
2121
libc-stdhandle = "0.1.0"
2222
log = "0.4"
2323
nix = { version = "0.26.2", features = ["signal", "process", "ptrace", "user"] }
24+
path-absolutize = "3.0.14"
2425
remove_dir_all = "0.7.0"
2526
tempfile = "3"

src/context/builder.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ impl CatBoxBuilder {
5656

5757
/// Create a compile CatBox
5858
pub fn compile() -> Self {
59-
Self::new(Box::new(CatBoxCompileContext {}))
59+
Self::new(Box::new(CatBoxCompileContext::new()))
6060
}
6161

6262
/// Create a judge CatBox
@@ -335,6 +335,12 @@ impl CatBoxOptionBuilder {
335335
self
336336
}
337337

338+
// Add mount point
339+
pub fn mount(mut self, mount_point: MountPoint) -> Self {
340+
self.option.mounts.push(mount_point);
341+
self
342+
}
343+
338344
/// Mount read directory
339345
pub fn mount_read<SP: Into<PathBuf>, DP: Into<PathBuf>>(mut self, src: SP, dst: DP) -> Self {
340346
self
@@ -383,7 +389,7 @@ impl CatBoxOption {
383389
let current_user = User::from_uid(Uid::current()).unwrap().unwrap();
384390
let cgroup = env::var("CATJ_CGROUP").unwrap_or(current_user.name);
385391

386-
let catbox_user = User::from_name("Nobody").unwrap().unwrap();
392+
let catbox_user = User::from_name("nobody").unwrap().unwrap();
387393
let catbox_group = Group::from_name("nogroup").unwrap().unwrap();
388394

389395
CatBoxOption {

src/context/mod.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ pub struct CatBoxRunContext {
5050
results: Vec<CatBoxResult>,
5151
}
5252

53-
pub struct CatBoxCompileContext {}
53+
pub struct CatBoxCompileContext {
54+
ok: bool,
55+
}
5456

5557
pub struct CatBoxJudgeContext {}
5658

@@ -98,6 +100,7 @@ impl CatBox {
98100
/// Run all the commands
99101
pub fn start(&mut self) -> Result<(), CatBoxError> {
100102
for option in self.options.iter() {
103+
dbg!(&option);
101104
let result = crate::run(&option)?;
102105
self.context.add_result(&option.label.clone(), result);
103106
}
@@ -244,9 +247,19 @@ impl CatBoxContext for CatBoxRunContext {
244247
}
245248
}
246249

250+
impl CatBoxCompileContext {
251+
fn new() -> Self {
252+
CatBoxCompileContext { ok: true }
253+
}
254+
}
255+
247256
impl CatBoxContext for CatBoxCompileContext {
248257
fn add_result(&mut self, _label: &String, result: CatBoxResult) {
249-
todo!()
258+
if self.ok {
259+
if result.status.unwrap_or(1) == 0 {
260+
self.ok = false;
261+
}
262+
}
250263
}
251264

252265
fn report_human(&self) {

src/main.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use log::{error, info};
1010
use crate::catbox::run;
1111
use crate::context::{CatBox, CatBoxBuilder, CatBoxOption};
1212
use crate::error::{CatBoxError, CatBoxExit};
13+
use crate::preset::make_compile_params;
1314
// use crate::preset::make_compile_params;
1415
use crate::utils::{default_format, GidType, MemoryLimitType, TimeLimitType, UidType};
1516

@@ -59,7 +60,7 @@ struct Cli {
5960
}
6061

6162
#[derive(Subcommand, Debug)]
62-
enum Commands {
63+
pub(crate) enum Commands {
6364
#[command(about = "Run user program")]
6465
Run {
6566
#[arg(help = "Program to be executed")]
@@ -172,14 +173,9 @@ impl Cli {
172173
.parse_mount_read(read)?
173174
.parse_mount_write(write)?
174175
.done(),
175-
Commands::Compile {
176-
language,
177-
submission,
178-
output,
179-
..
180-
} => {
176+
Commands::Compile { .. } => {
181177
// make_compile_params(language, submission, output)?
182-
unimplemented!()
178+
make_compile_params(builder, self.command)?
183179
}
184180
Commands::Validate { .. } => {
185181
unimplemented!()

src/preset/default/c.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ lazy_static! {
1919
"-Wno-unused-result",
2020
"-static",
2121
"-lm",
22-
"--std=c++20",
22+
"-std=c17",
2323
"-O2",
2424
"-DONLINE_JUDGE",
2525
"-Wall"

src/preset/default/cpp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ lazy_static! {
1919
"-Wno-unused-result",
2020
"-static",
2121
"-lm",
22-
"--std=c++20",
22+
"-std=c++17",
2323
"-O2",
2424
"-DONLINE_JUDGE",
2525
"-Wall"

src/preset/mod.rs

Lines changed: 75 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
use std::collections::HashMap;
2+
use std::fs::canonicalize;
3+
use std::path::PathBuf;
24

35
use lazy_static::lazy_static;
6+
use log::info;
7+
use path_absolutize::*;
48

5-
use crate::context::CatBoxOption;
9+
use crate::context::{CatBoxBuilder, CatBoxOption};
610
use crate::error::CatBoxError;
11+
use crate::preset::default::{CPP_PRESET, C_PRESET};
12+
use crate::preset::preset::UserType;
13+
use crate::Commands;
714

815
mod default;
916
mod preset;
@@ -42,28 +49,72 @@ fn detect_language(language: &Option<String>, submission: &String) -> Option<Str
4249
}
4350
}
4451

45-
pub fn make_compile_params(
46-
language: Option<String>,
47-
submission: String,
48-
_output: String,
49-
) -> Result<CatBoxOption, CatBoxError> {
50-
let language = detect_language(&language, &submission)
51-
.ok_or(CatBoxError::cli("Can not detect submission language"))?;
52+
pub(crate) fn make_compile_params(
53+
mut builder: CatBoxBuilder,
54+
command: Commands,
55+
) -> Result<CatBoxBuilder, CatBoxError> {
56+
if let Commands::Compile {
57+
language,
58+
submission,
59+
output,
60+
..
61+
} = command
62+
{
63+
let language = detect_language(&language, &submission)
64+
.ok_or(CatBoxError::cli("Can not detect submission language"))?;
5265

53-
unimplemented!()
54-
// match language.as_str() {
55-
// "c" => {
56-
// let args = vec![];
57-
// let params = CatBoxOption::new("g++", args);
58-
// Ok(params)
59-
// }
60-
// "cpp" => {
61-
// let args = vec![];
62-
// let params = CatBoxOption::new("g++", args);
63-
// Ok(params)
64-
// }
65-
// _ => {
66-
// unimplemented!()
67-
// }
68-
// }
66+
let preset = match language.as_str() {
67+
"c" => C_PRESET.clone(),
68+
"cpp" => CPP_PRESET.clone(),
69+
default => return Err(CatBoxError::cli("Can not find language preset")),
70+
};
71+
72+
info!("Compile language {}", &language);
73+
74+
let submission = PathBuf::from(&submission);
75+
let submission = submission.absolutize().unwrap();
76+
let submission_dir = submission.parent().unwrap();
77+
let output = PathBuf::from(&output);
78+
let output = output.absolutize().unwrap();
79+
let output_dir = output.parent().unwrap();
80+
81+
for command in preset.compile.commands.iter() {
82+
let option_builder = builder
83+
.command(
84+
command.apply_program(submission.to_str().unwrap(), output.to_str().unwrap()),
85+
command.apply_arguments(submission.to_str().unwrap(), output.to_str().unwrap()),
86+
)
87+
.time_limit(command.time_limit)
88+
.memory_limit(command.memory_limit)
89+
.set_process(Some(command.process))
90+
.set_chroot(command.chroot)
91+
.mount_read(submission_dir, submission_dir)
92+
.mount_write(output_dir, output_dir)
93+
.disable_ptrace();
94+
95+
let mut option_builder = match command.user {
96+
UserType::Nobody => option_builder,
97+
UserType::Current => option_builder.current_user(),
98+
UserType::Root => {
99+
unimplemented!()
100+
}
101+
};
102+
103+
for feat in command.ptrace.iter() {
104+
option_builder = option_builder.ptrace(feat.clone())
105+
}
106+
for mount_point in command.mounts.iter() {
107+
option_builder = option_builder.mount(mount_point.clone())
108+
}
109+
for (key, value) in command.env.iter() {
110+
option_builder = option_builder.env(key, value);
111+
}
112+
113+
builder = option_builder.done();
114+
}
115+
116+
Ok(builder)
117+
} else {
118+
Err(CatBoxError::cli("unreachable"))
119+
}
69120
}

src/preset/preset.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,42 @@ use crate::syscall::RestrictedSyscall;
33
use crate::utils::mount::MountPoint;
44
use crate::utils::{MemoryLimitType, TimeLimitType};
55

6+
#[derive(Debug, Clone)]
67
pub(crate) struct LanguagePreset {
78
pub(crate) compile: CompileOption,
89
pub(crate) execute: ExecuteOption,
910
}
1011

12+
#[derive(Debug, Clone)]
1113
pub(crate) struct CompileOption {
1214
pub(crate) extension: String,
1315
pub(crate) commands: Vec<ExecuteCommand>,
1416
}
1517

18+
#[derive(Debug, Clone)]
1619
pub(crate) struct ExecuteOption {
1720
pub(crate) commands: Vec<ExecuteCommand>,
1821
}
1922

23+
#[derive(Debug, Clone)]
2024
pub(crate) enum UserType {
2125
Nobody,
2226
Current,
2327
Root,
2428
}
2529

30+
#[derive(Debug, Clone)]
2631
pub struct ExecuteCommand {
27-
program: String,
28-
argument: Vec<String>,
29-
time_limit: TimeLimitType,
30-
memory_limit: MemoryLimitType,
31-
user: UserType,
32-
process: u64,
33-
ptrace: Vec<RestrictedSyscall>,
34-
chroot: bool,
35-
mounts: Vec<MountPoint>,
36-
env: Vec<(String, String)>,
32+
pub(crate) program: String,
33+
pub(crate) arguments: Vec<String>,
34+
pub(crate) time_limit: TimeLimitType,
35+
pub(crate) memory_limit: MemoryLimitType,
36+
pub(crate) user: UserType,
37+
pub(crate) process: u64,
38+
pub(crate) ptrace: Vec<RestrictedSyscall>,
39+
pub(crate) chroot: bool,
40+
pub(crate) mounts: Vec<MountPoint>,
41+
pub(crate) env: Vec<(String, String)>,
3742
}
3843

3944
impl CompileOption {
@@ -65,7 +70,7 @@ impl ExecuteCommand {
6570
pub(crate) fn new<PS: Into<String>, AS: Into<String>>(program: PS, arguments: Vec<AS>) -> Self {
6671
ExecuteCommand {
6772
program: program.into(),
68-
argument: arguments.into_iter().map(|a| a.into()).collect(),
73+
arguments: arguments.into_iter().map(|a| a.into()).collect(),
6974
time_limit: 1000,
7075
memory_limit: 262144,
7176
user: UserType::Nobody,
@@ -77,6 +82,24 @@ impl ExecuteCommand {
7782
}
7883
}
7984

85+
fn apply(text: &str, source: &str, executable: &str) -> String {
86+
text
87+
.replace("${source}", source)
88+
.replace("${executable}", executable)
89+
}
90+
91+
pub(crate) fn apply_program(&self, source: &str, executable: &str) -> String {
92+
Self::apply(self.program.as_str(), source, executable)
93+
}
94+
95+
pub(crate) fn apply_arguments(&self, source: &str, executable: &str) -> Vec<String> {
96+
self
97+
.arguments
98+
.iter()
99+
.map(|a| Self::apply(a, source, executable))
100+
.collect()
101+
}
102+
80103
pub(crate) fn default_time_limit(mut self, value: TimeLimitType) -> Self {
81104
self.time_limit = value;
82105
self

0 commit comments

Comments
 (0)