#![allow(clippy::missing_errors_doc)]
use anyhow::{Context, Result};
use hyalo_core::discovery;
use hyalo_core::index::{ScanOptions, ScannedIndex, SnapshotIndex, VaultIndex, find_stale_indexes};
use std::path::{Path, PathBuf};
use crate::output::{CommandOutcome, Format, format_success};
pub fn create_index(
dir: &Path,
site_prefix: Option<&str>,
output: Option<&Path>,
format: Format,
allow_outside_vault: bool,
) -> Result<CommandOutcome> {
let index_path = match output {
Some(p) => p.to_path_buf(),
None => dir.join(".hyalo-index"),
};
if output.is_some() && !allow_outside_vault {
let canonical_dir = discovery::canonicalize_vault_dir(dir)?;
let parent = index_path
.parent()
.context("output path has no parent directory")?;
let canonical_parent = dunce::canonicalize(parent).with_context(|| {
format!(
"failed to canonicalize parent of output path: {}",
parent.display()
)
})?;
if !canonical_parent.starts_with(&canonical_dir) {
let out = crate::output::format_error(
format,
"output path is outside the vault boundary",
Some(&index_path.display().to_string()),
Some("use --allow-outside-vault to override"),
None,
);
return Ok(CommandOutcome::UserError(out));
}
}
let all = discovery::discover_files(dir)?;
let files: Vec<(PathBuf, String)> = all
.into_iter()
.map(|p| {
let rel = discovery::relative_path(dir, &p);
(p, rel)
})
.collect();
let build = ScannedIndex::build(&files, site_prefix, &ScanOptions { scan_body: true })?;
for w in &build.warnings {
crate::warn::warn(format!("skipped {}: {}", w.rel_path, w.message));
}
let vault_dir_str = std::fs::canonicalize(dir)
.unwrap_or_else(|_| dir.to_path_buf())
.to_string_lossy()
.into_owned();
SnapshotIndex::save(&build.index, &index_path, &vault_dir_str, site_prefix)?;
if let Ok(stale) = find_stale_indexes(dir) {
for (stale_path, stale_vault, stale_ts) in stale {
if stale_path == index_path {
continue;
}
crate::warn::warn(format!(
"stale index at {} (vault: {}, created: {})",
stale_path.display(),
stale_vault,
stale_ts,
));
}
}
let file_count = build.index.entries().len();
let result = serde_json::json!({
"path": index_path.display().to_string(),
"files_indexed": file_count,
"warnings": build.warnings.len(),
});
Ok(CommandOutcome::success(format_success(format, &result)))
}