Skip to content

Commit b4ad694

Browse files
committed
Fix file locking
1 parent d5fb905 commit b4ad694

File tree

19 files changed

+695
-505
lines changed

19 files changed

+695
-505
lines changed

Cargo.lock

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

crates/bindings/tmc-langs-node/src/helpers.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ macro_rules! lock {
99
( $cx: ident, $( $path: expr ),+ ) => {
1010
$(
1111
let path_buf: PathBuf = (&$path).into();
12-
let mut fl = $crate::file_util::FileLock::new(path_buf).map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
13-
let _lock = fl.lock().map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
12+
let mut lock = $crate::file_util::Lock::file(path_buf, $crate::file_util::LockOptions::Write).map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
13+
let _guard = lock.lock().map_err(|e| $crate::helpers::convert_err(&mut $cx, e))?;
1414
)*
1515
};
1616
}

crates/bindings/tmc-langs-node/src/lib.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,14 @@ fn extract_project(mut cx: FunctionContext) -> JsResult<JsValue> {
134134
compression: Compression
135135
);
136136

137-
let mut archive =
138-
file_util::open_file_locked(archive_path).map_err(|e| convert_err(&mut cx, e))?;
139-
let mut guard = archive.write().expect("failed to lock file");
137+
let mut archive_lock = file_util::Lock::file(archive_path, file_util::LockOptions::Read)
138+
.map_err(|e| convert_err(&mut cx, e))?;
139+
let mut archive_guard = archive_lock.lock().map_err(|e| convert_err(&mut cx, e))?;
140140
let mut data = vec![];
141-
guard.read_to_end(&mut data).expect("failed to read data");
141+
archive_guard
142+
.get_file_mut()
143+
.read_to_end(&mut data)
144+
.expect("failed to read data");
142145

143146
let res =
144147
tmc_langs::extract_project(Cursor::new(data), &output_path, compression, false, false);

crates/plugins/make/src/check_log.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::collections::HashMap;
55
use tmc_langs_framework::{RunResult, RunStatus, TestResult};
66

77
#[derive(Debug, Deserialize)]
8+
#[allow(dead_code)]
89
pub struct CheckLog {
910
#[allow(dead_code)]
1011
pub datetime: String,
@@ -52,6 +53,7 @@ impl CheckLog {
5253
}
5354

5455
#[derive(Debug, Deserialize)]
56+
#[allow(dead_code)]
5557
pub struct TestSuite {
5658
#[allow(dead_code)]
5759
pub title: String,
@@ -60,6 +62,7 @@ pub struct TestSuite {
6062
}
6163

6264
#[derive(Debug, Deserialize)]
65+
#[allow(dead_code)]
6366
pub struct Test {
6467
pub result: String,
6568
#[allow(dead_code)]

crates/plugins/make/src/valgrind_log.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{
1111
use tmc_langs_util::{file_util, FileError};
1212

1313
#[derive(Debug)]
14+
#[allow(dead_code)]
1415
pub struct ValgrindLog {
1516
#[allow(dead_code)]
1617
pub header: (String, Vec<String>),
@@ -80,6 +81,7 @@ impl ValgrindLog {
8081
}
8182

8283
#[derive(Debug)]
84+
#[allow(dead_code)]
8385
pub struct ValgrindResult {
8486
#[allow(dead_code)]
8587
pub pid: String,

crates/tmc-langs-cli/src/lib.rs

Lines changed: 77 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use std::{
2626
path::{Path, PathBuf},
2727
};
2828
use tmc_langs::{
29+
file_util::{self, Lock, LockOptions},
2930
file_util,
3031
mooc::MoocClient,
3132
tmc::{request::FeedbackAnswer, TestMyCodeClient, TestMyCodeClientError},
@@ -180,14 +181,18 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
180181
locale: Locale(locale),
181182
output_path,
182183
} => {
183-
file_util::lock!(exercise_path);
184+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
185+
let _guard = lock.lock()?;
186+
184187
let check_result =
185188
run_checkstyle_write_results(&exercise_path, output_path.as_deref(), locale)?;
186189
CliOutput::finished_with_data("ran checkstyle", check_result.map(DataKind::Validation))
187190
}
188191

189192
Command::Clean { exercise_path } => {
190-
file_util::lock!(exercise_path);
193+
let mut lock = Lock::dir(&exercise_path, LockOptions::Write)?;
194+
let _guard = lock.lock()?;
195+
191196
tmc_langs::clean(&exercise_path)?;
192197
CliOutput::finished(format!("cleaned exercise at {}", exercise_path.display()))
193198
}
@@ -199,7 +204,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
199204
deterministic,
200205
naive,
201206
} => {
202-
file_util::lock!(exercise_path);
207+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
208+
let _guard = lock.lock()?;
209+
203210
let hash = tmc_langs::compress_project_to(
204211
&exercise_path,
205212
&output_path,
@@ -227,11 +234,11 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
227234
compression,
228235
naive,
229236
} => {
230-
let mut archive = file_util::open_file_locked(&archive_path)?;
231-
let mut guard = archive.write()?;
237+
let mut archive_lock = Lock::file(&archive_path, LockOptions::Read)?;
238+
let mut archive_guard = archive_lock.lock()?;
232239

233240
let mut data = vec![];
234-
guard.read_to_end(&mut data)?;
241+
archive_guard.get_file_mut().read_to_end(&mut data)?;
235242

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

@@ -243,7 +250,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
243250
}
244251

245252
Command::FastAvailablePoints { exercise_path } => {
246-
file_util::lock!(exercise_path);
253+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
254+
let _guard = lock.lock()?;
255+
247256
let points = tmc_langs::get_available_points(&exercise_path)?;
248257
CliOutput::finished_with_data(
249258
format!("found {} available points", points.len()),
@@ -255,7 +264,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
255264
search_path,
256265
output_path,
257266
} => {
258-
file_util::lock!(search_path);
267+
let mut lock = Lock::dir(&search_path, LockOptions::Read)?;
268+
let _guard = lock.lock()?;
269+
259270
let exercises =
260271
tmc_langs::find_exercise_directories(&search_path).with_context(|| {
261272
format!(
@@ -276,7 +287,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
276287
exercise_path,
277288
output_path,
278289
} => {
279-
file_util::lock!(exercise_path);
290+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
291+
let _guard = lock.lock()?;
292+
280293
let config = tmc_langs::get_exercise_packaging_configuration(&exercise_path)
281294
.with_context(|| {
282295
format!(
@@ -313,7 +326,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
313326
exercise_path,
314327
output_path,
315328
} => {
316-
file_util::lock!(exercise_path);
329+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
330+
let _guard = lock.lock()?;
331+
317332
tmc_langs::prepare_solution(&exercise_path, &output_path).with_context(|| {
318333
format!(
319334
"Failed to prepare solutions for exercise at {}",
@@ -331,7 +346,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
331346
exercise_path,
332347
output_path,
333348
} => {
334-
file_util::lock!(exercise_path);
349+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
350+
let _guard = lock.lock()?;
351+
335352
tmc_langs::prepare_stub(&exercise_path, &output_path).with_context(|| {
336353
format!(
337354
"Failed to prepare stubs for exercise at {}",
@@ -357,6 +374,9 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
357374
tmc_param,
358375
no_archive_prefix,
359376
} => {
377+
let mut clone_lock = Lock::dir(&clone_path, file_util::LockOptions::Read)?;
378+
let _clone_guard = clone_lock.lock()?;
379+
360380
// will contain for each key all the values with that key in a list
361381
let mut tmc_params_grouped = HashMap::new();
362382
for value in &tmc_param {
@@ -439,7 +459,8 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
439459
output_path,
440460
wait_for_secret,
441461
} => {
442-
file_util::lock!(exercise_path);
462+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
463+
let _guard = lock.lock()?;
443464

444465
let secret = if wait_for_secret {
445466
let mut s = String::new();
@@ -496,7 +517,8 @@ fn run_app(cli: Cli) -> Result<CliOutput> {
496517
exercise_path,
497518
output_path,
498519
} => {
499-
file_util::lock!(exercise_path);
520+
let mut lock = Lock::dir(&exercise_path, LockOptions::Read)?;
521+
let _guard = lock.lock()?;
500522

501523
let exercise_name = exercise_path.file_name().with_context(|| {
502524
format!(
@@ -584,6 +606,9 @@ fn run_tmc_inner(
584606
exercise_id,
585607
target,
586608
} => {
609+
let mut output_lock = Lock::dir(&target, file_util::LockOptions::WriteTruncate)?;
610+
let _output_guard = output_lock.lock()?;
611+
587612
client
588613
.download_model_solution(exercise_id, &target)
589614
.context("Failed to download model solution")?;
@@ -596,6 +621,9 @@ fn run_tmc_inner(
596621
exercise_id,
597622
output_path,
598623
} => {
624+
let mut output_lock = Lock::dir(&output_path, file_util::LockOptions::Write)?;
625+
let _output_guard = output_lock.lock()?;
626+
599627
tmc_langs::download_old_submission(
600628
client,
601629
exercise_id,
@@ -837,7 +865,9 @@ fn run_tmc_inner(
837865
paste_message,
838866
submission_path,
839867
} => {
840-
file_util::lock!(submission_path);
868+
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
869+
let _guard = lock.lock()?;
870+
841871
let locale = locale.map(|l| l.0);
842872
let new_submission = client
843873
.paste(exercise_id, &submission_path, paste_message, locale)
@@ -851,7 +881,9 @@ fn run_tmc_inner(
851881
message_for_reviewer,
852882
submission_path,
853883
} => {
854-
file_util::lock!(submission_path);
884+
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
885+
let _guard = lock.lock()?;
886+
855887
let new_submission = client
856888
.request_code_review(
857889
exercise_id,
@@ -871,7 +903,9 @@ fn run_tmc_inner(
871903
save_old_state,
872904
exercise_path,
873905
} => {
874-
file_util::lock!(exercise_path);
906+
let mut lock = Lock::dir(&exercise_path, LockOptions::Write)?;
907+
let _guard = lock.lock()?;
908+
875909
if save_old_state {
876910
// submit current state
877911
client.submit(exercise_id, &exercise_path, None)?;
@@ -923,7 +957,9 @@ fn run_tmc_inner(
923957
submission_path,
924958
exercise_id,
925959
} => {
926-
file_util::lock!(submission_path);
960+
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
961+
let _guard = lock.lock()?;
962+
927963
let locale = locale.map(|l| l.0);
928964
let new_submission = client
929965
.submit(exercise_id, &submission_path, locale)
@@ -1040,7 +1076,9 @@ fn run_mooc_inner(mooc: Mooc, client: &mut MoocClient) -> Result<CliOutput> {
10401076
task_id,
10411077
submission_path,
10421078
} => {
1043-
file_util::lock!(submission_path);
1079+
let mut lock = Lock::dir(&submission_path, LockOptions::Read)?;
1080+
let _guard = lock.lock()?;
1081+
10441082
let temp = file_util::named_temp_file()?;
10451083
tmc_langs::compress_project_to(
10461084
&submission_path,
@@ -1128,27 +1166,28 @@ fn write_result_to_file_as_json<T: Serialize>(
11281166
pretty: bool,
11291167
secret: Option<String>,
11301168
) -> Result<()> {
1131-
let mut output_file = file_util::create_file_locked(output_path).with_context(|| {
1132-
format!(
1133-
"Failed to create results JSON file at {}",
1134-
output_path.display()
1135-
)
1136-
})?;
1137-
let guard = output_file.write()?;
1169+
let mut output_lock =
1170+
Lock::file(output_path, LockOptions::WriteTruncate).with_context(|| {
1171+
format!(
1172+
"Failed to create results JSON file at {}",
1173+
output_path.display()
1174+
)
1175+
})?;
1176+
let mut output_guard = output_lock.lock()?;
11381177

11391178
if let Some(secret) = secret {
11401179
let token = tmc_langs::sign_with_jwt(result, secret.as_bytes())?;
1141-
file_util::write_to_writer(token, guard.deref())
1180+
file_util::write_to_writer(token, output_guard.get_file_mut())
11421181
.with_context(|| format!("Failed to write result to {}", output_path.display()))?;
11431182
} else if pretty {
1144-
serde_json::to_writer_pretty(guard.deref(), result).with_context(|| {
1183+
serde_json::to_writer_pretty(output_guard.get_file_mut(), result).with_context(|| {
11451184
format!(
11461185
"Failed to write result as JSON to {}",
11471186
output_path.display()
11481187
)
11491188
})?;
11501189
} else {
1151-
serde_json::to_writer(guard.deref(), result).with_context(|| {
1190+
serde_json::to_writer(output_guard.get_file_mut(), result).with_context(|| {
11521191
format!(
11531192
"Failed to write result as JSON to {}",
11541193
output_path.display()
@@ -1172,13 +1211,16 @@ fn run_checkstyle_write_results(
11721211
)
11731212
})?;
11741213
if let Some(output_path) = output_path {
1175-
let output_file = File::create(output_path).with_context(|| {
1176-
format!(
1177-
"Failed to create code style check results file at {}",
1178-
output_path.display()
1179-
)
1180-
})?;
1181-
serde_json::to_writer(output_file, &check_result).with_context(|| {
1214+
let mut output_lock =
1215+
Lock::file(output_path, LockOptions::WriteTruncate).with_context(|| {
1216+
format!(
1217+
"Failed to create code style check results file at {}",
1218+
output_path.display()
1219+
)
1220+
})?;
1221+
let mut output_guard = output_lock.lock()?;
1222+
1223+
serde_json::to_writer(output_guard.get_file_mut(), &check_result).with_context(|| {
11821224
format!(
11831225
"Failed to write code style check results as JSON to {}",
11841226
output_path.display()

crates/tmc-langs-framework/src/archive.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ fn walk_dir_for_compression(
365365
.sort_by_file_name()
366366
.into_iter()
367367
// filter windows lock files
368-
.filter_entry(|e| e.file_name() != ".tmc.lock")
368+
.filter_entry(|e| e.file_name() != file_util::LOCK_FILE_NAME)
369369
{
370370
let entry = entry?;
371371
let stripped = entry

crates/tmc-langs-framework/src/tmc_project_yml.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ use serde::{
77
};
88
use std::{
99
fmt::{self, Display},
10-
ops::Deref,
1110
path::{Path, PathBuf},
1211
};
13-
use tmc_langs_util::{deserialize, file_util, FileError};
12+
use tmc_langs_util::{
13+
deserialize,
14+
file_util::{self, Lock, LockOptions},
15+
};
1416

1517
/// Extra data from a `.tmcproject.yml` file.
1618
#[derive(Debug, Serialize, Deserialize, Default, Clone)]
@@ -125,11 +127,9 @@ impl TmcProjectYml {
125127
/// Saves the TmcProjectYml to the given directory.
126128
pub fn save_to_dir(&self, dir: &Path) -> Result<(), TmcError> {
127129
let config_path = Self::path_in_dir(dir);
128-
let mut file = file_util::create_file_locked(&config_path)?;
129-
let guard = file
130-
.write()
131-
.map_err(|e| FileError::FdLock(config_path.clone(), e))?;
132-
serde_yaml::to_writer(guard.deref(), &self)?;
130+
let mut lock = Lock::file(&config_path, LockOptions::WriteCreate)?;
131+
let mut guard = lock.lock()?;
132+
serde_yaml::to_writer(guard.get_file_mut(), &self)?;
133133
Ok(())
134134
}
135135
}

0 commit comments

Comments
 (0)