@@ -10,8 +10,8 @@ pub use self::tmc_config::{ConfigValue, TmcConfig};
1010use crate :: output:: LocalExercise ;
1111
1212use anyhow:: { Context , Error } ;
13- use std:: env ;
14- use std:: path :: PathBuf ;
13+ use std:: path :: { Path , PathBuf } ;
14+ use std:: { collections :: BTreeMap , env } ;
1515
1616// base directory for a given plugin's settings files
1717fn get_tmc_dir ( client_name : & str ) -> Result < PathBuf , Error > {
@@ -43,3 +43,108 @@ pub fn list_local_course_exercises(
4343 }
4444 Ok ( local_exercises)
4545}
46+
47+ pub fn migrate (
48+ tmc_config : & TmcConfig ,
49+ course_slug : & str ,
50+ exercise_slug : & str ,
51+ exercise_id : usize ,
52+ exercise_checksum : & str ,
53+ exercise_path : & Path ,
54+ ) -> anyhow:: Result < ( ) > {
55+ let mut projects_config = ProjectsConfig :: load ( & tmc_config. projects_dir ) ?;
56+ let course_config = projects_config
57+ . courses
58+ . entry ( course_slug. to_string ( ) )
59+ . or_insert ( CourseConfig {
60+ course : course_slug. to_string ( ) ,
61+ exercises : BTreeMap :: new ( ) ,
62+ } ) ;
63+
64+ let target_dir = ProjectsConfig :: get_exercise_download_target (
65+ & tmc_config. projects_dir ,
66+ course_slug,
67+ exercise_slug,
68+ ) ;
69+ if target_dir. exists ( ) {
70+ anyhow:: bail!(
71+ "Tried to migrate exercise to {}; however, something already exists at that path." ,
72+ target_dir. display( )
73+ ) ;
74+ }
75+
76+ course_config. exercises . insert (
77+ exercise_slug. to_string ( ) ,
78+ Exercise {
79+ id : exercise_id,
80+ checksum : exercise_checksum. to_string ( ) ,
81+ } ,
82+ ) ;
83+
84+ super :: move_dir ( exercise_path, & target_dir) ?;
85+ course_config. save_to_projects_dir ( & tmc_config. projects_dir ) ?;
86+ Ok ( ( ) )
87+ }
88+
89+ #[ cfg( test) ]
90+ mod test {
91+ use toml:: value:: Table ;
92+
93+ use super :: * ;
94+
95+ fn init ( ) {
96+ use log:: * ;
97+ use simple_logger:: * ;
98+ let _ = SimpleLogger :: new ( ) . with_level ( LevelFilter :: Debug ) . init ( ) ;
99+ }
100+
101+ fn file_to (
102+ target_dir : impl AsRef < std:: path:: Path > ,
103+ target_relative : impl AsRef < std:: path:: Path > ,
104+ contents : impl AsRef < [ u8 ] > ,
105+ ) -> PathBuf {
106+ let target = target_dir. as_ref ( ) . join ( target_relative) ;
107+ if let Some ( parent) = target. parent ( ) {
108+ std:: fs:: create_dir_all ( parent) . unwrap ( ) ;
109+ }
110+ std:: fs:: write ( & target, contents. as_ref ( ) ) . unwrap ( ) ;
111+ target
112+ }
113+
114+ #[ test]
115+ fn migrates ( ) {
116+ init ( ) ;
117+
118+ let projects_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
119+ let exercise_path = tempfile:: tempdir ( ) . unwrap ( ) ;
120+
121+ let tmc_config = TmcConfig {
122+ projects_dir : projects_dir. path ( ) . to_path_buf ( ) ,
123+ table : Table :: new ( ) ,
124+ } ;
125+
126+ file_to ( & exercise_path, "some_file" , "" ) ;
127+
128+ assert ! ( !projects_dir
129+ . path( )
130+ . join( "course/exercise/some_file" )
131+ . exists( ) ) ;
132+
133+ migrate (
134+ & tmc_config,
135+ "course" ,
136+ "exercise" ,
137+ 0 ,
138+ "checksum" ,
139+ exercise_path. path ( ) ,
140+ )
141+ . unwrap ( ) ;
142+
143+ assert ! ( projects_dir
144+ . path( )
145+ . join( "course/exercise/some_file" )
146+ . exists( ) ) ;
147+
148+ assert ! ( !exercise_path. path( ) . exists( ) ) ;
149+ }
150+ }
0 commit comments