Skip to content

Commit 02ac4c9

Browse files
committed
added check-exercise-updates, id to course config
1 parent f5f7c35 commit 02ac4c9

File tree

4 files changed

+93
-6
lines changed

4 files changed

+93
-6
lines changed

tmc-langs-cli/src/app.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Create clap app
22
3-
use crate::output::{CombinedCourseData, DownloadOrUpdateCourseExercisesResult, LocalExercise};
3+
use crate::output::{
4+
CombinedCourseData, DownloadOrUpdateCourseExercisesResult, LocalExercise, UpdatedExercise,
5+
};
46
use clap::{App, AppSettings, Arg, SubCommand};
57
use schemars::JsonSchema;
68
use std::path::PathBuf;
@@ -341,6 +343,10 @@ fn create_core_app() -> App<'static, 'static> {
341343
.required(true)
342344
.takes_value(true))
343345

346+
.subcommand(SubCommand::with_name("check-exercise-updates")
347+
.about("Checks for updates to any exercises that exist locally.")
348+
.long_about(schema_leaked::<Vec<UpdatedExercise>>()))
349+
344350
.subcommand(SubCommand::with_name("download-model-solution")
345351
.about("Downloads an exercise's model solution")
346352
.long_about(SCHEMA_NULL)
@@ -720,6 +726,13 @@ fn create_settings_app() -> App<'static, 'static> {
720726
.required(true)
721727
.takes_value(true),
722728
)
729+
.arg(
730+
Arg::with_name("exercise-id")
731+
.help("The exercise id, e.g. 1234.")
732+
.long("exercise-id")
733+
.required(true)
734+
.takes_value(true),
735+
)
723736
.arg(
724737
Arg::with_name("exercise-slug")
725738
.help("The exercise slug, e.g. part01-Part01_01.Sandbox.")

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ impl CourseConfig {
104104

105105
#[derive(Debug, Serialize, Deserialize)]
106106
pub struct Exercise {
107+
pub id: usize,
107108
pub checksum: String,
108109
}
109110

@@ -145,6 +146,7 @@ mod test {
145146
exercises.insert(
146147
"ex 1".to_string(),
147148
Exercise {
149+
id: 4321,
148150
checksum: "abcd1234".to_string(),
149151
},
150152
);
@@ -157,6 +159,7 @@ mod test {
157159
s,
158160
r#"course = "course 1"
159161
[exercises."ex 1"]
162+
id = 4321
160163
checksum = "abcd1234"
161164
"#
162165
)
@@ -170,9 +173,11 @@ checksum = "abcd1234"
170173
course = "python course"
171174
172175
[exercises.ex1]
176+
id = 4321
173177
checksum = "abcd1234"
174178
175179
[exercises."ex 2"]
180+
id = 5432
176181
checksum = "bcde2345"
177182
"#;
178183

@@ -191,9 +196,11 @@ checksum = "bcde2345"
191196
course = "python"
192197
193198
[exercises.ex1]
199+
id = 4321
194200
checksum = "abcd1234"
195201
196202
[exercises."ex 2"]
203+
id = 5432
197204
checksum = "bcde2345"
198205
"#,
199206
);
@@ -204,9 +211,11 @@ checksum = "bcde2345"
204211
course = "java"
205212
206213
[exercises.ex3]
214+
id = 6543
207215
checksum = "cdef3456"
208216
209217
[exercises."ex 4"]
218+
id = 7654
210219
checksum = "defg4567"
211220
"#,
212221
);
@@ -218,16 +227,20 @@ checksum = "defg4567"
218227
assert_eq!(cc.course, "python");
219228
assert_eq!(cc.exercises.len(), 2);
220229
let ex = cc.exercises.remove("ex1").unwrap();
230+
assert_eq!(ex.id, 4321);
221231
assert_eq!(ex.checksum, "abcd1234");
222232
let ex = cc.exercises.remove("ex 2").unwrap();
233+
assert_eq!(ex.id, 5432);
223234
assert_eq!(ex.checksum, "bcde2345");
224235

225236
let mut cc = pc.courses.remove("course 2").unwrap();
226237
assert_eq!(cc.course, "java");
227238
assert_eq!(cc.exercises.len(), 2);
228239
let ex = cc.exercises.remove("ex3").unwrap();
240+
assert_eq!(ex.id, 6543);
229241
assert_eq!(ex.checksum, "cdef3456");
230242
let ex = cc.exercises.remove("ex 4").unwrap();
243+
assert_eq!(ex.id, 7654);
231244
assert_eq!(ex.checksum, "defg4567");
232245
}
233246
}

tmc-langs-cli/src/main.rs

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use self::config::{CourseConfig, Credentials, Exercise, TmcConfig};
1010
use self::error::{InvalidTokenError, SandboxTestError};
1111
use self::output::{
1212
CombinedCourseData, DownloadOrUpdateCourseExercise, DownloadOrUpdateCourseExercisesResult,
13-
ErrorData, Kind, LocalExercise, Output, OutputData, OutputResult, Status, Warnings,
13+
ErrorData, Kind, LocalExercise, Output, OutputData, OutputResult, Status, UpdatedExercise,
14+
Warnings,
1415
};
1516
use anyhow::{Context, Result};
1617
use clap::{ArgMatches, Error, ErrorKind};
@@ -765,6 +766,52 @@ fn run_core(
765766

766767
// proof of having printed the output
767768
let printed: PrintToken = match matches.subcommand() {
769+
("check-exercise-updates", Some(_)) => {
770+
let mut updated_exercises = vec![];
771+
772+
let projects_dir = TmcConfig::load(client_name)?.projects_dir;
773+
let config = ProjectsConfig::load(&projects_dir)?;
774+
let local_exercises = config
775+
.courses
776+
.into_iter()
777+
.map(|c| c.1.exercises)
778+
.flatten()
779+
.map(|e| e.1)
780+
.collect::<Vec<_>>();
781+
782+
if !local_exercises.is_empty() {
783+
let exercise_ids = local_exercises.iter().map(|e| e.id).collect::<Vec<_>>();
784+
let server_exercises = client
785+
.get_exercises_details(exercise_ids)?
786+
.into_iter()
787+
.map(|e| (e.id, e))
788+
.collect::<HashMap<_, _>>();
789+
for local_exercise in local_exercises {
790+
let server_exercise =
791+
server_exercises.get(&local_exercise.id).with_context(|| {
792+
format!(
793+
"Server did not return details for local exercise with id {}",
794+
local_exercise.id
795+
)
796+
})?;
797+
if server_exercise.checksum != local_exercise.checksum {
798+
// server has an updated exercise
799+
updated_exercises.push(UpdatedExercise {
800+
id: local_exercise.id,
801+
});
802+
}
803+
}
804+
}
805+
806+
let output = Output::OutputData(OutputData {
807+
status: Status::Finished,
808+
message: None,
809+
result: OutputResult::RetrievedData,
810+
percent_done: 1.0,
811+
data: Some(updated_exercises),
812+
});
813+
print_output(&output, pretty, &warnings)?
814+
}
768815
("download-model-solution", Some(matches)) => {
769816
let solution_download_url = matches.value_of("solution-download-url").unwrap();
770817
let solution_download_url = into_url(solution_download_url)?;
@@ -845,7 +892,7 @@ fn run_core(
845892
let projects_dir = TmcConfig::load(client_name)?.projects_dir;
846893
let mut projects_config = ProjectsConfig::load(&projects_dir)?;
847894

848-
let mut course_data = HashMap::<String, Vec<(String, String)>>::new();
895+
let mut course_data = HashMap::<String, Vec<(String, String, usize)>>::new();
849896
let mut exercises_and_paths = vec![];
850897
let mut downloaded = vec![];
851898
let mut skipped = vec![];
@@ -888,7 +935,11 @@ fn run_core(
888935

889936
let entry = course_data.entry(exercise_detail.course_name);
890937
let course_exercises = entry.or_default();
891-
course_exercises.push((exercise_detail.exercise_name, exercise_detail.checksum));
938+
course_exercises.push((
939+
exercise_detail.exercise_name,
940+
exercise_detail.checksum,
941+
exercise_detail.id,
942+
));
892943

893944
exercises_and_paths.push((exercise_detail.id, target));
894945
}
@@ -898,8 +949,8 @@ fn run_core(
898949

899950
for (course_name, exercise_names) in course_data {
900951
let mut exercises = BTreeMap::new();
901-
for (exercise_name, checksum) in exercise_names {
902-
exercises.insert(exercise_name, Exercise { checksum });
952+
for (exercise_name, checksum, id) in exercise_names {
953+
exercises.insert(exercise_name, Exercise { id, checksum });
903954
}
904955

905956
if let Some(course_config) = projects_config.courses.get_mut(&course_name) {
@@ -1523,6 +1574,9 @@ fn run_settings(
15231574

15241575
let course_slug = matches.value_of("course-slug").unwrap();
15251576

1577+
let exercise_id = matches.value_of("exercise-id").unwrap();
1578+
let exercise_id = into_usize(exercise_id)?;
1579+
15261580
let exercise_slug = matches.value_of("exercise-slug").unwrap();
15271581

15281582
let exercise_checksum = matches.value_of("exercise-checksum").unwrap();
@@ -1548,6 +1602,7 @@ fn run_settings(
15481602
course_config.exercises.insert(
15491603
exercise_slug.to_string(),
15501604
Exercise {
1605+
id: exercise_id,
15511606
checksum: exercise_checksum.to_string(),
15521607
},
15531608
);

tmc-langs-cli/src/output.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@ pub struct LocalExercise {
9999
pub exercise_path: PathBuf,
100100
}
101101

102+
#[derive(Debug, Serialize, JsonSchema)]
103+
#[serde(rename_all = "kebab-case")]
104+
pub struct UpdatedExercise {
105+
pub id: usize,
106+
}
107+
102108
#[derive(Debug, Serialize)]
103109
pub struct DownloadTarget {
104110
pub id: usize,

0 commit comments

Comments
 (0)