@@ -7,6 +7,7 @@ use std::fs;
77use std:: path:: { Path , PathBuf } ;
88use std:: process:: { Command , Stdio } ;
99use std:: time:: Instant ;
10+ use tempfile;
1011
1112#[ derive( Args ) ]
1213pub struct EvalArgs {
@@ -195,6 +196,53 @@ impl EvalArgs {
195196
196197 /// 评测rustlings或其他项目
197198 fn eval_rustlings ( & self , course_path : & Path ) -> Result < ( Vec < ExerciseResult > , usize , usize , usize ) > {
199+ println ! ( "{}" , "评测 rustlings 项目..." . blue( ) . bold( ) ) ;
200+
201+ // 检查是否存在 rustlings 命令
202+ let rustlings_check = Command :: new ( "rustlings" )
203+ . arg ( "--help" )
204+ . stdout ( Stdio :: piped ( ) )
205+ . stderr ( Stdio :: piped ( ) )
206+ . output ( ) ;
207+
208+ // 无论 rustlings 命令是否存在,都使用 rustc 编译和运行测试来评测
209+ println ! ( "{}" , "使用 rustc 编译和运行测试来评测..." . blue( ) . bold( ) ) ;
210+
211+ // 处理 Rustlings 或其他非 learning-lm-rs 项目
212+ let exercise_files = find_exercise_files ( course_path, & None ) ?;
213+ let total_exercations = exercise_files. len ( ) ;
214+ println ! ( "{} {} {}" , "找到" . blue( ) . bold( ) , total_exercations, "个练习文件" . blue( ) . bold( ) ) ;
215+
216+ if total_exercations == 0 {
217+ println ! ( "{}" , "未找到练习文件,评测结束。" . yellow( ) ) ;
218+ return Ok ( ( Vec :: new ( ) , 0 , 0 , 0 ) ) ;
219+ }
220+
221+ let bar = ProgressBar :: new ( total_exercations as u64 ) ;
222+ bar. set_style (
223+ ProgressStyle :: with_template ( "{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})" )
224+ . unwrap ( )
225+ . progress_chars ( "##-" ) ,
226+ ) ;
227+
228+ let mut exercise_results = Vec :: new ( ) ;
229+ let mut total_succeeds = 0 ;
230+ let mut total_failures = 0 ;
231+
232+ for exercise_path in exercise_files. iter ( ) {
233+ bar. inc ( 1 ) ;
234+ let ( name, result, _time) = grade_exercise ( exercise_path, self . verbose ) ?;
235+ if result {
236+ total_succeeds += 1 ;
237+ } else {
238+ total_failures += 1 ;
239+ }
240+ exercise_results. push ( ExerciseResult { name, result } ) ;
241+ }
242+ bar. finish_with_message ( "评测完成!" ) ;
243+
244+ return Ok ( ( exercise_results, total_succeeds, total_failures, total_exercations) ) ;
245+
198246 // 处理 Rustlings 或其他非 learning-lm-rs 项目
199247 let exercise_files = find_exercise_files ( & course_path, & None ) ?;
200248 let total_exercations = exercise_files. len ( ) ;
@@ -466,6 +514,63 @@ fn grade_exercise(exercise_path: &Path, verbose: bool) -> Result<(String, bool,
466514
467515 println ! ( "{} {}" , "评测练习:" . blue( ) . bold( ) , exercise_name) ;
468516
517+ // 检查是否是 clippy 练习
518+ let is_clippy_exercise = exercise_path. to_string_lossy ( ) . contains ( "clippy" ) ;
519+
520+ // 如果是 clippy 练习,使用 cargo clippy 命令检查
521+ if is_clippy_exercise {
522+ // 创建一个临时目录来存放 Cargo.toml 和源文件
523+ let temp_dir = tempfile:: tempdir ( ) . context ( "创建临时目录失败" ) ?;
524+ let temp_dir_path = temp_dir. path ( ) ;
525+
526+ // 创建 Cargo.toml 文件
527+ let cargo_toml_content = r#"[package]
528+ name = "clippy_check"
529+ version = "0.1.0"
530+ edition = "2021"
531+
532+ [[bin]]
533+ name = "clippy_check"
534+ path = "src/main.rs"
535+ "# ;
536+ let cargo_toml_path = temp_dir_path. join ( "Cargo.toml" ) ;
537+ fs:: write ( & cargo_toml_path, cargo_toml_content) . context ( "写入 Cargo.toml 失败" ) ?;
538+
539+ // 创建 src 目录
540+ let src_dir = temp_dir_path. join ( "src" ) ;
541+ fs:: create_dir ( & src_dir) . context ( "创建 src 目录失败" ) ?;
542+
543+ // 复制练习文件到 src/main.rs
544+ let exercise_content = fs:: read_to_string ( exercise_path) . context ( "读取练习文件失败" ) ?;
545+ let main_rs_path = src_dir. join ( "main.rs" ) ;
546+ fs:: write ( & main_rs_path, exercise_content) . context ( "写入 main.rs 失败" ) ?;
547+
548+ // 运行 cargo clippy
549+ let clippy_output = Command :: new ( "cargo" )
550+ . arg ( "clippy" )
551+ . arg ( "--manifest-path" )
552+ . arg ( & cargo_toml_path)
553+ . arg ( "--" )
554+ . arg ( "-D" )
555+ . arg ( "warnings" )
556+ . current_dir ( temp_dir_path)
557+ . stdout ( Stdio :: piped ( ) )
558+ . stderr ( Stdio :: piped ( ) )
559+ . output ( )
560+ . context ( format ! ( "运行 cargo clippy 检查 {} 失败" , exercise_name) ) ?;
561+
562+ let clippy_success = clippy_output. status . success ( ) ;
563+
564+ if !clippy_success {
565+ if verbose {
566+ println ! ( "{}" , String :: from_utf8_lossy( & clippy_output. stdout) ) ;
567+ println ! ( "{}" , String :: from_utf8_lossy( & clippy_output. stderr) ) ;
568+ }
569+ println ! ( "{} {}" , "✗" . red( ) . bold( ) , exercise_name) ;
570+ return Ok ( ( exercise_name, false , start. elapsed ( ) . as_secs ( ) ) ) ;
571+ }
572+ }
573+
469574 // 对于rustlings练习,直接使用rustc编译和运行测试
470575 let test_output = Command :: new ( "rustc" )
471576 . arg ( exercise_path)
0 commit comments