Lock File Operations
This example demonstrates how to use Rhema’s foundational lock file operations for managing dependency locks and ensuring reproducible builds.
Context
Lock files are essential for:
- Deterministic builds - Ensuring the same dependencies are used across environments
- Dependency tracking - Managing complex dependency graphs with version constraints
- Integrity verification - Detecting when source files have changed
- Conflict resolution - Handling dependency conflicts in multi-scope projects
Basic Lock File Operations
Creating a New Lock File
use rhema_core::{LockFileOps, RhemaLock, LockedScope, LockedDependency, DependencyType};
use std::path::Path;
fn create_basic_lock_file() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
// Create a new lock file
let lock_data = LockFileOps::create_lock_file(lock_path, "rhema")?;
println!("Created lock file with {} scopes", lock_data.scopes.len());
println!("Generated by: {}", lock_data.generated_by);
println!("Checksum: {}", lock_data.checksum);
Ok(())
}Reading and Validating a Lock File
use rhema_core::{LockFileOps, ValidationResult};
fn validate_existing_lock_file() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
// Read the lock file
let lock_data = LockFileOps::read_lock_file(lock_path)?;
println!("Lock file contains {} scopes", lock_data.scopes.len());
// Validate integrity
let validation_result = LockFileOps::validate_lock_file_integrity(lock_path)?;
if validation_result.is_valid {
println!("✅ Lock file is valid");
} else {
println!("❌ Lock file validation failed:");
for message in &validation_result.messages {
println!(" - {}", message);
}
}
println!("Validation took {}ms", validation_result.validation_time_ms);
Ok(())
}Adding Scopes and Dependencies
use rhema_core::{LockFileOps, RhemaLock, LockedScope, LockedDependency, DependencyType};
use chrono::Utc;
fn add_scope_with_dependencies() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
// Create a new scope
let mut scope = LockedScope::new("1.0.0", "/api/service");
scope.has_circular_dependencies = false;
// Add dependencies to the scope
let dep1 = LockedDependency::new("2.1.0", "/shared/utils", DependencyType::Required);
let dep2 = LockedDependency::new("1.5.0", "/database", DependencyType::Required);
scope.add_dependency("utils".to_string(), dep1);
scope.add_dependency("db".to_string(), dep2);
// Update the lock file
let _lock_data = LockFileOps::update_lock_file_scope(lock_path, "/api/service", scope)?;
println!("Added scope /api/service with 2 dependencies");
Ok(())
}Checking if Lock File is Outdated
use rhema_core::LockFileOps;
use std::path::PathBuf;
fn check_lock_file_freshness() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
let source_paths = vec![
PathBuf::from("src/main.rs"),
PathBuf::from("Cargo.toml"),
PathBuf::from("rhema.yaml"),
];
let is_outdated = LockFileOps::is_lock_file_outdated(lock_path, &source_paths)?;
if is_outdated {
println!("⚠️ Lock file is outdated - source files have changed");
println!("Run 'rhema lock update' to regenerate the lock file");
} else {
println!("✅ Lock file is up to date");
}
Ok(())
}Merging Multiple Lock Files
use rhema_core::{LockFileOps, ConflictResolution};
use std::path::PathBuf;
fn merge_lock_files() -> Result<(), Box<dyn std::error::Error>> {
let lock_files = vec![
PathBuf::from("frontend/rhema.lock"),
PathBuf::from("backend/rhema.lock"),
PathBuf::from("shared/rhema.lock"),
];
let output_path = PathBuf::from("merged.lock");
// Merge with automatic conflict resolution
let merged_lock = LockFileOps::merge_lock_files(
&output_path,
&lock_files,
ConflictResolution::Automatic,
)?;
println!("Merged {} lock files into {}", lock_files.len(), output_path.display());
println!("Total scopes: {}", merged_lock.scopes.len());
println!("Total dependencies: {}", merged_lock.metadata.total_dependencies);
Ok(())
}Backup and Restore Operations
use rhema_core::LockFileOps;
fn backup_and_restore() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
// Create a backup
let backup_path = LockFileOps::backup_lock_file(lock_path)?;
println!("Created backup: {}", backup_path.display());
// Simulate some changes to the lock file
// ... (modify lock file) ...
// Restore from backup
LockFileOps::restore_lock_file(&backup_path, lock_path)?;
println!("Restored lock file from backup");
Ok(())
}Getting Lock File Statistics
use rhema_core::{LockFileOps, LockFileStats};
fn analyze_lock_file() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
let stats = LockFileStats::from_lock_file(lock_path)?;
println!("Lock File Analysis:");
println!(" Total scopes: {}", stats.total_scopes);
println!(" Total dependencies: {}", stats.total_dependencies);
println!(" Circular dependencies: {}", stats.circular_dependencies);
println!(" File size: {} bytes", stats.file_size_bytes);
println!(" Last modified: {}", stats.last_modified);
println!(" Generation time: {}ms", stats.generation_time_ms);
Ok(())
}Advanced Usage
Custom Checksum Calculation
use rhema_core::LockFileOps;
fn custom_checksum_operations() -> Result<(), Box<dyn std::error::Error>> {
// Calculate checksum for a file
let file_path = Path::new("src/main.rs");
let file_checksum = LockFileOps::calculate_file_checksum(file_path)?;
println!("File checksum: {}", file_checksum);
// Calculate checksum for content
let content = "Hello, Rhema!";
let content_checksum = LockFileOps::calculate_content_checksum(content);
println!("Content checksum: {}", content_checksum);
Ok(())
}Generating Lock File from Source
use rhema_core::{LockFileOps, LockedScope};
use std::collections::HashMap;
fn generate_lock_from_source() -> Result<(), Box<dyn std::error::Error>> {
let lock_path = Path::new("rhema.lock");
// Collect scopes from source files
let mut scopes = HashMap::new();
// Add scopes discovered from source
let api_scope = LockedScope::new("1.0.0", "/api");
let web_scope = LockedScope::new("2.0.0", "/web");
scopes.insert("/api".to_string(), api_scope);
scopes.insert("/web".to_string(), web_scope);
// Generate the lock file
let lock_data = LockFileOps::generate_lock_file(lock_path, "rhema-scanner", scopes)?;
println!("Generated lock file with {} scopes", lock_data.scopes.len());
println!("Generation time: {}ms",
lock_data.metadata.performance_metrics
.as_ref()
.map(|m| m.generation_time_ms)
.unwrap_or(0)
);
Ok(())
}Expected Output
When running these examples, you should see output similar to:
Created lock file with 0 scopes
Generated by: rhema
Checksum: checksum_1703123456
Lock file contains 3 scopes
✅ Lock file is valid
Validation took 5ms
Added scope /api/service with 2 dependencies
✅ Lock file is up to date
Merged 3 lock files into merged.lock
Total scopes: 8
Total dependencies: 24
Created backup: rhema.lock.backup.20231220123456
Restored lock file from backup
Lock File Analysis:
Total scopes: 3
Total dependencies: 12
Circular dependencies: 0
File size: 2048 bytes
Last modified: 2023-12-20 12:34:56 UTC
Generation time: 150msBest Practices
- Always validate lock files before using them in production
- Use backups before making significant changes to lock files
- Check freshness regularly to ensure lock files reflect current source
- Handle conflicts appropriately when merging lock files
- Monitor performance metrics to optimize lock file operations
- Use meaningful generated_by values for audit trails
Error Handling
The lock file operations return RhemaResult<T> which can contain various error types:
FileNotFound- Lock file or source files don’t existValidationError- Lock file validation failedLockError- Lock file operation failedIoError- File system operations failed
Always handle these errors appropriately in your applications.
Integration with Rhema CLI
These lock file operations are integrated into the Rhema CLI:
# Generate a new lock file
rhema lock generate
# Validate existing lock file
rhema lock validate
# Update lock file from source
rhema lock update
# Merge multiple lock files
rhema lock merge frontend/rhema.lock backend/rhema.lock
# Show lock file statistics
rhema lock statsThis provides a comprehensive foundation for managing dependency locks in Rhema projects.
Last updated on