@@ -7,11 +7,12 @@ use std::fs::{self, File};
77use std:: io:: BufReader ;
88use std:: path:: Path ;
99use std:: process:: Command ;
10+ use std:: time:: Duration ;
1011use tmc_langs_framework:: {
1112 domain:: { ExerciseDesc , RunResult , RunStatus , TestDesc , TestResult } ,
1213 plugin:: LanguagePlugin ,
1314 policy:: StudentFilePolicy ,
14- Error ,
15+ CommandWithTimeout , Error ,
1516} ;
1617use walkdir:: WalkDir ;
1718
@@ -33,7 +34,7 @@ impl LanguagePlugin for Python3Plugin {
3334 }
3435
3536 fn scan_exercise ( & self , path : & Path , exercise_name : String ) -> Result < ExerciseDesc , Error > {
36- let run_result = run_tmc_command ( path, & [ "available_points" ] ) ;
37+ let run_result = run_tmc_command ( path, & [ "available_points" ] , None ) ;
3738
3839 if let Err ( error) = run_result {
3940 log:: error!( "Failed to scan exercise. {}" , error) ;
@@ -43,8 +44,12 @@ impl LanguagePlugin for Python3Plugin {
4344 Ok ( ExerciseDesc :: new ( exercise_name, test_descs) )
4445 }
4546
46- fn run_tests ( & self , path : & Path ) -> Result < RunResult , Error > {
47- let run_result = run_tmc_command ( path, & [ ] ) ;
47+ fn run_tests_with_timeout (
48+ & self ,
49+ path : & Path ,
50+ timeout : Option < Duration > ,
51+ ) -> Result < RunResult , Error > {
52+ let run_result = run_tmc_command ( path, & [ ] , timeout) ;
4853
4954 if let Err ( error) = run_result {
5055 log:: error!( "Failed to parse exercise description. {}" , error) ;
@@ -87,37 +92,45 @@ impl LanguagePlugin for Python3Plugin {
8792 }
8893}
8994
90- fn run_tmc_command ( path : & Path , extra_args : & [ & str ] ) -> Result < std:: process:: Output , PythonError > {
95+ fn run_tmc_command (
96+ path : & Path ,
97+ extra_args : & [ & str ] ,
98+ timeout : Option < Duration > ,
99+ ) -> Result < std:: process:: Output , PythonError > {
91100 let path = path
92101 . canonicalize ( )
93102 . map_err ( |e| PythonError :: Path ( path. to_path_buf ( ) , e) ) ?;
94103 log:: debug!( "running tmc command at {}" , path. display( ) ) ;
95104 let common_args = [ "-m" , "tmc" ] ;
96- let result = match & * LOCAL_PY {
97- LocalPy :: Unix => Command :: new ( "python3" )
105+
106+ let ( name, mut command) = match & * LOCAL_PY {
107+ LocalPy :: Unix => ( "python3" , Command :: new ( "python3" ) ) ,
108+ LocalPy :: Windows => ( "py" , Command :: new ( "py" ) ) ,
109+ //.map_err(|e| PythonError::Command("py", e))?,
110+ LocalPy :: WindowsConda { conda_path } => ( "conda" , Command :: new ( conda_path) ) ,
111+ } ;
112+ let command = match & * LOCAL_PY {
113+ LocalPy :: Unix => command
98114 . args ( & common_args)
99115 . args ( extra_args)
100- . current_dir ( path)
101- . output ( )
102- . map_err ( |e| PythonError :: Command ( "python3" , e) ) ?,
103- LocalPy :: Windows => Command :: new ( "py" )
116+ . current_dir ( path) ,
117+ LocalPy :: Windows => command
104118 . args ( & [ "-3" ] )
105119 . args ( & common_args)
106120 . args ( extra_args)
107- . current_dir ( path)
108- . output ( )
109- . map_err ( |e| PythonError :: Command ( "py" , e) ) ?,
110- LocalPy :: WindowsConda { conda_path } => Command :: new ( conda_path)
121+ . current_dir ( path) ,
122+ LocalPy :: WindowsConda { .. } => command
111123 . args ( & common_args)
112124 . args ( extra_args)
113- . current_dir ( path)
114- . output ( )
115- . map_err ( |e| PythonError :: Command ( conda_path, e) ) ?,
125+ . current_dir ( path) ,
116126 } ;
127+ let output = CommandWithTimeout ( command)
128+ . wait_with_timeout ( name, timeout)
129+ . unwrap ( ) ;
117130
118- log:: debug!( "stdout: {}" , String :: from_utf8_lossy( & result . stdout) ) ;
119- log:: debug!( "stderr: {}" , String :: from_utf8_lossy( & result . stderr) ) ;
120- Ok ( result )
131+ log:: debug!( "stdout: {}" , String :: from_utf8_lossy( & output . stdout) ) ;
132+ log:: debug!( "stderr: {}" , String :: from_utf8_lossy( & output . stderr) ) ;
133+ Ok ( output )
121134}
122135
123136fn parse_exercise_description ( path : & Path ) -> Result < Vec < TestDesc > , PythonError > {
0 commit comments