Skip to main content

talon_cli/config/
refresh.rs

1use std::path::PathBuf;
2
3use talon_core::TalonConfig;
4
5/// Controls how auto-refresh handles an already-running sync.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum RefreshLockPolicy {
8    /// Return an error when another Talon process owns the sync lock.
9    ErrorIfBusy,
10    /// Leave the existing index untouched and continue with a read query.
11    SkipIfBusy,
12}
13
14/// Returns the advisory sync lock path for a configured database.
15#[must_use]
16pub fn sync_lock_path(config: &TalonConfig) -> PathBuf {
17    config
18        .db_path
19        .parent()
20        .map_or_else(|| PathBuf::from("sync.lock"), |p| p.join("sync.lock"))
21}
22
23/// Auto-refresh the index against on-disk state before running a query.
24///
25/// Mirrors `talon sync` minus the embed pass. Recently edited files become
26/// searchable via BM25 immediately; semantic embeddings catch up on the next
27/// explicit `talon sync`.
28///
29/// # Errors
30///
31/// Returns an error if the underlying refresh fails. When `policy` is
32/// [`RefreshLockPolicy::SkipIfBusy`], a live sync lock is treated as a no-op
33/// because another process is already moving the index forward.
34pub fn refresh_index_if_needed(
35    config: &TalonConfig,
36    conn: &mut talon_core::Connection,
37    fast: bool,
38    policy: RefreshLockPolicy,
39) -> eyre::Result<()> {
40    if fast {
41        return Ok(());
42    }
43    let lock_path = sync_lock_path(config);
44    let indexer_config = talon_core::IndexerConfig {
45        include_patterns: config.include_patterns.clone(),
46        ignore_patterns: config.ignore_patterns.clone(),
47        talon_config: Some(config.clone()),
48    };
49    match talon_core::refresh_index(
50        conn,
51        &config.vault_path,
52        &lock_path,
53        &indexer_config,
54        &config.chunker,
55    ) {
56        Ok(_) => {}
57        Err(talon_core::SyncError::LockBusy) if policy == RefreshLockPolicy::SkipIfBusy => {}
58        Err(e) => return Err(eyre::eyre!("auto-refresh failed: {e}")),
59    }
60    Ok(())
61}
62
63/// Auto-refreshes when the caller already owns the sync lock.
64///
65/// # Errors
66///
67/// Returns an error if the underlying refresh fails.
68pub fn refresh_index_with_lock(
69    config: &TalonConfig,
70    conn: &mut talon_core::Connection,
71    lock: talon_core::SyncLock,
72) -> eyre::Result<()> {
73    let indexer_config = talon_core::IndexerConfig {
74        include_patterns: config.include_patterns.clone(),
75        ignore_patterns: config.ignore_patterns.clone(),
76        talon_config: Some(config.clone()),
77    };
78    talon_core::refresh_index_locked(
79        conn,
80        &config.vault_path,
81        &indexer_config,
82        &config.chunker,
83        lock,
84    )
85    .map_err(|e| eyre::eyre!("auto-refresh failed: {e}"))?;
86    Ok(())
87}