get_exercise.rs

  1use anyhow::{Result, anyhow};
  2use std::{
  3    fs,
  4    path::{Path, PathBuf},
  5};
  6
  7pub fn get_exercise_name(exercise_path: &Path) -> String {
  8    exercise_path
  9        .file_name()
 10        .unwrap_or_default()
 11        .to_string_lossy()
 12        .to_string()
 13}
 14
 15pub fn get_exercise_language(exercise_path: &Path) -> Result<String> {
 16    // Extract the language from path (data/python/exercises/... => python)
 17    let parts: Vec<_> = exercise_path.components().collect();
 18
 19    for (i, part) in parts.iter().enumerate() {
 20        if i > 0 && part.as_os_str() == "eval_code" {
 21            if i + 1 < parts.len() {
 22                let language = parts[i + 1].as_os_str().to_string_lossy().to_string();
 23                return Ok(language);
 24            }
 25        }
 26    }
 27
 28    Err(anyhow!(
 29        "Could not determine language from path: {:?}",
 30        exercise_path
 31    ))
 32}
 33
 34pub fn find_exercises(
 35    framework_path: &Path,
 36    languages: &[&str],
 37    max_per_language: Option<usize>,
 38) -> Result<Vec<PathBuf>> {
 39    let mut all_exercises = Vec::new();
 40
 41    println!("Searching for exercises in languages: {:?}", languages);
 42
 43    for language in languages {
 44        let language_dir = framework_path
 45            .join("eval_code")
 46            .join(language)
 47            .join("exercises")
 48            .join("practice");
 49
 50        println!("Checking language directory: {:?}", language_dir);
 51        if !language_dir.exists() {
 52            println!("Warning: Language directory not found: {:?}", language_dir);
 53            continue;
 54        }
 55
 56        let mut exercises = Vec::new();
 57        match fs::read_dir(&language_dir) {
 58            Ok(entries) => {
 59                for entry_result in entries {
 60                    match entry_result {
 61                        Ok(entry) => {
 62                            let path = entry.path();
 63
 64                            if path.is_dir() {
 65                                // Special handling for "internal" directory
 66                                if *language == "internal" {
 67                                    // Check for repo_info.json to validate it's an internal exercise
 68                                    let repo_info_path = path.join(".meta").join("repo_info.json");
 69                                    let instructions_path =
 70                                        path.join(".docs").join("instructions.md");
 71
 72                                    if repo_info_path.exists() && instructions_path.exists() {
 73                                        exercises.push(path);
 74                                    }
 75                                } else {
 76                                    // Map the language to the file extension - original code
 77                                    let language_extension = match *language {
 78                                        "python" => "py",
 79                                        "go" => "go",
 80                                        "rust" => "rs",
 81                                        "typescript" => "ts",
 82                                        "javascript" => "js",
 83                                        "ruby" => "rb",
 84                                        "php" => "php",
 85                                        "bash" => "sh",
 86                                        "multi" => "diff",
 87                                        _ => continue, // Skip unsupported languages
 88                                    };
 89
 90                                    // Check if this is a valid exercise with instructions and example
 91                                    let instructions_path =
 92                                        path.join(".docs").join("instructions.md");
 93                                    let has_instructions = instructions_path.exists();
 94                                    let example_path = path
 95                                        .join(".meta")
 96                                        .join(format!("example.{}", language_extension));
 97                                    let has_example = example_path.exists();
 98
 99                                    if has_instructions && has_example {
100                                        exercises.push(path);
101                                    }
102                                }
103                            }
104                        }
105                        Err(err) => println!("Error reading directory entry: {}", err),
106                    }
107                }
108            }
109            Err(err) => println!(
110                "Error reading directory {}: {}",
111                language_dir.display(),
112                err
113            ),
114        }
115
116        // Sort exercises by name for consistent selection
117        exercises.sort_by(|a, b| {
118            let a_name = a.file_name().unwrap_or_default().to_string_lossy();
119            let b_name = b.file_name().unwrap_or_default().to_string_lossy();
120            a_name.cmp(&b_name)
121        });
122
123        // Apply the limit if specified
124        if let Some(limit) = max_per_language {
125            if exercises.len() > limit {
126                println!(
127                    "Limiting {} exercises to {} for language {}",
128                    exercises.len(),
129                    limit,
130                    language
131                );
132                exercises.truncate(limit);
133            }
134        }
135
136        println!(
137            "Found {} exercises for language {}: {:?}",
138            exercises.len(),
139            language,
140            exercises
141                .iter()
142                .map(|p| p.file_name().unwrap_or_default().to_string_lossy())
143                .collect::<Vec<_>>()
144        );
145        all_exercises.extend(exercises);
146    }
147
148    Ok(all_exercises)
149}