@@ -27,12 +27,14 @@ pub struct RefreshData {
2727
2828/// An exercise from a finished course refresh.
2929#[ derive( Debug , Serialize , Deserialize ) ]
30+ #[ serde( rename_all = "kebab-case" ) ]
3031pub struct RefreshExercise {
3132 name : String ,
3233 checksum : String ,
3334 points : Vec < String > ,
3435 #[ serde( skip) ]
3536 path : PathBuf ,
37+ tmcproject_yml : Option < TmcProjectYml > ,
3638}
3739
3840/// Used by tmc-server. Refreshes the course.
@@ -86,15 +88,15 @@ pub fn refresh_course(
8688 . map ( |ed| ed. strip_prefix ( & new_clone_path) . unwrap ( ) . to_path_buf ( ) ) // safe
8789 . collect :: < Vec < _ > > ( ) ;
8890
89- // merge the root config with each exercise's, if any
90- if let Ok ( root_tmcproject ) = TmcProjectYml :: from ( & course_cache_path) {
91- merge_tmcproject_configs ( root_tmcproject , & exercise_dirs ) ? ;
92- }
91+ // collect .tmcproject.ymls and merge the root config with each exercise's, if any
92+ let root_tmcproject_yml = TmcProjectYml :: load ( & course_cache_path) ? ;
93+ let exercise_dirs_and_tmcprojects =
94+ get_and_merge_tmcproject_configs ( root_tmcproject_yml , & new_clone_path , exercise_dirs ) ? ;
9395 progress_stage ( "Merged .tmcproject.yml files in exercise directories to the root file, if any" ) ;
9496
9597 // make_solutions
9698 log:: info!( "preparing solutions to {}" , new_solution_path. display( ) ) ;
97- for exercise in & exercise_dirs {
99+ for ( exercise, _ ) in & exercise_dirs_and_tmcprojects {
98100 super :: prepare_solution (
99101 & new_clone_path. join ( & exercise) ,
100102 & new_solution_path. join ( & exercise) ,
@@ -104,15 +106,19 @@ pub fn refresh_course(
104106
105107 // make_stubs
106108 log:: info!( "preparing stubs to {}" , new_stub_path. display( ) ) ;
107- for exercise in & exercise_dirs {
109+ for ( exercise, _ ) in & exercise_dirs_and_tmcprojects {
108110 super :: prepare_stub (
109111 & new_clone_path. join ( & exercise) ,
110112 & new_stub_path. join ( & exercise) ,
111113 ) ?;
112114 }
113115 progress_stage ( "Prepared stubs" ) ;
114116
115- let exercises = get_exercises ( exercise_dirs, & new_clone_path, & new_stub_path) ?;
117+ let exercises = get_exercises (
118+ exercise_dirs_and_tmcprojects,
119+ & new_clone_path,
120+ & new_stub_path,
121+ ) ?;
116122 progress_stage ( "Located exercises" ) ;
117123
118124 // make_zips_of_solutions
@@ -221,17 +227,30 @@ fn check_directory_names(path: &Path) -> Result<(), LangsError> {
221227 Ok ( ( ) )
222228}
223229
224- fn merge_tmcproject_configs (
225- root_tmcproject : TmcProjectYml ,
226- exercise_dirs : & [ PathBuf ] ,
227- ) -> Result < ( ) , LangsError > {
230+ fn get_and_merge_tmcproject_configs (
231+ root_tmcproject : Option < TmcProjectYml > ,
232+ clone_path : & Path ,
233+ exercise_dirs : Vec < PathBuf > ,
234+ ) -> Result < Vec < ( PathBuf , Option < TmcProjectYml > ) > , LangsError > {
235+ let mut res = vec ! [ ] ;
228236 for exercise_dir in exercise_dirs {
229- if let Ok ( mut exercise_tmcproject) = TmcProjectYml :: from ( exercise_dir) {
230- exercise_tmcproject. merge ( root_tmcproject. clone ( ) ) ;
231- exercise_tmcproject. save_to_dir ( exercise_dir) ?;
237+ let target_dir = clone_path. join ( & exercise_dir) ;
238+ let exercise_tmcproject = TmcProjectYml :: load ( & target_dir) ?;
239+ match ( & root_tmcproject, exercise_tmcproject) {
240+ ( Some ( root) , Some ( mut exercise) ) => {
241+ exercise. merge ( root. clone ( ) ) ;
242+ exercise. save_to_dir ( & target_dir) ?;
243+ res. push ( ( exercise_dir, Some ( exercise) ) ) ;
244+ }
245+ ( Some ( root) , None ) => {
246+ root. save_to_dir ( & target_dir) ?;
247+ res. push ( ( exercise_dir, Some ( root. clone ( ) ) ) ) ;
248+ }
249+ ( None , Some ( exercise) ) => res. push ( ( exercise_dir, Some ( exercise) ) ) ,
250+ ( None , None ) => res. push ( ( exercise_dir, None ) ) ,
232251 }
233252 }
234- Ok ( ( ) )
253+ Ok ( res )
235254}
236255
237256/// Checks for a course_clone_path/course_options.yml
@@ -257,15 +276,15 @@ fn get_course_options(course_clone_path: &Path, course_name: &str) -> Result<Map
257276/// Finds exercise directories, and converts the directories to "exercise names" by swapping the separators for dashes.
258277/// Also calculates checksums and fetches points for all
259278fn get_exercises (
260- exercise_dirs : Vec < PathBuf > ,
279+ exercise_dirs_and_tmcprojects : Vec < ( PathBuf , Option < TmcProjectYml > ) > ,
261280 course_clone_path : & Path ,
262281 course_stub_path : & Path ,
263282) -> Result < Vec < RefreshExercise > , LangsError > {
264283 log:: info!( "finding exercise checksums and points" ) ;
265284
266- let exercises = exercise_dirs
285+ let exercises = exercise_dirs_and_tmcprojects
267286 . into_iter ( )
268- . map ( |exercise_dir| {
287+ . map ( |( exercise_dir, tmcproject_yml ) | {
269288 log:: debug!(
270289 "processing points and checksum for {}" ,
271290 exercise_dir. display( )
@@ -280,6 +299,7 @@ fn get_exercises(
280299 points,
281300 checksum,
282301 path : exercise_dir,
302+ tmcproject_yml,
283303 } )
284304 } )
285305 . collect :: < Result < _ , LangsError > > ( ) ?;
@@ -475,9 +495,12 @@ mod test {
475495 . unwrap ( )
476496 . into_iter ( )
477497 . map ( |ed| {
478- ed. strip_prefix ( & temp. path ( ) . join ( "course" ) )
479- . unwrap ( )
480- . to_path_buf ( )
498+ (
499+ ed. strip_prefix ( & temp. path ( ) . join ( "course" ) )
500+ . unwrap ( )
501+ . to_path_buf ( ) ,
502+ None ,
503+ )
481504 } )
482505 . collect ( ) ;
483506 let exercises = get_exercises (
@@ -516,9 +539,12 @@ mod test {
516539 . unwrap ( )
517540 . into_iter ( )
518541 . map ( |ed| {
519- ed. strip_prefix ( & temp. path ( ) . join ( "clone" ) )
520- . unwrap ( )
521- . to_path_buf ( )
542+ (
543+ ed. strip_prefix ( & temp. path ( ) . join ( "clone" ) )
544+ . unwrap ( )
545+ . to_path_buf ( ) ,
546+ None ,
547+ )
522548 } )
523549 . collect ( ) ;
524550 let exercises = get_exercises (
@@ -604,10 +630,12 @@ mod test {
604630 init ( ) ;
605631
606632 let temp = tempfile:: tempdir ( ) . unwrap ( ) ;
607- let exap = temp. path ( ) . join ( "exa" ) ;
608- file_util:: create_dir ( & exap) . unwrap ( ) ;
609- let exbp = temp. path ( ) . join ( "exb" ) ;
610- file_util:: create_dir ( & exbp) . unwrap ( ) ;
633+ let exap = PathBuf :: from ( "exa" ) ;
634+ let exap_path = temp. path ( ) . join ( & exap) ;
635+ file_util:: create_dir ( & exap_path) . unwrap ( ) ;
636+ let exbp = PathBuf :: from ( "exb" ) ;
637+ let exbp_path = temp. path ( ) . join ( & exbp) ;
638+ file_util:: create_dir ( & exbp_path) . unwrap ( ) ;
611639
612640 let root = TmcProjectYml {
613641 tests_timeout_ms : Some ( 1234 ) ,
@@ -618,21 +646,21 @@ mod test {
618646 tests_timeout_ms : Some ( 2345 ) ,
619647 ..Default :: default ( )
620648 } ;
621- tpya. save_to_dir ( & exap ) . unwrap ( ) ;
649+ tpya. save_to_dir ( & exap_path ) . unwrap ( ) ;
622650 let tpyb = TmcProjectYml {
623651 fail_on_valgrind_error : Some ( false ) ,
624652 ..Default :: default ( )
625653 } ;
626- tpyb. save_to_dir ( & exbp ) . unwrap ( ) ;
627- let exercise_dirs = & [ exap. clone ( ) , exbp. clone ( ) ] ;
654+ tpyb. save_to_dir ( & exbp_path ) . unwrap ( ) ;
655+ let exercise_dirs = vec ! [ exap. clone( ) , exbp. clone( ) ] ;
628656
629- merge_tmcproject_configs ( root, exercise_dirs) . unwrap ( ) ;
657+ get_and_merge_tmcproject_configs ( Some ( root) , temp . path ( ) , exercise_dirs) . unwrap ( ) ;
630658
631- let tpya = TmcProjectYml :: from ( & exap ) . unwrap ( ) ;
659+ let tpya = TmcProjectYml :: load ( & exap_path ) . unwrap ( ) . unwrap ( ) ;
632660 assert_eq ! ( tpya. tests_timeout_ms, Some ( 2345 ) ) ;
633661 assert_eq ! ( tpya. fail_on_valgrind_error, Some ( true ) ) ;
634662
635- let tpyb = TmcProjectYml :: from ( & exbp ) . unwrap ( ) ;
663+ let tpyb = TmcProjectYml :: load ( & exbp_path ) . unwrap ( ) . unwrap ( ) ;
636664 assert_eq ! ( tpyb. tests_timeout_ms, Some ( 1234 ) ) ;
637665 assert_eq ! ( tpyb. fail_on_valgrind_error, Some ( false ) ) ;
638666 }
0 commit comments