Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
113 changes: 27 additions & 86 deletions crates/cli/src/problem/solve.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::ffi::OsStr;
use std::fs::{self, File};
use std::fs::File;
use std::io::Write;
use std::path::Path;

use anyhow::{bail, Context, Result};
use normpath::PathExt;
use subprocess::Exec;
use anyhow::{Context, Result};

use super::sync_mappings::get_problem;
use crate::problem::run::{RunCommand, RunnableCategory, RunnableFile};
use crate::util::get_project_root;
use crate::{config::Settings, util::get_input_files_in_directory};

Expand All @@ -19,109 +18,51 @@ pub fn solve(
solution_lang: Option<&String>,
) -> Result<()> {
let project_root = get_project_root()?;
let problem = project_root.join(get_problem(problems_dir, problem_name)?);
let problem_path = project_root.join(get_problem(problems_dir, problem_name)?);

let solution_lang = solution_lang.unwrap_or(&settings.problem.default_lang);
let mut solution_file = problem.join(format!("solutions/solution.{solution_lang}"));
if solution_file_name.is_some() {
solution_file = problem.join(format!(
"solutions/{}",
solution_file_name.context("Failed to get solution file name")?
));
}
solution_file = solution_file.normalize()?.into();
let mut solution_file = format!("solution.{solution_lang}");

if !fs::exists(&solution_file).expect("Failed to check if path exists") {
bail!("Solution file does not exist: {:?}", solution_file);
// Use custom solution file or script file if it exists
if solution_file_name.is_some() {
solution_file = solution_file_name
.context("Failed to get solution file name")?
.to_string();
}

eprintln!("Using solution file at: {}", solution_file.display());

let bin_file = problem.join("solutions/solution.out");
let script_file = problem.join(format!("solutions/solution.{solution_lang}"));

let lang_settings = settings
.problem
.solution
.get(solution_lang)
.context(format!(
"Could not get settings for language `{solution_lang}`"
))?;

let compile_command = lang_settings.compile_command.clone();
let runnable_file =
RunnableFile::new(settings, RunnableCategory::Solution, Some(&solution_file))?;

// Check if the solution file is a script (if it needs compilation or not)
let needs_compilation = compile_command.is_some();
let compile_command = compile_command.unwrap_or_default();
if needs_compilation && compile_command.is_empty() {
bail!("compile_command specified in the settings, but array is empty");
}

if needs_compilation {
let mut cmd_iter = compile_command.iter();
let mut final_cmd = Exec::cmd(cmd_iter.next().context("Failed to get command")?);
for c in cmd_iter {
// Replace strings where necessary
final_cmd = match c.as_str() {
"@in_file" => final_cmd.arg(&solution_file),
"@bin_file" => final_cmd.arg(&bin_file),
_ => final_cmd.arg(c),
}
}
eprint!("Compiling the solution file... ");
// Run the compile command
final_cmd.join()?;
eprintln!("Done");
}
let run_command = RunCommand::new(
settings,
&problem_path,
&runnable_file,
problem_path.join("solutions/solution.out"),
problem_path.join(&solution_file),
)?;

let run_command = lang_settings.run_command.clone().unwrap_or_default();
if run_command.is_empty() {
bail!("No run command specified in the settings. It must be specified!");
}
let cmd_iter = run_command.iter();
let test_files = get_input_files_in_directory(problem.join("tests"))?;
let test_files = get_input_files_in_directory(problem_path.join("tests"))?;

eprintln!("Running the solution file for each test case...");
// Run the file for every test input and generate the corresponding output
for test_file in test_files {
let input_file_path = problem.join(format!("tests/{test_file}"));
let output_file_path = problem.join(format!(
let input_file_path = problem_path.join(format!("tests/{test_file}"));
let output_file_path = problem_path.join(format!(
"tests/{}.out",
test_file
.strip_suffix(".in")
.context("Failed to strip suffix of test file")?
));

let mut cmd_iter_clone = cmd_iter.clone();
let cmd = cmd_iter_clone.next().context("Failed to get command")?;
let mut final_cmd = Exec::cmd(match cmd.as_str() {
"@bin_file" => bin_file.as_os_str(),
"@script_file" => script_file.as_os_str(),
_ => OsStr::new(cmd),
});
let result = run_command.get_result(Some(&input_file_path))?;
let mut output_file = File::create(output_file_path)?;
output_file.write_all(result.output.as_bytes())?;

for c in cmd_iter_clone {
// Replace strings where necessary
final_cmd = match c.as_str() {
"@bin_file" => final_cmd.arg(&bin_file),
"@script_file" => final_cmd.arg(&script_file),
_ => final_cmd.arg(c),
}
}

let input_file = File::open(input_file_path)?;
let output_file = File::create(output_file_path)?;

final_cmd = final_cmd.stdin(input_file).stdout(output_file);
final_cmd.capture()?;
eprintln!(" - generated output for test file: {test_file}");
}
eprintln!("Finished generating outputs for all test cases");

// Delete the compiled run file, if it exists
if bin_file.exists() {
fs::remove_file(bin_file)?;
}
run_command.cleanup()?;

Ok(())
}
115 changes: 27 additions & 88 deletions crates/cli/src/problem/test.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use std::ffi::OsStr;
use std::fs::{self, File};
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::time::{Duration, Instant};
use std::time::Duration;

use anyhow::{bail, Context, Result};
use normpath::PathExt;
use subprocess::{Exec, Redirection};
use anyhow::{Context, Result};

use crate::config::Settings;
use crate::problem::run::{RunCommand, RunnableCategory, RunnableFile};
use crate::util::{get_input_files_in_directory, get_project_root};

use super::sync_mappings::get_problem;
Expand All @@ -22,67 +20,30 @@ pub fn test(
solution_lang: Option<&String>,
) -> Result<()> {
let project_root = get_project_root()?;
let problem = project_root.join(get_problem(problems_dir, problem_name)?);
let problem_path = project_root.join(get_problem(problems_dir, problem_name)?);

let solution_lang = solution_lang.unwrap_or(&settings.problem.default_lang);
let mut solution_file = problem.join(format!("solutions/solution.{solution_lang}"));
if solution_file_name.is_some() {
solution_file = problem.join(format!(
"solutions/{}",
solution_file_name.context("Failed to get solution file name")?
));
}
solution_file = solution_file.normalize()?.into();
let mut solution_file = format!("solution.{solution_lang}");

if !fs::exists(&solution_file).expect("Failed to check if path exists") {
bail!("Solution file does not exist: {:?}", solution_file);
// Use custom solution file or script file if it exists
if solution_file_name.is_some() {
solution_file = solution_file_name
.context("Failed to get solution file name")?
.to_string();
}

eprintln!("Using solution file at: {}", solution_file.display());
let runnable_file =
RunnableFile::new(settings, RunnableCategory::Solution, Some(&solution_file))?;

let bin_file = problem.join("solutions/solution.out");
let script_file = problem.join(format!("solutions/solution.{solution_lang}"));
let run_command = RunCommand::new(
settings,
&problem_path,
&runnable_file,
problem_path.join("solutions/solution.out"),
problem_path.join(&solution_file),
)?;

let lang_settings = settings
.problem
.solution
.get(solution_lang)
.context(format!(
"Could not get settings for language `{solution_lang}`"
))?;

let compile_command = lang_settings.compile_command.clone();

// Check if the solution file is a script (if it needs compilation or not)
let needs_compilation = compile_command.is_some();
let compile_command = compile_command.unwrap_or_default();
if needs_compilation && compile_command.is_empty() {
bail!("compile_command specified in the settings, but array is empty");
}

if needs_compilation {
let mut cmd_iter = compile_command.iter();
let mut final_cmd = Exec::cmd(cmd_iter.next().context("Failed to get command")?);
for c in cmd_iter {
// Replace strings where necessary
final_cmd = match c.as_str() {
"@in_file" => final_cmd.arg(&solution_file),
"@bin_file" => final_cmd.arg(&bin_file),
_ => final_cmd.arg(c),
}
}
eprint!("Compiling the solution file... ");
// Run the compile command
final_cmd.join()?;
eprintln!("Done");
}

let run_command = lang_settings.run_command.clone().unwrap_or_default();
if run_command.is_empty() {
bail!("No run command specified in the settings. It must be specified!");
}
let cmd_iter = run_command.iter();
let test_files = get_input_files_in_directory(problem.join("tests"))?;
let test_files = get_input_files_in_directory(problem_path.join("tests"))?;

eprintln!("Running the solution file for each test case...");

Expand All @@ -91,38 +52,19 @@ pub fn test(
let mut total_time: Duration = Duration::new(0, 0);

for test_file in test_files {
let input_file_path = problem.join(format!("tests/{test_file}"));
let output_file_path = problem.join(format!(
let input_file_path = problem_path.join(format!("tests/{test_file}"));
let output_file_path = problem_path.join(format!(
"tests/{}.out",
test_file
.strip_suffix(".in")
.context("Failed to strip suffix of test file")?
));

let mut cmd_iter_clone = cmd_iter.clone();
let cmd = cmd_iter_clone.next().context("Failed to get command")?;
let mut final_cmd = Exec::cmd(match cmd.as_str() {
"@bin_file" => bin_file.as_os_str(),
"@script_file" => script_file.as_os_str(),
_ => OsStr::new(cmd),
});

for c in cmd_iter_clone {
// Replace strings where necessary
final_cmd = match c.as_str() {
"@bin_file" => final_cmd.arg(&bin_file),
"@script_file" => final_cmd.arg(&script_file),
_ => final_cmd.arg(c),
}
}
let result = run_command.get_result(Some(&input_file_path))?;

let input_file = File::open(input_file_path)?;
let mut output_file = File::open(output_file_path)?;

let start_time = Instant::now();
final_cmd = final_cmd.stdin(input_file).stdout(Redirection::Pipe);
let out_str = final_cmd.capture()?.stdout_str();
let elapsed_time = start_time.elapsed();
let out_str = result.output;
let elapsed_time = result.elapsed_time;

// Compare the output with the expected output
let expected: &mut Vec<u8> = &mut Vec::new();
Expand Down Expand Up @@ -150,10 +92,7 @@ pub fn test(
total_time.as_secs_f64()
);

// Delete the compiled run file, if it exists
if bin_file.exists() {
fs::remove_file(bin_file)?;
}
run_command.cleanup()?;

Ok(())
}