Skip to content

Commit b68e0d3

Browse files
committed
feat: add cache versioning for forward compatibility
- Add CACHE_VERSION constant (v1) to track cache format - Update CodeownersCache to include version field - Update Serialize/Deserialize to handle version - Check version on load and rebuild if outdated - Handle deserialization failures gracefully by rebuilding - Remove redundant cache verification load in parse command This ensures that cache format changes trigger automatic rebuilds instead of cryptic deserialization errors.
1 parent de35d54 commit b68e0d3

File tree

3 files changed

+37
-14
lines changed

3 files changed

+37
-14
lines changed

codeinput/src/core/cache.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
resolver::find_owners_and_tags_for_file,
66
types::{
77
codeowners_entry_to_matcher, CacheEncoding, CodeownersCache, CodeownersEntry,
8-
CodeownersEntryMatcher, FileEntry,
8+
CodeownersEntryMatcher, FileEntry, CACHE_VERSION,
99
},
1010
},
1111
utils::error::{Error, Result},
@@ -121,6 +121,7 @@ pub fn build_cache(
121121
}
122122

123123
Ok(CodeownersCache {
124+
version: CACHE_VERSION,
124125
hash,
125126
entries,
126127
files: file_entries,
@@ -219,21 +220,32 @@ pub fn sync_cache(
219220
}
220221

221222
// Load the cache from the specified file
222-
let cache = load_cache(&repo.join(cache_file)).map_err(|e| {
223-
crate::utils::error::Error::new(&format!(
224-
"Failed to load cache from {}: {}",
225-
cache_file.display(),
226-
e
227-
))
228-
})?;
223+
let cache = match load_cache(&repo.join(cache_file)) {
224+
Ok(cache) => cache,
225+
Err(e) => {
226+
// Cache is corrupted or incompatible format - rebuild it
227+
log::info!("Cache could not be loaded ({}), rebuilding...", e);
228+
return parse_repo(repo, cache_file);
229+
}
230+
};
231+
232+
// Check cache version - rebuild if outdated
233+
if cache.version != CACHE_VERSION {
234+
log::info!(
235+
"Cache version mismatch (found v{}, expected v{}), rebuilding...",
236+
cache.version,
237+
CACHE_VERSION
238+
);
239+
return parse_repo(repo, cache_file);
240+
}
229241

230242
// verify the hash of the cache matches the current repo hash
231243
let current_hash = get_repo_hash(repo)?;
232244
let cache_hash = cache.hash;
233245

234246
if cache_hash != current_hash {
235247
// parse the codeowners files and build the cache
236-
return parse_repo(&repo, &cache_file);
248+
return parse_repo(repo, cache_file);
237249
} else {
238250
return Ok(cache);
239251
}

codeinput/src/core/commands/parse.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{
22
core::{
3-
cache::{build_cache, load_cache, store_cache},
3+
cache::{build_cache, store_cache},
44
common::{find_codeowners_files, find_files, get_repo_hash},
55
parser::parse_codeowners,
66
types::{CacheEncoding, CodeownersEntry},
@@ -46,8 +46,5 @@ pub fn run(
4646
// Store the cache in the specified file
4747
store_cache(&cache, &cache_file, encoding)?;
4848

49-
// Test the cache by loading it back
50-
let _cache = load_cache(&cache_file)?;
51-
5249
Ok(())
5350
}

codeinput/src/core/types.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,20 @@ pub struct FileEntry {
249249
pub tags: Vec<Tag>,
250250
}
251251

252+
/// Current cache format version. Increment when making breaking changes.
253+
pub const CACHE_VERSION: u32 = 1;
254+
252255
/// Pre-computed cache of CODEOWNERS information for fast lookups.
253256
///
254257
/// The cache stores parsed CODEOWNERS rules, file ownership mappings,
255258
/// and reverse lookup indexes for efficient querying.
256259
///
260+
/// # Cache Versioning
261+
///
262+
/// The cache includes a version field to detect incompatible formats.
263+
/// When loading an older cache version, the cache is automatically
264+
/// rebuilt to ensure compatibility.
265+
///
257266
/// # Cache Invalidation
258267
///
259268
/// The cache is invalidated when the repository state changes, detected
@@ -263,6 +272,8 @@ pub struct FileEntry {
263272
/// - Unstaged file changes (excluding cache files themselves)
264273
#[derive(Debug)]
265274
pub struct CodeownersCache {
275+
/// Cache format version for compatibility checking
276+
pub version: u32,
266277
/// SHA-256 hash of the repository state for cache invalidation
267278
pub hash: [u8; 32],
268279
/// All parsed CODEOWNERS entries
@@ -282,7 +293,8 @@ impl Serialize for CodeownersCache {
282293
{
283294
use serde::ser::SerializeStruct;
284295

285-
let mut state = serializer.serialize_struct("CodeownersCache", 4)?;
296+
let mut state = serializer.serialize_struct("CodeownersCache", 6)?;
297+
state.serialize_field("version", &self.version)?;
286298
state.serialize_field("hash", &self.hash)?;
287299
state.serialize_field("entries", &self.entries)?;
288300
state.serialize_field("files", &self.files)?;
@@ -307,6 +319,7 @@ impl<'de> Deserialize<'de> for CodeownersCache {
307319
{
308320
#[derive(Deserialize)]
309321
struct CodeownersCacheHelper {
322+
version: u32,
310323
hash: [u8; 32],
311324
entries: Vec<CodeownersEntry>,
312325
files: Vec<FileEntry>,
@@ -328,6 +341,7 @@ impl<'de> Deserialize<'de> for CodeownersCache {
328341
}
329342

330343
Ok(CodeownersCache {
344+
version: helper.version,
331345
hash: helper.hash,
332346
entries: helper.entries,
333347
files: helper.files,

0 commit comments

Comments
 (0)