Skip to content

Commit 014e205

Browse files
committed
moved project dir moving to a function and tested
1 parent 93a5476 commit 014e205

File tree

3 files changed

+107
-48
lines changed

3 files changed

+107
-48
lines changed

tmc-langs-cli/src/config.rs

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use crate::output::LocalExercise;
1111

1212
use anyhow::{Context, Error};
1313
use std::path::{Path, PathBuf};
14-
use std::{collections::BTreeMap, env};
14+
use std::{collections::BTreeMap, env, fs};
15+
use tmc_langs_framework::file_util;
1516

1617
// base directory for a given plugin's settings files
1718
fn get_tmc_dir(client_name: &str) -> Result<PathBuf, Error> {
@@ -26,7 +27,8 @@ pub fn list_local_course_exercises(
2627
client_name: &str,
2728
course_slug: &str,
2829
) -> Result<Vec<LocalExercise>, anyhow::Error> {
29-
let projects_dir = TmcConfig::load(client_name)?.projects_dir;
30+
let config_path = TmcConfig::get_location(client_name)?;
31+
let projects_dir = TmcConfig::load(client_name, &config_path)?.projects_dir;
3032
let mut projects_config = ProjectsConfig::load(&projects_dir)?;
3133

3234
let exercises = projects_config
@@ -52,6 +54,9 @@ pub fn migrate(
5254
exercise_checksum: &str,
5355
exercise_path: &Path,
5456
) -> anyhow::Result<()> {
57+
let mut lock = file_util::FileLock::new(exercise_path.to_path_buf())?;
58+
let guard = lock.lock()?;
59+
5560
let mut projects_config = ProjectsConfig::load(&tmc_config.projects_dir)?;
5661
let course_config = projects_config
5762
.courses
@@ -81,11 +86,47 @@ pub fn migrate(
8186
},
8287
);
8388

84-
super::move_dir(exercise_path, &target_dir)?;
89+
super::move_dir(exercise_path, guard, &target_dir)?;
8590
course_config.save_to_projects_dir(&tmc_config.projects_dir)?;
8691
Ok(())
8792
}
8893

94+
pub fn move_projects_dir(
95+
mut tmc_config: TmcConfig,
96+
config_path: &Path,
97+
target: PathBuf,
98+
) -> anyhow::Result<()> {
99+
if target.is_file() {
100+
anyhow::bail!("The target path points to a file.")
101+
}
102+
if !target.exists() {
103+
fs::create_dir_all(&target)
104+
.with_context(|| format!("Failed to create directory at {}", target.display()))?;
105+
}
106+
107+
let target_canon = target
108+
.canonicalize()
109+
.with_context(|| format!("Failed to canonicalize {}", target.display()))?;
110+
let prev_dir_canon = tmc_config.projects_dir.canonicalize().with_context(|| {
111+
format!(
112+
"Failed to canonicalize {}",
113+
tmc_config.projects_dir.display()
114+
)
115+
})?;
116+
if target_canon == prev_dir_canon {
117+
anyhow::bail!("Attempted to move the projects-dir to the directory it's already in.")
118+
}
119+
120+
let old_projects_dir = tmc_config.set_projects_dir(target.clone())?;
121+
122+
let mut lock = file_util::FileLock::new(old_projects_dir.clone())?;
123+
let guard = lock.lock()?;
124+
125+
super::move_dir(&old_projects_dir, guard, &target)?;
126+
tmc_config.save(config_path)?;
127+
Ok(())
128+
}
129+
89130
#[cfg(test)]
90131
mod test {
91132
use toml::value::Table;
@@ -147,4 +188,42 @@ mod test {
147188

148189
assert!(!exercise_path.path().exists());
149190
}
191+
192+
#[test]
193+
fn moves_projects_dir() {
194+
init();
195+
196+
let projects_dir = tempfile::tempdir().unwrap();
197+
let target_dir = tempfile::tempdir().unwrap();
198+
199+
let config_path = tempfile::NamedTempFile::new().unwrap();
200+
let tmc_config = TmcConfig {
201+
projects_dir: projects_dir.path().to_path_buf(),
202+
table: Table::new(),
203+
};
204+
205+
file_to(
206+
projects_dir.path(),
207+
"some course/some exercise/some file",
208+
"",
209+
);
210+
211+
assert!(!target_dir
212+
.path()
213+
.join("some course/some exercise/some file")
214+
.exists());
215+
216+
move_projects_dir(
217+
tmc_config,
218+
config_path.path(),
219+
target_dir.path().to_path_buf(),
220+
)
221+
.unwrap();
222+
223+
assert!(target_dir
224+
.path()
225+
.join("some course/some exercise/some file")
226+
.exists());
227+
assert!(!projects_dir.path().exists());
228+
}
150229
}

tmc-langs-cli/src/config/tmc_config.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ impl TmcConfig {
6161
Ok(target)
6262
}
6363

64-
pub fn save(self, client_name: &str) -> Result<()> {
65-
let path = Self::get_location(client_name)?;
64+
pub fn save(self, path: &Path) -> Result<()> {
6665
if let Some(parent) = path.parent() {
6766
file_util::create_dir_all(parent)?;
6867
}
@@ -82,9 +81,7 @@ impl TmcConfig {
8281
Ok(())
8382
}
8483

85-
pub fn load(client_name: &str) -> Result<TmcConfig> {
86-
let path = Self::get_location(client_name)?;
87-
84+
pub fn load(client_name: &str, path: &Path) -> Result<TmcConfig> {
8885
// try to open config file
8986
let config = match file_util::open_file_lock(&path) {
9087
Ok(mut lock) => {
@@ -161,11 +158,11 @@ impl TmcConfig {
161158
}
162159

163160
// path to the configuration file
164-
fn get_location(client_name: &str) -> Result<PathBuf> {
161+
pub fn get_location(client_name: &str) -> Result<PathBuf> {
165162
super::get_tmc_dir(client_name).map(|dir| dir.join("config.toml"))
166163
}
167164

168-
// some client use a different name for the directory
165+
// some clients use a different name for the directory
169166
fn get_client_stub(client: &str) -> &str {
170167
match client {
171168
"vscode_plugin" => "vscode",

tmc-langs-cli/src/lib.rs

Lines changed: 21 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ use tmc_client::{
3838
};
3939
use tmc_client::{ClientError, FeedbackAnswer, TmcClient, Token};
4040
use tmc_langs_framework::{
41-
domain::StyleValidationResult, error::CommandError, file_util, warning_reporter,
41+
domain::StyleValidationResult,
42+
error::CommandError,
43+
file_util::{self, FileLockGuard},
44+
warning_reporter,
4245
};
4346
use tmc_langs_util::{
4447
progress_reporter,
@@ -656,7 +659,8 @@ fn run_core(
656659
("check-exercise-updates", Some(_)) => {
657660
let mut updated_exercises = vec![];
658661

659-
let projects_dir = TmcConfig::load(client_name)?.projects_dir;
662+
let config_path = TmcConfig::get_location(client_name)?;
663+
let projects_dir = TmcConfig::load(client_name, &config_path)?.projects_dir;
660664
let config = ProjectsConfig::load(&projects_dir)?;
661665
let local_exercises = config
662666
.courses
@@ -758,7 +762,8 @@ fn run_core(
758762
.collect::<Result<_>>()?;
759763
let exercises_details = client.get_exercises_details(exercises)?;
760764

761-
let projects_dir = TmcConfig::load(client_name)?.projects_dir;
765+
let config_path = TmcConfig::get_location(client_name)?;
766+
let projects_dir = TmcConfig::load(client_name, &config_path)?.projects_dir;
762767
let mut projects_config = ProjectsConfig::load(&projects_dir)?;
763768

764769
// separate downloads into ones that don't need to be downloaded and ones that do
@@ -1332,7 +1337,8 @@ fn run_core(
13321337
let mut to_be_skipped = vec![];
13331338
let mut course_data = HashMap::<String, Vec<(String, String, usize)>>::new();
13341339

1335-
let projects_dir = TmcConfig::load(client_name)?.projects_dir;
1340+
let config_path = TmcConfig::get_location(client_name)?;
1341+
let projects_dir = TmcConfig::load(client_name, &config_path)?.projects_dir;
13361342
let mut projects_config = ProjectsConfig::load(&projects_dir)?;
13371343
let local_exercises = projects_config
13381344
.courses
@@ -1441,7 +1447,9 @@ fn run_core(
14411447

14421448
fn run_settings(matches: &ArgMatches, pretty: bool) -> Result<PrintToken> {
14431449
let client_name = matches.value_of("client-name").unwrap();
1444-
let mut tmc_config = TmcConfig::load(client_name)?;
1450+
1451+
let config_path = TmcConfig::get_location(client_name)?;
1452+
let mut tmc_config = TmcConfig::load(client_name, &config_path)?;
14451453

14461454
match matches.subcommand() {
14471455
("get", Some(matches)) => {
@@ -1468,8 +1476,6 @@ fn run_settings(matches: &ArgMatches, pretty: bool) -> Result<PrintToken> {
14681476

14691477
let exercise_checksum = matches.value_of("exercise-checksum").unwrap();
14701478

1471-
file_util::lock!(exercise_path);
1472-
14731479
config::migrate(
14741480
&tmc_config,
14751481
course_slug,
@@ -1486,33 +1492,7 @@ fn run_settings(matches: &ArgMatches, pretty: bool) -> Result<PrintToken> {
14861492
let dir = matches.value_of("dir").unwrap();
14871493
let target = PathBuf::from(dir);
14881494

1489-
if target.is_file() {
1490-
anyhow::bail!("The target path points to a file.")
1491-
}
1492-
if !target.exists() {
1493-
fs::create_dir_all(&target).with_context(|| {
1494-
format!("Failed to create directory at {}", target.display())
1495-
})?;
1496-
}
1497-
1498-
let target_canon = target
1499-
.canonicalize()
1500-
.with_context(|| format!("Failed to canonicalize {}", target.display()))?;
1501-
let prev_dir_canon = tmc_config.projects_dir.canonicalize().with_context(|| {
1502-
format!(
1503-
"Failed to canonicalize {}",
1504-
tmc_config.projects_dir.display()
1505-
)
1506-
})?;
1507-
if target_canon == prev_dir_canon {
1508-
anyhow::bail!(
1509-
"Attempted to move the projects-dir to the directory it's already in."
1510-
)
1511-
}
1512-
1513-
let old_projects_dir = tmc_config.set_projects_dir(target.clone())?;
1514-
move_dir(&old_projects_dir, &target)?;
1515-
tmc_config.save(client_name)?;
1495+
config::move_projects_dir(tmc_config, &config_path, target)?;
15161496

15171497
let output = Output::finished_with_data("moved project directory", None);
15181498
print_output(&output, pretty)
@@ -1533,7 +1513,7 @@ fn run_settings(matches: &ArgMatches, pretty: bool) -> Result<PrintToken> {
15331513
tmc_config
15341514
.insert(key.to_string(), value.clone())
15351515
.with_context(|| format!("Failed to set {} to {}", key, value))?;
1536-
tmc_config.save(client_name)?;
1516+
tmc_config.save(&config_path)?;
15371517

15381518
let output = Output::finished_with_data("set setting", None);
15391519
print_output(&output, pretty)
@@ -1549,7 +1529,7 @@ fn run_settings(matches: &ArgMatches, pretty: bool) -> Result<PrintToken> {
15491529
tmc_config
15501530
.remove(key)
15511531
.with_context(|| format!("Failed to unset {}", key))?;
1552-
tmc_config.save(client_name)?;
1532+
tmc_config.save(&config_path)?;
15531533

15541534
let output = Output::finished_with_data("unset setting", None);
15551535
print_output(&output, pretty)
@@ -1698,7 +1678,7 @@ fn json_to_toml(json: JsonValue) -> Result<TomlValue> {
16981678
}
16991679
}
17001680

1701-
fn move_dir(source: &Path, target: &Path) -> anyhow::Result<()> {
1681+
fn move_dir(source: &Path, source_lock: FileLockGuard, target: &Path) -> anyhow::Result<()> {
17021682
let mut file_count_copied = 0;
17031683
let mut file_count_total = 0;
17041684
for entry in WalkDir::new(source) {
@@ -1713,7 +1693,7 @@ fn move_dir(source: &Path, target: &Path) -> anyhow::Result<()> {
17131693
format!("Moving dir {} -> {}", source.display(), target.display()),
17141694
);
17151695

1716-
for entry in WalkDir::new(source).contents_first(true) {
1696+
for entry in WalkDir::new(source).contents_first(true).min_depth(1) {
17171697
let entry =
17181698
entry.with_context(|| format!("Failed to read file inside {}", source.display()))?;
17191699
let entry_path = entry.path();
@@ -1770,6 +1750,9 @@ fn move_dir(source: &Path, target: &Path) -> anyhow::Result<()> {
17701750
}
17711751
}
17721752

1753+
drop(source_lock);
1754+
fs::remove_dir(source)?;
1755+
17731756
finish_stage("Finished moving project directory");
17741757
Ok(())
17751758
}

0 commit comments

Comments
 (0)