Skip to content

Commit

Permalink
Rust scheduler: Implement setup step upon startup
Browse files Browse the repository at this point in the history
CMK-14522
  • Loading branch information
jherbel committed Sep 21, 2023
1 parent 156c16c commit 6a99fc7
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 6 deletions.
83 changes: 80 additions & 3 deletions v2/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions v2/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"

[dependencies]
anyhow = { version = "*", features = ["backtrace"] }
atomicwrites = "*"
chrono = "0.4.31"
clap = { version = "*", features = ["derive"] }
flexi_logger = "*"
Expand Down
5 changes: 5 additions & 0 deletions v2/rust/src/environment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use std::path::{Path, PathBuf};

pub fn environment_building_stdio_directory(working_directory: &Path) -> PathBuf {
working_directory.join("environment_building_stdio")
}
14 changes: 11 additions & 3 deletions v2/rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,31 @@
pub mod attempt;
mod cli;
mod config;
mod environment;
mod logging;
pub mod parse_xml;
mod results;
mod setup;

use anyhow::Context;
use anyhow::{Context, Result};
use clap::Parser;
use log::{debug, info};
use logging::log_and_return_error;

fn main() -> anyhow::Result<()> {
fn main() -> Result<()> {
let args = cli::Args::parse();
logging::init(args.log_specification(), &args.log_path)?;
info!("Program started and logging set up");

let _config = config::load(&args.config_path)
let conf = config::load(&args.config_path)
.context("Configuration loading failed")
.map_err(log_and_return_error)?;
debug!("Configuration loaded");

setup::setup(&conf)
.context("Setup failed")
.map_err(log_and_return_error)?;
debug!("Setup completed");

Ok(())
}
9 changes: 9 additions & 0 deletions v2/rust/src/results.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use std::path::{Path, PathBuf};

pub fn suite_results_directory(results_directory: &Path) -> PathBuf {
results_directory.join("suites")
}

pub fn suite_result_file(suite_results_dir: &Path, suite_name: &str) -> PathBuf {
suite_results_dir.join(format!("{}.json", suite_name))
}
112 changes: 112 additions & 0 deletions v2/rust/src/setup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use anyhow::{Context, Result};
use std::collections::HashSet;
use std::fs::create_dir_all;
use std::path::{Path, PathBuf};

use super::config::Config;
use super::environment::environment_building_stdio_directory;
use super::results::{suite_result_file, suite_results_directory};

pub fn setup(config: &Config) -> Result<()> {
create_dir_all(&config.working_directory).context("Failed to create working directory")?;
create_dir_all(environment_building_stdio_directory(
&config.working_directory,
))
.context("Failed to create environment building stdio directory")?;
create_dir_all(&config.results_directory).context("Failed to create results directory")?;
create_dir_all(suite_results_directory(&config.results_directory))
.context("Failed to create suite results directory")?;
clean_up_results_directory_atomic(config)
}

fn clean_up_results_directory_atomic(config: &Config) -> Result<()> {
let suite_results_directory = suite_results_directory(&config.results_directory);
let result_files_to_keep: HashSet<PathBuf> = HashSet::from_iter(result_files_to_keep(
&suite_results_directory,
config
.suites()
.into_iter()
.map(|(suite_name, _suite_config)| suite_name.as_str()),
));
let currently_present_result_files =
HashSet::from_iter(currently_present_result_files(&suite_results_directory)?);
let result_files_to_remove = currently_present_result_files.difference(&result_files_to_keep);
remove_files_atomic(
&suite_results_directory.join("deprecated_result"),
result_files_to_remove.into_iter(),
)
}

fn result_files_to_keep<'a>(
suite_results_directory: &std::path::Path,
suite_names: impl Iterator<Item = &'a str>,
) -> Vec<std::path::PathBuf> {
let mut wanted_files_in_results_dir = vec![];

for suite_name in suite_names {
wanted_files_in_results_dir.push(suite_result_file(suite_results_directory, suite_name));
}

wanted_files_in_results_dir
}

fn currently_present_result_files(
suite_results_directory: &std::path::Path,
) -> Result<Vec<PathBuf>> {
let mut result_files = vec![];

for dir_entry in std::fs::read_dir(suite_results_directory).context(format!(
"Failed to read entries of results directory {}",
suite_results_directory.display()
))? {
let dir_entry = dir_entry.context(format!(
"Failed to read entries of results directory {}",
suite_results_directory.display()
))?;
if dir_entry
.file_type()
.context(format!(
"Failed to determine file type of {}",
dir_entry.path().display()
))?
.is_file()
{
result_files.push(dir_entry.path())
}
}

Ok(result_files)
}

fn remove_files_atomic<'a>(
intermediate_path_for_move: &Path,
files_to_be_removed: impl Iterator<Item = &'a PathBuf>,
) -> Result<()> {
for path in files_to_be_removed {
atomicwrites::replace_atomic(path, intermediate_path_for_move).context(format!(
"Failed to move {} to {}",
path.display(),
intermediate_path_for_move.display()
))?;
}

let _ = std::fs::remove_file(intermediate_path_for_move);

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_result_files_to_keep() {
assert_eq!(
result_files_to_keep(&PathBuf::from("/a/b/c"), ["suite1", "suite2"].into_iter()),
vec![
PathBuf::from("/a/b/c/suite1.json"),
PathBuf::from("/a/b/c/suite2.json")
]
)
}
}

0 comments on commit 6a99fc7

Please sign in to comment.