Skip to content

Commit 82d0c5a

Browse files
committed
download-old-submission
1 parent c111424 commit 82d0c5a

File tree

5 files changed

+121
-49
lines changed

5 files changed

+121
-49
lines changed

tmc-langs-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ serde = "1"
2020
anyhow = "1"
2121
quit = "1"
2222
dirs = "3"
23+
tempfile = "3"
2324

2425
[dev-dependencies]
2526
tempfile = "3"

tmc-langs-cli/src/main.rs

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use tmc_langs_framework::io::submission_processing;
1616
use tmc_langs_util::{task_executor, Language};
1717
use url::Url;
1818
use walkdir::WalkDir;
19+
use tempfile::NamedTempFile;
1920

2021
#[quit::main]
2122
fn main() {
@@ -123,11 +124,11 @@ fn run() -> Result<()> {
123124
.arg(Arg::with_name("checkstyle-output-path")
124125
.long("checkstyle-output-path")
125126
.help("Runs checkstyle if defined")
126-
.takes_value(true))
127+
.takes_value(true)
128+
.requires("locale"))
127129
.arg(Arg::with_name("locale")
128130
.help("Language as a three letter ISO 639-3 code, e.g. 'eng' or 'fin'.")
129131
.long("locale")
130-
.help("Required if checkstyle-output-path is defined")
131132
.takes_value(true)))
132133

133134
.subcommand(SubCommand::with_name("scan-exercise")
@@ -183,11 +184,13 @@ fn run() -> Result<()> {
183184
.arg(Arg::with_name("email")
184185
.help("The email address of your TMC account")
185186
.long("email")
186-
.takes_value(true))
187+
.takes_value(true)
188+
.required_unless("set-access-token"))
187189
.arg(Arg::with_name("set-access-token")
188190
.help("The OAUTH2 access token that should be used for authentication")
189191
.long("set-access-token")
190-
.takes_value(true)))
192+
.takes_value(true)
193+
.required_unless("email")))
191194

192195
.subcommand(SubCommand::with_name("logout")
193196
.about("Logout and remove OAuth2 token from config."))
@@ -357,6 +360,36 @@ fn run() -> Result<()> {
357360
.arg(Arg::with_name("target")
358361
.long("target")
359362
.required(true)
363+
.takes_value(true)))
364+
365+
.subcommand(SubCommand::with_name("reset-exercise")
366+
.about("Reset exercise, optionally submitting it before doing so.")
367+
.arg(Arg::with_name("exercise-path")
368+
.long("exercise-path")
369+
.required(true)
370+
.takes_value(true))
371+
.arg(Arg::with_name("save-old-state")
372+
.long("save-old-state")
373+
.requires("submission-url"))
374+
.arg(Arg::with_name("submission-url")
375+
.long("submission-url")
376+
.takes_value(true)))
377+
378+
.subcommand(SubCommand::with_name("download-old-submission")
379+
.about("Downloads an old submission.")
380+
.arg(Arg::with_name("exercise-id")
381+
.long("exercise-id")
382+
.required(true)
383+
.takes_value(true))
384+
.arg(Arg::with_name("output-path")
385+
.long("exercise-path")
386+
.required(true)
387+
.takes_value(true))
388+
.arg(Arg::with_name("save-old-state")
389+
.long("save-old-state")
390+
.requires("submission-url"))
391+
.arg(Arg::with_name("submission-url")
392+
.long("submission-url")
360393
.takes_value(true))))
361394

362395
.get_matches();
@@ -447,9 +480,6 @@ fn run() -> Result<()> {
447480
let checkstyle_output_path = matches.value_of("checkstyle-output-path");
448481
let checkstyle_output_path: Option<&Path> = checkstyle_output_path.map(Path::new);
449482

450-
let optional_locale = matches.value_of("locale");
451-
let optional_locale = optional_locale.map(into_locale);
452-
453483
let test_result = task_executor::run_tests(exercise_path).with_context(|| {
454484
format!(
455485
"Failed to run tests for exercise at {}",
@@ -460,13 +490,8 @@ fn run() -> Result<()> {
460490
write_result_to_file_as_json(&test_result, output_path)?;
461491

462492
if let Some(checkstyle_output_path) = checkstyle_output_path {
463-
let locale = optional_locale.unwrap_or_else(|| {
464-
Error::with_description(
465-
"Locale must be given if checkstyle-output-path is given.",
466-
ErrorKind::ArgumentNotFound,
467-
)
468-
.exit()
469-
})?;
493+
let locale = matches.value_of("locale").unwrap();
494+
let locale = into_locale(locale)?;
470495

471496
run_checkstyle(exercise_path, checkstyle_output_path, locale)?;
472497
}
@@ -601,11 +626,7 @@ fn run() -> Result<()> {
601626
.context("Failed to authenticate with TMC")?;
602627
token
603628
} else {
604-
Error::with_description(
605-
"Either the --email or --set-access-token argument should be given",
606-
ErrorKind::MissingRequiredArgument,
607-
)
608-
.exit();
629+
unreachable!("validation error");
609630
};
610631

611632
// create token file
@@ -850,6 +871,43 @@ fn run() -> Result<()> {
850871

851872
core.download_model_solution(solution_download_url, target)
852873
.context("Failed to download model solution")?;
874+
} else if let Some(matches) = matches.subcommand_matches("reset-exercise") {
875+
let exercise_path = matches.value_of("exercise-path").unwrap();
876+
let exercise_path = Path::new(exercise_path);
877+
878+
let exercise_id = matches.value_of("exercise-id").unwrap();
879+
let exercise_id = into_usize(exercise_id)?;
880+
881+
let save_old_state = matches.is_present("save-old-state");
882+
883+
if save_old_state {
884+
let submission_url = matches.value_of("submission_url").unwrap();
885+
let submission_url = into_url(submission_url)?;
886+
core.submit(submission_url, exercise_path, None)?;
887+
}
888+
core.reset(exercise_id, exercise_path)?;
889+
} else if let Some(matches) = matches.subcommand_matches("download-old-submission") {
890+
let exercise_id = matches.value_of("exercise-id").unwrap();
891+
let exercise_id = into_usize(exercise_id)?;
892+
893+
let submission_id = matches.value_of("submission-id").unwrap();
894+
let submission_id = into_usize(submission_id)?;
895+
896+
let output_path = matches.value_of("output-path").unwrap();
897+
let output_path = Path::new(output_path);
898+
899+
let save_old_state = matches.is_present("save-old-state");
900+
901+
if save_old_state {
902+
let submission_url = matches.value_of("submission_url").unwrap();
903+
let submission_url = into_url(submission_url)?;
904+
core.submit(submission_url, output_path, None)?;
905+
}
906+
core.reset(exercise_id, output_path)?;
907+
908+
let temp_zip = NamedTempFile::new().context("Failed to create a temporary archive")?;
909+
core.download_old_submission(submission_id, temp_zip.path())?;
910+
task_executor::extract_project(temp_zip.path(), output_path)?;
853911
}
854912
}
855913
Ok(())

tmc-langs-cli/tests/core_integration.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,31 @@ fn run_core_cmd(args: &[&str]) -> Output {
3838

3939
#[test]
4040
#[ignore]
41-
fn download_model_solution() {
41+
fn downloads_model_solution() {
4242
todo!()
4343
}
4444

4545
#[test]
4646
#[ignore]
47-
fn download_or_update_exercises() {
47+
fn downloads_or_updates_exercises() {
4848
todo!()
4949
}
5050

5151
#[test]
5252
#[ignore]
53-
fn get_course_details() {
53+
fn gets_course_details() {
5454
todo!()
5555
}
5656

5757
#[test]
5858
#[ignore]
59-
fn get_exercise_updates() {
59+
fn gets_exercise_updates() {
6060
todo!()
6161
}
6262

6363
#[test]
6464
#[ignore]
65-
fn get_organizations() {
65+
fn gets_organizations() {
6666
init();
6767
let out = run_core_cmd(&["get-organizations"]);
6868
assert!(out.status.success());
@@ -72,13 +72,13 @@ fn get_organizations() {
7272

7373
#[test]
7474
#[ignore]
75-
fn get_unread_reviews() {
75+
fn gets_unread_reviews() {
7676
todo!()
7777
}
7878

7979
#[test]
8080
#[ignore]
81-
fn list_courses() {
81+
fn lists_courses() {
8282
init();
8383
let out = run_core_cmd(&["list-courses", "--organization", "hy"]);
8484
assert!(out.status.success());
@@ -88,42 +88,42 @@ fn list_courses() {
8888

8989
#[test]
9090
#[ignore]
91-
fn mark_review_as_read() {
91+
fn marks_review_as_read() {
9292
todo!()
9393
}
9494

9595
#[test]
9696
#[ignore]
97-
fn paste_with_comment() {
97+
fn pastes_with_comment() {
9898
todo!()
9999
}
100100

101101
#[test]
102102
#[ignore]
103-
fn request_code_review() {
103+
fn requests_code_review() {
104104
todo!()
105105
}
106106

107107
#[test]
108108
#[ignore]
109-
fn run_checkstyle() {
109+
fn runs_checkstyle() {
110110
todo!()
111111
}
112112

113113
#[test]
114114
#[ignore]
115-
fn run_tests() {
115+
fn runs_tests() {
116116
todo!()
117117
}
118118

119119
#[test]
120120
#[ignore]
121-
fn send_feedback() {
121+
fn sends_feedback() {
122122
todo!()
123123
}
124124

125125
#[test]
126126
#[ignore]
127-
fn submit() {
127+
fn submits() {
128128
todo!()
129129
}

tmc-langs-core/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ pub enum CoreError {
2323
FileOpen(PathBuf, #[source] std::io::Error),
2424
#[error("Failed to write to file at {0}")]
2525
FileWrite(PathBuf, #[source] std::io::Error),
26+
#[error("Failed to remove directory at {0}")]
27+
DirRemove(PathBuf, #[source] std::io::Error),
2628

2729
// network
2830
#[error("HTTP error {1} for {0}: {2}")]

0 commit comments

Comments
 (0)