diff --git a/Cargo.lock b/Cargo.lock index 2e17313..a8b59cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,6 +67,12 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + [[package]] name = "bumpalo" version = "3.17.0" @@ -162,6 +168,34 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" name = "environment" version = "0.0.0" +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi", +] + [[package]] name = "heck" version = "0.5.0" @@ -215,6 +249,12 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +[[package]] +name = "linux-raw-sys" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" + [[package]] name = "log" version = "0.4.27" @@ -263,6 +303,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "regex" version = "1.11.1" @@ -292,6 +338,19 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rustix" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "ryu" version = "1.0.20" @@ -356,6 +415,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +dependencies = [ + "fastrand", + "getrandom", + "once_cell", + "rustix", + "windows-sys", +] + [[package]] name = "unicode-ident" version = "1.0.18" @@ -384,6 +456,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.14.2+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -533,6 +614,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "xtask" version = "0.1.0" @@ -546,5 +636,6 @@ dependencies = [ "regex", "serde", "serde_json", + "tempfile", "walkdir", ] diff --git a/eval_result.json b/eval_result.json index 85ac448..38b827d 100644 --- a/eval_result.json +++ b/eval_result.json @@ -1,146 +1,34 @@ { "exercises": [ { - "name": "exercise00", - "result": true - }, - { - "name": "exercise01", - "result": false - }, - { - "name": "exercise02", - "result": false - }, - { - "name": "exercise03", - "result": false - }, - { - "name": "exercise04", - "result": false - }, - { - "name": "exercise05", - "result": false - }, - { - "name": "exercise06", - "result": false - }, - { - "name": "exercise07", - "result": false - }, - { - "name": "exercise08", - "result": false - }, - { - "name": "exercise09", - "result": false - }, - { - "name": "exercise10", - "result": false - }, - { - "name": "exercise11", - "result": false - }, - { - "name": "exercise12", - "result": false - }, - { - "name": "exercise13", - "result": false - }, - { - "name": "exercise14", - "result": false - }, - { - "name": "exercise15", + "name": "f16_overflow.rs", "result": false }, { - "name": "exercise16", + "name": "f16_basics.rs", "result": false }, { - "name": "exercise17", - "result": false - }, - { - "name": "exercise18", - "result": false - }, - { - "name": "exercise19", - "result": false - }, - { - "name": "exercise20", - "result": false - }, - { - "name": "exercise21", - "result": false - }, - { - "name": "exercise22", - "result": false - }, - { - "name": "exercise23", - "result": false - }, - { - "name": "exercise24", - "result": false - }, - { - "name": "exercise25", - "result": false - }, - { - "name": "exercise26", - "result": false - }, - { - "name": "exercise27", - "result": false - }, - { - "name": "exercise28", - "result": false - }, - { - "name": "exercise29", - "result": false - }, - { - "name": "exercise30", - "result": false + "name": "attention_score.rs", + "result": true }, { - "name": "exercise31", - "result": false + "name": "gradient_compute.rs", + "result": true }, { - "name": "exercise32", + "name": "layer_norm.rs", "result": false }, { - "name": "exercise33", - "result": false + "name": "multi_head_attention.rs", + "result": true } ], "statistics": { - "total_exercations": 34, - "total_succeeds": 1, - "total_failures": 33, - "total_time": 61 + "total_exercations": 6, + "total_succeeds": 3, + "total_failures": 3, + "total_time": 2 } } \ No newline at end of file diff --git a/exercises/Rustlings-for-LLM b/exercises/Rustlings-for-LLM new file mode 160000 index 0000000..28ee516 --- /dev/null +++ b/exercises/Rustlings-for-LLM @@ -0,0 +1 @@ +Subproject commit 28ee516bc8741e2902c4baad66a178b84611c4c4 diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 11bb994..a1f1e48 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -14,3 +14,4 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" walkdir = "2.3" regex = "1.10" +tempfile = "3.8" diff --git a/xtask/src/eval.rs b/xtask/src/eval.rs index 707aa43..79a4263 100644 --- a/xtask/src/eval.rs +++ b/xtask/src/eval.rs @@ -7,6 +7,7 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::time::Instant; +use tempfile; #[derive(Args)] pub struct EvalArgs { @@ -195,6 +196,53 @@ impl EvalArgs { /// 评测rustlings或其他项目 fn eval_rustlings(&self, course_path: &Path) -> Result<(Vec, usize, usize, usize)> { + println!("{}", "评测 rustlings 项目...".blue().bold()); + + // 检查是否存在 rustlings 命令 + let rustlings_check = Command::new("rustlings") + .arg("--help") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .output(); + + // 无论 rustlings 命令是否存在,都使用 rustc 编译和运行测试来评测 + println!("{}", "使用 rustc 编译和运行测试来评测...".blue().bold()); + + // 处理 Rustlings 或其他非 learning-lm-rs 项目 + let exercise_files = find_exercise_files(course_path, &None)?; + let total_exercations = exercise_files.len(); + println!("{} {} {}", "找到".blue().bold(), total_exercations, "个练习文件".blue().bold()); + + if total_exercations == 0 { + println!("{}", "未找到练习文件,评测结束。".yellow()); + return Ok((Vec::new(), 0, 0, 0)); + } + + let bar = ProgressBar::new(total_exercations as u64); + bar.set_style( + ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} ({eta})") + .unwrap() + .progress_chars("##-"), + ); + + let mut exercise_results = Vec::new(); + let mut total_succeeds = 0; + let mut total_failures = 0; + + for exercise_path in exercise_files.iter() { + bar.inc(1); + let (name, result, _time) = grade_exercise(exercise_path, self.verbose)?; + if result { + total_succeeds += 1; + } else { + total_failures += 1; + } + exercise_results.push(ExerciseResult { name, result }); + } + bar.finish_with_message("评测完成!"); + + return Ok((exercise_results, total_succeeds, total_failures, total_exercations)); + // 处理 Rustlings 或其他非 learning-lm-rs 项目 let exercise_files = find_exercise_files(&course_path, &None)?; let total_exercations = exercise_files.len(); @@ -466,6 +514,63 @@ fn grade_exercise(exercise_path: &Path, verbose: bool) -> Result<(String, bool, println!("{} {}", "评测练习:".blue().bold(), exercise_name); + // 检查是否是 clippy 练习 + let is_clippy_exercise = exercise_path.to_string_lossy().contains("clippy"); + + // 如果是 clippy 练习,使用 cargo clippy 命令检查 + if is_clippy_exercise { + // 创建一个临时目录来存放 Cargo.toml 和源文件 + let temp_dir = tempfile::tempdir().context("创建临时目录失败")?; + let temp_dir_path = temp_dir.path(); + + // 创建 Cargo.toml 文件 + let cargo_toml_content = r#"[package] +name = "clippy_check" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "clippy_check" +path = "src/main.rs" +"#; + let cargo_toml_path = temp_dir_path.join("Cargo.toml"); + fs::write(&cargo_toml_path, cargo_toml_content).context("写入 Cargo.toml 失败")?; + + // 创建 src 目录 + let src_dir = temp_dir_path.join("src"); + fs::create_dir(&src_dir).context("创建 src 目录失败")?; + + // 复制练习文件到 src/main.rs + let exercise_content = fs::read_to_string(exercise_path).context("读取练习文件失败")?; + let main_rs_path = src_dir.join("main.rs"); + fs::write(&main_rs_path, exercise_content).context("写入 main.rs 失败")?; + + // 运行 cargo clippy + let clippy_output = Command::new("cargo") + .arg("clippy") + .arg("--manifest-path") + .arg(&cargo_toml_path) + .arg("--") + .arg("-D") + .arg("warnings") + .current_dir(temp_dir_path) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .output() + .context(format!("运行 cargo clippy 检查 {} 失败", exercise_name))?; + + let clippy_success = clippy_output.status.success(); + + if !clippy_success { + if verbose { + println!("{}", String::from_utf8_lossy(&clippy_output.stdout)); + println!("{}", String::from_utf8_lossy(&clippy_output.stderr)); + } + println!("{} {}", "✗".red().bold(), exercise_name); + return Ok((exercise_name, false, start.elapsed().as_secs())); + } + } + // 对于rustlings练习,直接使用rustc编译和运行测试 let test_output = Command::new("rustc") .arg(exercise_path)