@@ -7,7 +7,8 @@ mod output;
77
88use anyhow:: { Context , Result } ;
99use clap:: { ArgMatches , Error , ErrorKind } ;
10- use config:: { Credentials , TmcConfig } ;
10+ use config:: ProjectsConfig ;
11+ use config:: { CourseConfig , Credentials , Exercise , TmcConfig } ;
1112use error:: { InvalidTokenError , SandboxTestError } ;
1213use output:: {
1314 CombinedCourseData , ErrorData , Kind , Output , OutputData , OutputResult , Status , Warnings ,
@@ -789,6 +790,84 @@ fn run_core(
789790 } ) ;
790791 print_output ( & output, pretty, & warnings) ?
791792 }
793+ ( "download-or-update-course-exercises" , Some ( matches) ) => {
794+ let exercise_ids = matches. values_of ( "exercise-id" ) . unwrap ( ) ;
795+
796+ // collect exercise into (id, path) pairs
797+ let exercises = exercise_ids
798+ . into_iter ( )
799+ . map ( into_usize)
800+ . collect :: < Result < _ > > ( ) ?;
801+ let exercises_details = core. get_exercises_details ( exercises) ?;
802+
803+ let tmc_config = TmcConfig :: load ( client_name) ?;
804+
805+ let projects_dir = tmc_config. projects_dir ;
806+ let mut projects_config = ProjectsConfig :: load ( & projects_dir) ?;
807+
808+ let mut course_data = HashMap :: < String , Vec < ( String , String ) > > :: new ( ) ;
809+ let mut exercises_and_paths = vec ! [ ] ;
810+ for exercise_detail in exercises_details {
811+ // get course and exercise name from server
812+ let ex_details = core. get_exercise_details ( exercise_detail. id ) ?;
813+ // check if the checksum is different from what's already on disk
814+ if let Some ( course_config) = projects_config. courses . get ( & ex_details. course_name ) {
815+ if let Some ( exercise) = course_config. exercises . get ( & ex_details. exercise_name ) {
816+ if exercise_detail. checksum == exercise. checksum {
817+ // skip this exercise
818+ log:: info!(
819+ "Skipping exercise {} ({} in {}) due to identical checksum" ,
820+ exercise_detail. id,
821+ ex_details. course_name,
822+ ex_details. exercise_name
823+ ) ;
824+ continue ;
825+ }
826+ }
827+ }
828+
829+ let target = ProjectsConfig :: get_exercise_download_target (
830+ & projects_dir,
831+ & ex_details. course_name ,
832+ & ex_details. exercise_name ,
833+ ) ;
834+
835+ let entry = course_data. entry ( ex_details. course_name ) ;
836+ let course_exercises = entry. or_default ( ) ;
837+ course_exercises. push ( ( ex_details. exercise_name , exercise_detail. checksum ) ) ;
838+
839+ exercises_and_paths. push ( ( exercise_detail. id , target) ) ;
840+ }
841+ core. download_or_update_exercises ( exercises_and_paths)
842+ . context ( "Failed to download exercises" ) ?;
843+
844+ for ( course_name, exercise_names) in course_data {
845+ let mut exercises = HashMap :: new ( ) ;
846+ for ( exercise_name, checksum) in exercise_names {
847+ exercises. insert ( exercise_name, Exercise { checksum } ) ;
848+ }
849+
850+ if let Some ( course_config) = projects_config. courses . get_mut ( & course_name) {
851+ course_config. exercises . extend ( exercises) ;
852+ course_config. save_to_projects_dir ( & projects_dir) ?;
853+ } else {
854+ let course_config = CourseConfig {
855+ course : course_name,
856+ exercises,
857+ } ;
858+ course_config. save_to_projects_dir ( & projects_dir) ?;
859+ } ;
860+ }
861+
862+ let output = Output :: OutputData :: < ( ) > ( OutputData {
863+ status : Status :: Finished ,
864+ message : None ,
865+ result : OutputResult :: RetrievedData ,
866+ percent_done : 1.0 ,
867+ data : None ,
868+ } ) ;
869+ print_output ( & output, pretty, & warnings) ?
870+ }
792871 ( "download-or-update-exercises" , Some ( matches) ) => {
793872 let mut exercise_args = matches. values_of ( "exercise" ) . unwrap ( ) ;
794873
0 commit comments