Skip to main content

crbrs_lib/
lib.rs

1// FILE: crbrs-lib/src/lib.rs
2
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5use std::path::PathBuf;
6use thiserror::Error;
7use ::config::ConfigError;
8
9// --- Configuration Structures ---
10
11#[derive(Debug, Serialize, Deserialize, Clone)] // Clone is useful for modifying settings
12#[serde(default)] // Ensure defaults are used if fields are missing in config file
13pub struct Settings {
14    pub compiler_repository_url: String,
15    pub compiler_storage_path: Option<PathBuf>, // Option allows finding default if None
16    pub installed_compilers: HashMap<String, CompilerInfo>,
17    pub file_associations: HashMap<String, String>, // Key: extension (e.g., "cr2"), Value: compiler ID
18    pub wine_path: Option<String>,
19}
20
21impl Default for Settings {
22    fn default() -> Self {
23        Settings {
24            // TODO: Consider a more permanent default URL later
25            compiler_repository_url: "https://raw.githubusercontent.com/RileyLeff/campbell-scientific-compilers/refs/heads/main/compilers.toml".to_string(),
26            compiler_storage_path: None, // We'll resolve this to a default path at runtime
27            installed_compilers: HashMap::new(),
28            file_associations: HashMap::new(),
29            wine_path: None, // Will try finding 'wine' in PATH by default
30        }
31    }
32}
33
34// --- CompilerInfo (Installed Compiler) - Slight Refinement ---
35// This struct represents a compiler *after* it has been installed.
36// It might store slightly different or additional info compared to the manifest entry.
37
38#[derive(Debug, Serialize, Deserialize, Clone)]
39pub struct CompilerInfo {
40    pub id: String,                 // e.g., "cr2comp-v4.0" (matches manifest key)
41    pub description: String,        // From manifest
42    pub version: String,            // From manifest
43    pub install_subdir: PathBuf,    // Path to the *directory* of this compiler relative to compiler_storage_path
44                                    // (e.g., "cr2comp-v4.0/")
45    pub executable_name: String,    // e.g., "cr2comp.exe" (relative to install_subdir)
46    pub requires_wine: bool,        // From manifest
47    pub supported_loggers: Option<Vec<String>>, // From manifest
48}
49
50// Helper for serde default
51fn default_true() -> bool {
52    true
53}
54
55
56// --- Manifest Structures (NEW) ---
57
58#[derive(Debug, Serialize, Deserialize, Clone)]
59pub struct Manifest {
60    pub manifest_version: String,
61    #[serde(default)] // Allow empty 'compilers' table in TOML
62    pub compilers: HashMap<String, ManifestCompilerEntry>, // Key is the Compiler ID
63}
64
65#[derive(Debug, Serialize, Deserialize, Clone)]
66pub struct ManifestCompilerEntry {
67    pub description: String,
68    pub version: String,
69    pub download_url: String,
70    pub executable_name: String, // e.g., "cr2comp.exe"
71    #[serde(default = "default_true")] // Assume requires wine if not specified
72    pub requires_wine: bool,
73    #[serde(default)]
74    pub supported_loggers: Option<Vec<String>>,
75    #[serde(default)]
76    pub sha256: Option<String>, // Optional checksum for verification
77}
78
79#[derive(Debug, Clone)] // Clone might be useful
80pub struct CompilationErrorDetail {
81    pub file_path_in_log: String, // e.g., "example.cr2" from the log's first line
82    pub line: Option<u32>,
83    pub message: String,
84    // Add character_pos or other fields if the compiler ever provides them
85}
86
87// --- Error Enum ---
88
89#[derive(Error, Debug)]
90pub enum Error {
91    #[error("Configuration error: {0}")]
92    Config(#[from] ConfigError),
93
94    #[error("I/O error: {0}")]
95    Io(#[from] std::io::Error),
96
97    #[error("Network error: {0}")]
98    Network(#[from] reqwest::Error),
99
100    #[error("Failed to process ZIP archive: {0}")]
101    Zip(#[from] zip::result::ZipError),
102
103    // #[error("Failed to process TAR archive: {0}")] // Add if/when tar support is added
104    // Tar(#[from] tar::Error), // Requires tar crate
105
106    #[error("Compiler '{0}' not found in configuration.")]
107    CompilerNotFound(String),
108
109    #[error("SHA256 checksum mismatch for compiler '{compiler_id}'. Expected: '{expected}', Got: '{actual}'.")]
110    ChecksumMismatch { // <-- NEW ERROR VARIANT
111        compiler_id: String,
112        expected: String,
113        actual: String,
114    },
115
116    #[error("No compiler associated with file extension '.{0}'. Please configure an association.")]
117    NoCompilerForExtension(String),
118
119    #[error("Could not find Wine executable. Please install Wine or set the path in configuration.")]
120    WineNotFound,
121
122    #[error("Failed to execute subprocess: {0}")]
123    Subprocess(std::io::Error), // Separate from general Io for clarity
124
125    #[error("Compilation of '{file_path}' failed.")]
126    CompilationFailed {
127        file_path: PathBuf, // The input file path
128        errors: Vec<CompilationErrorDetail>,
129        raw_log: String, // Always include the full log for reference
130    },
131
132    // Keep a simpler variant if log parsing itself fails or is ambiguous
133    #[error("Compiler reported failure for '{file_path}'. Log:\n{raw_log}")]
134    GenericCompilationFailedWithLog {
135        file_path: PathBuf,
136        raw_log: String,
137    },
138
139    #[error("Compiler execution failed. Output Log:\n{log_content}")]
140    CompilationFailedWithLog { log_content: String }, // Use if we parse the log
141
142    #[error("Invalid compiler source or manifest: {0}")]
143    InvalidCompilerSource(String),
144
145    #[error("Failed to determine application directories.")]
146    DirectoryResolutionFailed,
147
148    #[error("Compiler ID '{0}' not found in the repository manifest.")]
149    CompilerIdNotFoundInManifest(String),
150
151    #[error("Invalid file extension: '{0}'.")]
152    InvalidExtension(String),
153}
154
155// Define pub modules for organization (create the files next)
156pub mod config;
157pub mod compiler;
158pub mod installer;
159// pub mod download; // Maybe later
160
161// Example function signature using the types (implementation later)
162pub fn compile_file(
163    input_file: PathBuf,
164    output_log: Option<PathBuf>,
165    compiler_id: Option<String>,
166    settings: &Settings,
167) -> Result<(), Error> {
168    compiler::compile_file_impl(
169            &input_file,
170            output_log.as_deref(), // Convert Option<PathBuf> to Option<&Path>
171            compiler_id.as_deref(), // Convert Option<String> to Option<&str>
172            settings,
173        )
174}
175
176
177#[cfg(test)]
178mod tests {
179    // Add basic tests later if needed
180}