Skip to content

Fix file locking #212

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

Merged
merged 7 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
334 changes: 171 additions & 163 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ authors = [
edition = "2021"
license = "MIT OR Apache-2.0"
rust-version = "1.70.0"
version = "0.36.3"
version = "0.36.4"

[workspace.dependencies]
mooc-langs-api = { git = "https://github.com/rage/secret-project-331.git", rev = "9fb5f894c72932e77dafa6d0f00df7a8abdfa84c" }
Expand Down
2 changes: 1 addition & 1 deletion crates/bindings/tmc-langs-node/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde::de::{
pub fn from_value<'j, C, T>(cx: &mut C, value: Handle<'j, JsValue>) -> LibResult<T>
where
C: Context<'j>,
T: DeserializeOwned + ?Sized,
T: DeserializeOwned,
{
let mut deserializer: Deserializer<C> = Deserializer::new(cx, value);
let t = T::deserialize(&mut deserializer)?;
Expand Down
4 changes: 2 additions & 2 deletions crates/bindings/tmc-langs-node/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ macro_rules! lock {
( $cx: ident, $( $path: expr ),+ ) => {
$(
let path_buf: PathBuf = (&$path).into();
let mut fl = $crate::file_util::FileLock::new(path_buf).map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
let _lock = fl.lock().map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
let mut lock = $crate::file_util::Lock::dir(path_buf, $crate::file_util::LockOptions::Write).map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
let _guard = lock.lock().map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
)*
};
}
Expand Down
11 changes: 7 additions & 4 deletions crates/bindings/tmc-langs-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,14 @@ fn extract_project(mut cx: FunctionContext) -> JsResult<JsValue> {
compression: Compression
);

let mut archive =
file_util::open_file_locked(archive_path).map_err(|e| convert_err(&mut cx, e))?;
let mut guard = archive.write().expect("failed to lock file");
let mut archive_lock = file_util::Lock::file(archive_path, file_util::LockOptions::Read)
.map_err(|e| convert_err(&mut cx, e))?;
let mut archive_guard = archive_lock.lock().map_err(|e| convert_err(&mut cx, e))?;
let mut data = vec![];
guard.read_to_end(&mut data).expect("failed to read data");
archive_guard
.get_file_mut()
.read_to_end(&mut data)
.expect("failed to read data");

let res =
tmc_langs::extract_project(Cursor::new(data), &output_path, compression, false, false);
Expand Down
276 changes: 222 additions & 54 deletions crates/bindings/tmc-langs-node/ts/generated.d.ts

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions crates/plugins/make/src/check_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::HashMap;
use tmc_langs_framework::{RunResult, RunStatus, TestResult};

#[derive(Debug, Deserialize)]
#[allow(dead_code)]
pub struct CheckLog {
#[allow(dead_code)]
pub datetime: String,
Expand Down Expand Up @@ -52,6 +53,7 @@ impl CheckLog {
}

#[derive(Debug, Deserialize)]
#[allow(dead_code)]
pub struct TestSuite {
#[allow(dead_code)]
pub title: String,
Expand All @@ -60,6 +62,7 @@ pub struct TestSuite {
}

#[derive(Debug, Deserialize)]
#[allow(dead_code)]
pub struct Test {
pub result: String,
#[allow(dead_code)]
Expand Down
2 changes: 2 additions & 0 deletions crates/plugins/make/src/valgrind_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use std::{
use tmc_langs_util::{file_util, FileError};

#[derive(Debug)]
#[allow(dead_code)]
pub struct ValgrindLog {
#[allow(dead_code)]
pub header: (String, Vec<String>),
Expand Down Expand Up @@ -80,6 +81,7 @@ impl ValgrindLog {
}

#[derive(Debug)]
#[allow(dead_code)]
pub struct ValgrindResult {
#[allow(dead_code)]
pub pid: String,
Expand Down
119 changes: 80 additions & 39 deletions crates/tmc-langs-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ use serde_json::Value;
use std::{
collections::HashMap,
env,
fs::File,
io::{self, BufReader, Cursor, Read},
ops::Deref,
path::{Path, PathBuf},
};
use tmc_langs::{
file_util,
mooc::MoocClient,
tmc::{request::FeedbackAnswer, TestMyCodeClient, TestMyCodeClientError},
CommandError, Compression, Credentials, DownloadOrUpdateCourseExercisesResult, DownloadResult,
Language, StyleValidationResult, TmcConfig, UpdatedExercise,
};
use tmc_langs_util::deserialize;
use tmc_langs_util::{
deserialize,
file_util::{self, Lock, LockOptions},
};

pub enum ParsingResult {
Ok(Cli),
Expand Down Expand Up @@ -180,14 +180,18 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
locale: Locale(locale),
output_path,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let check_result =
run_checkstyle_write_results(&exercise_path, output_path.as_deref(), locale)?;
CliOutput::finished_with_data("ran checkstyle", check_result.map(DataKind::Validation))
}

Command::Clean { exercise_path } => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Write)?;
let _guard = lock.lock()?;

tmc_langs::clean(&exercise_path)?;
CliOutput::finished(format!("cleaned exercise at {}", exercise_path.display()))
}
Expand All @@ -199,7 +203,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
deterministic,
naive,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let hash = tmc_langs::compress_project_to(
&exercise_path,
&output_path,
Expand Down Expand Up @@ -227,11 +233,11 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
compression,
naive,
} => {
let mut archive = file_util::open_file_locked(&archive_path)?;
let mut guard = archive.write()?;
let mut archive_lock = Lock::file(&archive_path, LockOptions::Read)?;
let mut archive_guard = archive_lock.lock()?;

let mut data = vec![];
guard.read_to_end(&mut data)?;
archive_guard.get_file_mut().read_to_end(&mut data)?;

tmc_langs::extract_project(Cursor::new(data), &output_path, compression, true, naive)?;

Expand All @@ -243,7 +249,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
}

Command::FastAvailablePoints { exercise_path } => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let points = tmc_langs::get_available_points(&exercise_path)?;
CliOutput::finished_with_data(
format!("found {} available points", points.len()),
Expand All @@ -255,7 +263,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
search_path,
output_path,
} => {
file_util::lock!(search_path);
let mut lock = Lock::dir(&search_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let exercises =
tmc_langs::find_exercise_directories(&search_path).with_context(|| {
format!(
Expand All @@ -276,7 +286,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
exercise_path,
output_path,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let config = tmc_langs::get_exercise_packaging_configuration(&exercise_path)
.with_context(|| {
format!(
Expand Down Expand Up @@ -313,7 +325,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
exercise_path,
output_path,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

tmc_langs::prepare_solution(&exercise_path, &output_path).with_context(|| {
format!(
"Failed to prepare solutions for exercise at {}",
Expand All @@ -331,7 +345,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
exercise_path,
output_path,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

tmc_langs::prepare_stub(&exercise_path, &output_path).with_context(|| {
format!(
"Failed to prepare stubs for exercise at {}",
Expand All @@ -357,6 +373,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
tmc_param,
no_archive_prefix,
} => {
let mut clone_lock = Lock::dir(&clone_path, file_util::LockOptions::Read)?;
let _clone_guard = clone_lock.lock()?;

// will contain for each key all the values with that key in a list
let mut tmc_params_grouped = HashMap::new();
for value in &tmc_param {
Expand Down Expand Up @@ -439,7 +458,8 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
output_path,
wait_for_secret,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let secret = if wait_for_secret {
let mut s = String::new();
Expand Down Expand Up @@ -496,7 +516,8 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
exercise_path,
output_path,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let exercise_name = exercise_path.file_name().with_context(|| {
format!(
Expand Down Expand Up @@ -584,6 +605,9 @@ fn run_tmc_inner(
exercise_id,
target,
} => {
let mut output_lock = Lock::dir(&target, file_util::LockOptions::WriteTruncate)?;
let _output_guard = output_lock.lock()?;

client
.download_model_solution(exercise_id, &target)
.context("Failed to download model solution")?;
Expand All @@ -596,6 +620,9 @@ fn run_tmc_inner(
exercise_id,
output_path,
} => {
let mut output_lock = Lock::dir(&output_path, file_util::LockOptions::Write)?;
let _output_guard = output_lock.lock()?;

tmc_langs::download_old_submission(
client,
exercise_id,
Expand Down Expand Up @@ -837,7 +864,9 @@ fn run_tmc_inner(
paste_message,
submission_path,
} => {
file_util::lock!(submission_path);
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let locale = locale.map(|l| l.0);
let new_submission = client
.paste(exercise_id, &submission_path, paste_message, locale)
Expand All @@ -851,7 +880,9 @@ fn run_tmc_inner(
message_for_reviewer,
submission_path,
} => {
file_util::lock!(submission_path);
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let new_submission = client
.request_code_review(
exercise_id,
Expand All @@ -871,7 +902,9 @@ fn run_tmc_inner(
save_old_state,
exercise_path,
} => {
file_util::lock!(exercise_path);
let mut lock = Lock::dir(&exercise_path, LockOptions::Write)?;
let _guard = lock.lock()?;

if save_old_state {
// submit current state
client.submit(exercise_id, &exercise_path, None)?;
Expand Down Expand Up @@ -923,7 +956,9 @@ fn run_tmc_inner(
submission_path,
exercise_id,
} => {
file_util::lock!(submission_path);
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let locale = locale.map(|l| l.0);
let new_submission = client
.submit(exercise_id, &submission_path, locale)
Expand Down Expand Up @@ -1040,7 +1075,9 @@ fn run_mooc_inner(mooc: Mooc, client: &mut MoocClient) -> Result<CliOutput> {
task_id,
submission_path,
} => {
file_util::lock!(submission_path);
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
let _guard = lock.lock()?;

let temp = file_util::named_temp_file()?;
tmc_langs::compress_project_to(
&submission_path,
Expand Down Expand Up @@ -1128,27 +1165,28 @@ fn write_result_to_file_as_json<T: Serialize>(
pretty: bool,
secret: Option<String>,
) -> Result<()> {
let mut output_file = file_util::create_file_locked(output_path).with_context(|| {
format!(
"Failed to create results JSON file at {}",
output_path.display()
)
})?;
let guard = output_file.write()?;
let mut output_lock =
Lock::file(output_path, LockOptions::WriteTruncate).with_context(|| {
format!(
"Failed to create results JSON file at {}",
output_path.display()
)
})?;
let mut output_guard = output_lock.lock()?;

if let Some(secret) = secret {
let token = tmc_langs::sign_with_jwt(result, secret.as_bytes())?;
file_util::write_to_writer(token, guard.deref())
file_util::write_to_writer(token, output_guard.get_file_mut())
.with_context(|| format!("Failed to write result to {}", output_path.display()))?;
} else if pretty {
serde_json::to_writer_pretty(guard.deref(), result).with_context(|| {
serde_json::to_writer_pretty(output_guard.get_file_mut(), result).with_context(|| {
format!(
"Failed to write result as JSON to {}",
output_path.display()
)
})?;
} else {
serde_json::to_writer(guard.deref(), result).with_context(|| {
serde_json::to_writer(output_guard.get_file_mut(), result).with_context(|| {
format!(
"Failed to write result as JSON to {}",
output_path.display()
Expand All @@ -1172,13 +1210,16 @@ fn run_checkstyle_write_results(
)
})?;
if let Some(output_path) = output_path {
let output_file = File::create(output_path).with_context(|| {
format!(
"Failed to create code style check results file at {}",
output_path.display()
)
})?;
serde_json::to_writer(output_file, &check_result).with_context(|| {
let mut output_lock =
Lock::file(output_path, LockOptions::WriteTruncate).with_context(|| {
format!(
"Failed to create code style check results file at {}",
output_path.display()
)
})?;
let mut output_guard = output_lock.lock()?;

serde_json::to_writer(output_guard.get_file_mut(), &check_result).with_context(|| {
format!(
"Failed to write code style check results as JSON to {}",
output_path.display()
Expand Down
2 changes: 1 addition & 1 deletion crates/tmc-langs-framework/src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ fn walk_dir_for_compression(
.sort_by_file_name()
.into_iter()
// filter windows lock files
.filter_entry(|e| e.file_name() != ".tmc.lock")
.filter_entry(|e| e.file_name() != file_util::LOCK_FILE_NAME)
{
let entry = entry?;
let stripped = entry
Expand Down
Loading