@@ -1514,6 +1514,102 @@ fn run_core(
15141514 print_output ( & output, pretty, & warnings) ?
15151515 }
15161516 }
1517+ ( "update-exercises" , Some ( _) ) => {
1518+ let mut exercises_to_update = vec ! [ ] ;
1519+ let mut downloaded_exercises = vec ! [ ] ;
1520+ let mut skipped_exercises = vec ! [ ] ;
1521+ let mut course_data = HashMap :: < String , Vec < ( String , String , usize ) > > :: new ( ) ;
1522+
1523+ let projects_dir = TmcConfig :: load ( client_name) ?. projects_dir ;
1524+ let mut projects_config = ProjectsConfig :: load ( & projects_dir) ?;
1525+ let local_exercises = projects_config
1526+ . courses
1527+ . iter ( )
1528+ . map ( |c| & c. 1 . exercises )
1529+ . flatten ( )
1530+ . map ( |e| e. 1 )
1531+ . collect :: < Vec < _ > > ( ) ;
1532+ let exercise_ids = local_exercises. iter ( ) . map ( |e| e. id ) . collect :: < Vec < _ > > ( ) ;
1533+
1534+ // request would error with 0 exercise ids
1535+ if !exercise_ids. is_empty ( ) {
1536+ let server_exercises = client
1537+ . get_exercises_details ( exercise_ids) ?
1538+ . into_iter ( )
1539+ . map ( |e| ( e. id , e) )
1540+ . collect :: < HashMap < _ , _ > > ( ) ;
1541+ for local_exercise in local_exercises {
1542+ let server_exercise =
1543+ server_exercises. get ( & local_exercise. id ) . with_context ( || {
1544+ format ! (
1545+ "Server did not return details for local exercise with id {}" ,
1546+ local_exercise. id
1547+ )
1548+ } ) ?;
1549+ if server_exercise. checksum != local_exercise. checksum {
1550+ // server has an updated exercise
1551+ let target = ProjectsConfig :: get_exercise_download_target (
1552+ & projects_dir,
1553+ & server_exercise. course_name ,
1554+ & server_exercise. exercise_name ,
1555+ ) ;
1556+ let exercise_list = course_data
1557+ . entry ( server_exercise. course_name . clone ( ) )
1558+ . or_default ( ) ;
1559+ exercise_list. push ( (
1560+ server_exercise. exercise_name . clone ( ) ,
1561+ server_exercise. checksum . clone ( ) ,
1562+ server_exercise. id ,
1563+ ) ) ;
1564+ exercises_to_update. push ( ( local_exercise. id , target) ) ;
1565+ downloaded_exercises. push ( DownloadOrUpdateCourseExercise {
1566+ course_slug : server_exercise. course_name . clone ( ) ,
1567+ exercise_slug : server_exercise. exercise_name . clone ( ) ,
1568+ } ) ;
1569+ } else {
1570+ skipped_exercises. push ( DownloadOrUpdateCourseExercise {
1571+ course_slug : server_exercise. course_name . clone ( ) ,
1572+ exercise_slug : server_exercise. exercise_name . clone ( ) ,
1573+ } ) ;
1574+ }
1575+ }
1576+
1577+ if !exercises_to_update. is_empty ( ) {
1578+ client. download_or_update_exercises ( exercises_to_update) ?;
1579+
1580+ for ( course_name, exercise_names) in course_data {
1581+ let mut exercises = BTreeMap :: new ( ) ;
1582+ for ( exercise_name, checksum, id) in exercise_names {
1583+ exercises. insert ( exercise_name, Exercise { id, checksum } ) ;
1584+ }
1585+
1586+ if let Some ( course_config) = projects_config. courses . get_mut ( & course_name) {
1587+ course_config. exercises . extend ( exercises) ;
1588+ course_config. save_to_projects_dir ( & projects_dir) ?;
1589+ } else {
1590+ let course_config = CourseConfig {
1591+ course : course_name,
1592+ exercises,
1593+ } ;
1594+ course_config. save_to_projects_dir ( & projects_dir) ?;
1595+ } ;
1596+ }
1597+ }
1598+ }
1599+
1600+ let data = DownloadOrUpdateCourseExercisesResult {
1601+ downloaded : downloaded_exercises,
1602+ skipped : skipped_exercises,
1603+ } ;
1604+ let output = Output :: OutputData ( OutputData {
1605+ status : Status :: Finished ,
1606+ message : None ,
1607+ result : OutputResult :: RetrievedData ,
1608+ percent_done : 1.0 ,
1609+ data : Some ( data) ,
1610+ } ) ;
1611+ print_output ( & output, pretty, & warnings) ?
1612+ }
15171613 ( "wait-for-submission" , Some ( matches) ) => {
15181614 let submission_url = matches. value_of ( "submission-url" ) . unwrap ( ) ;
15191615
0 commit comments