docling_core/assets.rs
1//! Runtime-asset path resolution shared by every crate.
2//!
3//! All optional runtime assets (ONNX models, OCR dictionaries, the chunker
4//! tokenizer) live under one directory, `.models/` — dot-prefixed like
5//! `.pdfium/`, so the plain `models` name stays free for source code.
6//! Resolution is CWD-relative with an executable-directory fallback.
7
8/// Resolve a default (CWD-relative) asset path. If it doesn't exist relative
9/// to the current directory, try next to the executable and one level above
10/// it (following symlinks — the layout `scripts/install/install.sh` produces:
11/// `/usr/local/bin/docling-rs` → `/usr/local/docling.rs/bin/docling-rs` with
12/// `.models/` and `.pdfium/` in `/usr/local/docling.rs`). Returns `rel`
13/// unchanged when nothing exists anywhere, so callers' error messages keep
14/// the familiar path. Explicit env overrides never reach this.
15pub fn resolve(rel: &str) -> String {
16 if std::path::Path::new(rel).exists() {
17 return rel.to_string();
18 }
19 let dir = std::env::current_exe()
20 .ok()
21 .and_then(|p| p.canonicalize().ok())
22 .and_then(|p| p.parent().map(std::path::Path::to_path_buf));
23 if let Some(dir) = dir {
24 for base in [Some(dir.as_path()), dir.parent()].into_iter().flatten() {
25 let p = base.join(rel);
26 if p.exists() {
27 return p.to_string_lossy().into_owned();
28 }
29 }
30 }
31 rel.to_string()
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37
38 #[test]
39 fn missing_everywhere_returns_input() {
40 assert_eq!(
41 resolve(".models/definitely/not/there.onnx"),
42 ".models/definitely/not/there.onnx"
43 );
44 }
45}