@@ -7,7 +7,7 @@ use crate::valgrind_log::ValgrindLog;
77use lazy_static:: lazy_static;
88use regex:: Regex ;
99use std:: collections:: HashMap ;
10- use std:: io:: { self , BufRead , BufReader } ;
10+ use std:: io:: { self , BufRead , BufReader , Read , Seek } ;
1111use std:: path:: { Path , PathBuf } ;
1212use std:: time:: Duration ;
1313use tmc_langs_framework:: {
@@ -19,6 +19,7 @@ use tmc_langs_framework::{
1919 nom:: { bytes, character, combinator, sequence, IResult } ,
2020 plugin:: LanguagePlugin ,
2121 subprocess:: PopenError ,
22+ zip:: ZipArchive ,
2223 TmcError , TmcProjectYml ,
2324} ;
2425
@@ -288,9 +289,40 @@ impl LanguagePlugin for MakePlugin {
288289 Ok ( run_result)
289290 }
290291
291- /// Checks if the directory has a Makefile in it.
292+ fn find_project_dir_in_zip < R : Read + Seek > (
293+ zip_archive : & mut ZipArchive < R > ,
294+ ) -> Result < PathBuf , TmcError > {
295+ for i in 0 ..zip_archive. len ( ) {
296+ // zips don't necessarily contain entries for intermediate directories,
297+ // so we need to check every path for src
298+ let file = zip_archive. by_index ( i) ?;
299+ let file_path = PathBuf :: from ( file. name ( ) ) ;
300+ drop ( file) ;
301+
302+ // todo: do in one pass somehow
303+ if file_path. components ( ) . any ( |c| c. as_os_str ( ) == "src" ) {
304+ let path: PathBuf = file_path
305+ . components ( )
306+ . take_while ( |c| c. as_os_str ( ) != "src" )
307+ . collect ( ) ;
308+
309+ if path. components ( ) . any ( |p| p. as_os_str ( ) == "__MACOSX" ) {
310+ continue ;
311+ }
312+ // found src not in __MACOSX, check for Makefile
313+ if let Some ( makefile_path) = path. join ( "Makefile" ) . to_str ( ) {
314+ if zip_archive. by_name ( makefile_path) . is_ok ( ) {
315+ return Ok ( path) ;
316+ }
317+ }
318+ }
319+ }
320+ Err ( TmcError :: NoProjectDirInZip )
321+ }
322+
323+ /// Checks if the directory has a src dir and a Makefile file in it.
292324 fn is_exercise_type_correct ( path : & Path ) -> bool {
293- path. join ( "Makefile" ) . is_file ( )
325+ path. join ( "src" ) . is_dir ( ) && path . join ( " Makefile") . is_file ( )
294326 }
295327
296328 // does not check for success
@@ -539,6 +571,7 @@ test [invalid] point6
539571 init ( ) ;
540572 let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
541573 dir_to ( & temp_dir, "Outer/Inner/make_project/src" ) ;
574+ file_to ( & temp_dir, "Outer/Inner/make_project/Makefile" , "" ) ;
542575
543576 let zip_contents = dir_to_zip ( & temp_dir) ;
544577 let mut zip = ZipArchive :: new ( std:: io:: Cursor :: new ( zip_contents) ) . unwrap ( ) ;
@@ -551,7 +584,8 @@ test [invalid] point6
551584 init ( ) ;
552585
553586 let temp_dir = tempfile:: tempdir ( ) . unwrap ( ) ;
554- dir_to ( & temp_dir, "Outer/Inner/make_project/srcb" ) ;
587+ dir_to ( & temp_dir, "Outer/Inner/make_project/src" ) ;
588+ file_to ( & temp_dir, "Outer/Inner/make_project/Makefil" , "" ) ;
555589
556590 let zip_contents = dir_to_zip ( & temp_dir) ;
557591 let mut zip = ZipArchive :: new ( std:: io:: Cursor :: new ( zip_contents) ) . unwrap ( ) ;
0 commit comments