Skip to main content

scc_engine/
index.rs

1//! Engine index operations: full index, path refresh, resolution.
2//!
3//! Moved verbatim from `scc-cli` lib.rs / commands.rs: the revision-after-
4//! recompile ordering contract and the no-change fast path move WITH the
5//! code (parity tests enforce byte-identical reports).
6
7use std::path::Path;
8
9// trace:exempt reason=internal-detail
10pub fn full(root: &Path, config: &scc_indexer::Config) -> crate::Result<scc_indexer::IndexReport> {
11    crate::workspace::ensure_scc_ignored(root);
12    crate::workspace::resilient_index(root, || {
13        let (store, quarantined) = crate::workspace::open_store_recovering(root)?;
14        crate::workspace::report_quarantine(&quarantined);
15        let indexer = scc_indexer::Indexer::new(store, config.clone());
16        let report = indexer.index()?;
17        let store = crate::workspace::open_store(root)?;
18        if config.index.auto_resolve {
19            let _ = scc_indexer::resolver::resolve_repository(
20                &store,
21                root,
22                scc_indexer::resolver::MAX_CALL_SITES,
23            );
24        }
25        let unchanged = report.changed == 0 && report.removed == 0 && !config.index.auto_resolve;
26        let extractor_current = store
27            .revisions()
28            .map(|rs| {
29                rs.into_iter().last().map(|h| {
30                    h.extractor_version
31                        == format!(
32                            "store:{};core:{}",
33                            scc_store::SCHEMA_VERSION,
34                            scc_core::SCHEMA_VERSION
35                        )
36                })
37                .unwrap_or(false)
38            })
39            .unwrap_or(false);
40        if !(unchanged && extractor_current) {
41            recompile(&store)?;
42        }
43        let _ = store.record_current_revision_with_config(
44            &scc_indexer::semantic_config_hash(config),
45        )?;
46        Ok(report)
47    })
48}
49
50// trace:exempt reason=internal-detail
51pub fn refresh_paths(root: &Path, config: &scc_indexer::Config, paths: &[String]) -> crate::Result<scc_indexer::IndexReport> {
52    let (store, quarantined) = crate::workspace::open_store_recovering(root)?;
53    crate::workspace::report_quarantine(&quarantined);
54    let indexer = scc_indexer::Indexer::new(crate::workspace::open_store(root)?, config.clone());
55    let report = indexer.refresh_paths(paths)?;
56    drop(indexer);
57    recompile(&store)?;
58    let _ = store.record_current_revision_with_config(
59        &scc_indexer::semantic_config_hash(config),
60    )?;
61    Ok(report)
62}
63
64// trace:exempt reason=internal-detail
65pub fn recompile(store: &scc_store::Store) -> crate::Result<scc_graph::RecompileReport> {
66    Ok(scc_graph::recompile(store)?)
67}
68
69// trace:exempt reason=internal-detail
70pub fn resolve_and_recompile(root: &Path) -> crate::Result<scc_indexer::resolver::ResolveReport> {
71    let store = crate::workspace::open_store(root)?;
72    let report = scc_indexer::resolver::resolve_repository(
73        &store,
74        root,
75        scc_indexer::resolver::MAX_CALL_SITES,
76    )
77    .map_err(|e| crate::EngineError::Other(e.to_string()))?;
78    recompile(&store)?;
79    Ok(report)
80}